MySQL query to select specific resources - php

Scenario:
The school where I work at has already a system that handles resource reservation (racks with tv's, projectors, etc), however I was asked to make a quick-fix for today since the system has a problem, there's no way to make the resource only appear for a specific segment:
1-6th grade is a segment,
7-11th grade is a segment.
The system is made out of PHP and MySQL.
Problem:
Without creating a new table, I have to find a way to show a specific resource only to 1-3rd grade and another one only to 4-6th grade.
Here are the tables:
I added into the grade table a new column called UNIQUERESOURCESwhere I put a value of 1 to sections between first and third grade and a value of 2 to sections between fourth and sixth grade.
How can I show to grades from 1-3 grade ONLY those specific resources and from 4-6 grade ONLY the other specific resources?
Here is the current query:
SELECT DISTINCT r.RESOURCEID, r.RESOURCENAME, rl.RESOURCELOCATIONNAME FROM resource r
inner join resource_location rl
on r.RESOURCELOCATIONID = rl.RESOURCELOCATIONID
inner join grade g
on g.RESOURCELOCATIONID = r.RESOURCELOCATIONID
inner join users_intermediate ui
on g.GRADEID = ui.GRADEID
WHERE ui.USERID = '%s'
How can I fix this query to include the resources as follows:
Include RESOURCELOCATIONID = 5 where UNIQUERESOURCES = 1 if the user is in between GRADEID 1-12
Include RESOURCELOCATIONID = 6 where UNIQUERESOURCES = 2 if the user is in between GRADEID 13-24.
This is the part I can't figure out. Some help would be really appreciated!
EDIT:
Here are some pictures of the resources
Resources:
Grades:
Users Intermediate (emails are censored in this pic):
As you can see, what I'm trying to accomplish is also include the resources that have resourcelocationid = 5 or resourcelocationid = 6 if the user teaches in grades that go from 1-3 or 4-6

Have you tryed this way:
SELECT RESOURCEID, RESOURCENAME, RESOURCEDESCRIPTION,
T3.RESOURCELOCATIONNAME, T2.RESOURCESTATUSNAME,
T2.RESOURCESTATUSDESCRIPTION, T2.RESOURCESTATUSID
FROM resource T1
INNER JOIN resource_status T2 USING(RESOURCESTATUSID)
INNER JOIN resource_location T3 USING(RESOURCELOCATIONID)
INNER JOIN grade USING(RESOURCELOCATIONID)
WHERE T1.RESOURCELOCATIONID IN (
SELECT DISTINCT RESOURCELOCATIONID FROM grade G
INNER JOIN users_intermediate UI
ON G.GRADEID = UI.GRADEID
WHERE USERID = "%s"
)
AND (
T1.RESOURCESTATUSID = 1
OR (
T1.RESOURCELOCATIONID = 5
AND (
UNIQUERESOURCES = 1 AND GRADEID >= 1 AND GRADEID <= 12
)
)
OR (
T1.RESOURCELOCATIONID = 6
AND (
UNIQUERESOURCES = 2 AND GRADEID >= 13 AND GRADEID <= 24
)
)
)

Not seeing sample data and confirming true context of your data and expected output, I would like to mentally describe via transitive association.
User "A" is associated with class/grade 1,2 and 3.
Looking into the Grade table, you find User "A" has grade information pointing to Locations "LH", "LR" and "LX" (arbitrary as to not confuse a location with a grade of 1-3 OR 4-6 (or other as later needed)).
Since we know the qualified "Locations", User "A" has access to ANYTHING found within the "LH", "LR" and "LX" locations.
Now, because the ResourceLocationID is in both the Resource_Location and the Resource table, the Grade table can actually join to each directly as the resource location table is nothing more than a lookup to get a descriptive name of where it is. The multiple things IN the room are the resources.
So, the only thing my inner prequery "QualGroups" does, is get a list of the UniqueResources groups (either 1 or 2) a user has access to. The next level is to get all DISTINCT locations under that 1 or 2 status. Because IF a user is access for group 1 at location "LH" AND class group 2 at location "LH", you do not want duplicated resources for location "LH". I am getting the location name while I am at it. (result alias QualLocations)
Now, I can get the resources for those distinct qualified locations
SELECT
QualLocations.ResourceLocationID,
QualLocations.ResourceLocationName,
R.ResourceID,
R.ResourceName,
R.ResourceDescription,
R.ResourceStatusID
from
( SELECT distinct
RL.ResourceLocationID,
RL.ResourceLocationName
from
grade G2
JOIN ( select distinct
G.UniqueResources
from
users_intermediate UI
JOIN grade G
ON UI.GradeID = G.GradeID
where
UI.UserID = "%s" ) QualGroups
ON G2.UniqueResources = QualGroups.UniqueResources
JOIN Resource_Location RL
ON G2.ResourceLocationID = RL.ResourceLocationID )
as QualLocations
JOIN Resource R
ON QualLocations.ResourceLocationID = R.ResourceLocationID
Now, if you ONLY CARE about a very specific classification group, UPDATE the inner-most query joining the "Grade G" table to include the unique resource you are looking for... in this case either 1 or 2
JOIN grade G
ON UI.GradeID = G.GradeID
AND G.UniqueResource = 1 (or 2 if you only wanted 4th-6th grade)
Hope this helps you on your way.
Aside from posted question above, if you change your "UniqueResource" to have a numeric value of the specific GRADE it is vs the verbiage description of the grade name, the AND clause above could be simplified to something like
AND G.UniqueResource IN ( 1, 2, 3 ) // for only grades 1-3
AND G.UniqueResource BETWEEN 1 and 6 // ex: for grades 1-6
AND G.UniqueResource > 6 // for any grade above 6th grade

Related

Count from selection and access both tables with joins

I stumbled upon a query that I have never done until now.
Before asking the question I looked for if another user had had the same need as me but nothing.
My goal is very simple:
having two tables:
collaboratori (collaborators)
invite (invitations)
I have to count how many invitations the collaborators have made.
table structure of collaboratori:
ID_Collaboratori | cod_manager
37 4675
150 6675
3 6575
table structure of inviti:
invite_id | invite_code_manager
37 6675
39 6575
40 4675
41 6675
if I execute the join obviously I access the two tables in this way:
$q_stats_prod_manager = $connessione->prepare("
SELECT * FROM invite
LEFT JOIN collaboratori
ON collaboratori.cod_manager = invite.invite_code_manager ");
$q_stats_prod_manager->execute();
$r_stats_prod_manager = $q_stats_prod_manager->get_result();
my need lies in showing in a table:
show me for each manager who has his cod_manager inside the inviti table, the number of times he sent them.
Name Surname Manager 1 | Number of invite: 200
Name Surname Manager 2 | Number of invite: 50
Name Surname Manager 3 | Number of invite: 10
not limiting myself to just one counter but also being able to access other table values ​​like any join
I take the liberty of putting the answer that was partially written by another user, adding a detail and explanation for future users. The resolution query for this case is the same:
$q_stats_prod_manager = $connessione->prepare("
SELECT count(invite.invite_id)
/*name of what you want to call the result you will see in the while*/
AS result_count, /*you can call this value whatever you want*/
/*Start | Values ​​of the tables you are interested in selecting*/
collaboratori.nome,
collaboratori.data_registrazione,
invite.invite_code_manager
/*End | Values ​​of the tables you are interested in selecting*/
FROM collaboratori
LEFT JOIN invite
ON invite.invite_code_manager = collaboratori.cod_manager group by invite.invite_code_manager
");
$q_stats_prod_manager->execute();
$r_stats_prod_manager = $q_stats_prod_manager->get_result();
$count_invite_manager=mysqli_fetch_array($r_stats_prod_manager);
$number_of_invite_manager = $count_invite_manager[0];
Select the id of the table you want to count
Give a name you wish you want to name the counted result
Select the values ​​of the tables on which you will perform the join you want to view
Join the tables
Show the result with while
Code while:
<?php while($rowstatspm = mysqli_fetch_assoc($r_stats_prod_manager)){ ?>
<!-- this is the fancy name you associated with your query when you wrote: AS nameofwhatyouwant -->
<?php echo $rowstatspm['result_count'] ;?>
<?php } ?>
You seem to want aggregation. I assume you want all rows for collaboratori, so that should be the first table for the LEFT JOIN:
SELECT c.cod_manager, COUNT(i.invite_code_manager)
FROM collaboratori c LEFT JOIN
invite i
ON c.cod_manager = i.invite_code_manager
GROUP BY c.cod_manager;
Your question doesn't describe where the name comes from. But those fields should be in both the SELECT and GROUP BY.
SELECT count(invite.invite_id),collaboratori.name FROM collaboratori
LEFT JOIN invite
ON invite.invite_code_manager = collaboratori.cod_manager group by invite.invite_code_manager

Filling out 2D array based on one or the other argument

I am downloading from my database people working for different companies and I want to create associative array with values "source" and "target" which represent company IDs that the employee works for. There are at least 2 rows for the same person from my query so I know that each person from my query works at least for 2 companies.
Example if 'Aberdeen asset management plc' works for 'New India Investment Trust PLC' (Company ID 300) and for 'Aberdeen New Dawn Investment Trust PLC' (Company ID 4), I would want to have a row in my array like:
"source"=>300,"target"=>4,"officers"=>'Aberdeen asset management plc'
Source & Target are interchangable the order does not matter. Each employee could have multiple rows added if he works for more than 2 companies. The only issue occurs when employee works for odd number of companies but then target/source could be set to the previous source/target that this person works for.
Data example:
while($row = mysqli_fetch_array($dataDB)){
array_push($data, array("Company_ID"=>intval($row['Company_ID']),"Company_Name"=>$row['Company_Name'],"Company_Index"=>$row['Company_Index'], "Officer_Name"=>$row['Officer_Name'], "Officer_Role"=>$row['Officer_Role']));
}
$edges = array();
foreach($data as $d){
array_push($edges, array("source"=>$d['Company_ID']),"target"=>'',"officers"=>array($d['Officer_Name'])));
}
SQL Query is quite long since it is taking into consideration that employees are still working not resigned and taking only workers that work for more than 1 company:
SELECT
CD.Company_ID,
CD.Company_Name,
CD.Company_Index,
OD.Officer_Name,
CO.Officer_Role
FROM
Company_Details CD
INNER JOIN Company_Officer CO
ON CD.Company_ID = CO.Company_ID
INNER JOIN Officer_Details OD
ON CO.Officer_ID = OD.Officer_ID
WHERE CD.Company_Index<>'' AND
CO.Resigned_On='' AND
CO.Officer_ID IN
( SELECT CO2.officer_id
FROM Company_Officer CO2
INNER JOIN Company_Details CD2
ON CO2.Company_ID = CD2.Company_ID
WHERE CO2.Resigned_On='' AND CD2.Company_Index<>''
GROUP BY CO2.officer_id
HAVING Count( DISTINCT CO2.company_id ) > 1
)
ORDER BY `OD`.`Officer_Name` ASC;

MySQL count datas with row values without new query loop

I've 4 table for a newsletter. Newsletters, Subscribers, Subscriber Groups and Selected Subscriber Groups. I've choose subscriber groups in campaign edit area, and its save selected groups to tbl_newsletter_groups table like;
tbl_newsletters
NID title details
1 text 1 content 1
2 text 2 content 2
tbl_subscriber_groups
GID group_name
5 group 1
6 group 2
tbl_subscribers
SID GID email name
10 5 sub1#mail.com sub1 name
11 6 sub1#mail.com sub1 name
tbl_newsletter_groups
NGID NID GID
15 1 6
16 1 6
17 1 6
I want to show total selected subscriber count when I list newsletters in my page. My soulution works fine, Im looking for simple and clearly statement, there any faster way available like in single newsletter list statement?
Here my own count style (yes I know its too bad and long way);
$subGID = array();
$list = $myconn->query("SELECT * FROM tbl_newsletters");
while($listRs = $list->fetch_assoc()){
$grps = $myconn->query("SELECT * FROM tbl_newsletter_groups WHERE NID=". $listRs['NID'] ."");
while($grpsRs = $grps->fetch_asscoc()){
$subGID[] = $grpsRs['GID'];
} $grps->free();
$subs = implode(" OR GID=",$subGID);
$count = mysqli_num_rows($myconn->query("SELECT ID FROM tbl_subscribers WHERE GID=". $subs));
echo('Total Selected Subscriber: '.$count);
} $list->free();
Thanks.
The search term you want is "set-based logic".
Your thinking is sound: you need everything from tbl_newsletters, then you need to count results from tbl_subscribers, but in order to get those you need information from tbl_newsletter_groups.
In SQL, that's an indication you want a join. You've already discovered the conditions you need, you just don't know the syntax. A reference manual can help there.
Now you'll have a bunch of records, which you need to smash into a smaller number of records. You need aggregation functions and a GROUP BY clause.
So here's the final query:
SELECT n.NID, n.title, n.details, COUNT(s.SID)
FROM tbl_newsletters AS n
JOIN tbl_newsletter_groups AS g ON n.NID = g.NID
JOIN tbl_subscribers AS s ON g.GID = s.GID
GROUP BY n.NID

Advanced mysql queries, fetching from several tables and rows at once. Joins?

I'm currently working on a project where I have information stored in several tables that all connect to each other. I believe that the table and column format is logical and the best choice. The problem though, is that I don't have enough knowledge to build queries advanced enough to fetch all the information I need.
The main table is ab_ads, where advertisements are stored. These ads can be assigned several formats (ie. 250x360, 980x120 etc), and you can also select the region where they should be showing (ie. Skåne, Stockholm, Kalmar, Dalarna, Jämtland etc).
This is how I store my data. I'm not showing all tables but I hope this is sufficient.
Advertisements column (ab_ads): (There are more columns but they are not relevant)
ID orgnum company_name title content link
1 556664-7524 Company Inc Lorem ipsum Lorem ipsum URL
Advertisement states (ab_ads_states):
ID adID stateID
1 1 2 // Skåne
2 1 5 // Kalmar
3 1 8 // Stockholm
4 1 10 // Värmland
5 2 2 // Skåne
6 2 5 // Kalmar
7 3 8 // Stockholm
8 4 10 // Värmland
Advertisement formats (ab_ads_formats)
ID adID formatID
1 1 1 // 250x360
2 1 2 // 980x120
3 2 1 // 250x360
4 3 2 // 980x120
Formats table (ab_formats)
ID name width height
1 Format 1 250 360
2 Format 2 980 120
So, I have two flash banners both are supposed to call a PHP-script which in turn is supposed to deliver an XML-file back with all the results.
I know how to select data from different tables, but I've never worked with selecting multiple rows from another table and merging them into one, which I suppose is that I need to do here. I'm very thankful for any help I can get.
The flash banners will send two parameters to the PHP file, stateID and formatID. Which means I have to SELECT ad WHERE state = param AND format = format. But since I store multiple entries for the ad states I don't know how to do it.
EDIT:
I would also like to fetch the format names in the query and get them in the following format: "Format 1,Format 2" in a column named "formats". I guess this would require some kind of join?
Thanks in advance!
I think this will work:
select ab.name as formats, aa.* from ab_ads as aa
inner join ab_ads_states as aas on aa.id = aas.adid and aas.stateId = stateIdParam
inner join ab_ads_formats as aaf on aa.id = aaf.adid and aaf.formatId = formatIdParam
inner join ab_formats as ab on aaf.formatid = ab.id
Edit:
I'm not very good with mySql, and don't have anything to test this on, but I think group_concat may be what you are looking for. If so, it will probably look something like this:
select group_concat(ab.name separator ", ") as formats from ab_ads aa
inner join ab_ads_states as aas on aa.id = aas.adid and aas.stateId = 2
inner join ab_ads_formats as aaf on aa.id = aaf.adid and aaf.formatId in(1,2)
inner join ab_formats as ab on aaf.formatid = ab.id
group by ab.id
Please try below SQL:
SELECT count(aaf.ID) AS TotalFormat,
group_concat(ab.name) AS formats
FROM ab_ads aa
INNER JOIN ab_ads_states AS aas ON aa.ID = aas.adID
AND aas.stateID = 2
INNER JOIN ab_ads_formats AS aaf ON aa.id = aaf.adID
AND aaf.formatID in(1,2)
INNER JOIN ab_formats AS ab ON aaf.formatID = ab.ID
GROUP BY aaf.adID HAVING TotalFormat >=2
SQL Demo: http://sqlfiddle.com/#!2/9f0ab/10

How can I eliminate duplicates in a SQL Join?

I am doing a web-based application in php for my university and I need to show how many students are taking some courses at the same time so they can avoid scheduling conflicts.
This my schema:
studentID course grade program
324532 csc232 0 computer science
I am using php and this is the SQL query. I put grade 0 because he/she taking the course right now.
$result = mysql_query("SELECT s1.course AS c1 , s2.course AS c2 ,count(*) AS count
FROM student s1 ,student s2
WHERE s1.studentID = s2.studentID
AND s1.course!=s2.course AND s1.grade='0' AND s2.grade='0' GROUP BY s1.course,s2.course");
The answer I got is like this:
cscs321 csci322 6 // there is 6 students taking this two courses together
csci321 csci113 4 // there is 4 students taking these two subjects together
The problem is that I got some repeated results. For example csci321, csc322
is the same as csci322 and csci321.
How can I avoid this repetition?
You could try this one:
SELECT
s1.course AS c1,
s2.course AS c2,
count(s2.studentID) AS count
FROM student s1
JOIN student s2 ON (
s1.studentID = s2.studentID
AND s1.course<s2.course -- <-- this line is important
AND s1.grade='0'
AND s2.grade='0'
)
GROUP BY
s1.course,
s2.course;
The idea is to "sort" the courses per line, so that
csci321, csc322
and
csc322, csci321
are considered the same, because csc233 < csci321
You should use SUM instead of COUNT because you want the sum of students and not the count.

Categories