Unexpected results from SQL Query using GROUP_CONCAT - php

I'm having an issue with an sql query and I'm not sure what I am doing wrong. Anyways let me explain:
Initially this was the original query:
SELECT cl.*,
c.id,c.type,
c.firstname,
c.surname,
c.job,
c.company,
c.directorycompany_id,
dc.id, dc.name,
es.id FROM contactlist_contact cl
INNER JOIN contact c ON cl.contact_id = c.id
LEFT JOIN directorycompany dc ON dc.id = c.directorycompany_id
LEFT JOIN expertsection es ON es.id = c.expertsection_id
WHERE cl.contactlist_id = 36311
ORDER BY dc.surname
The statement fetches all of the details from the contactlist table where the id is X. The information it returns is a row for each contact in the contactlist table along with information on the company (directorycompany) they work for and various other details about the contact from the contact table. So the information looks something like this:
contactlist_id contact_id id active id type firstname surname job company directorycompany_id id name id
36311 1939 316955375 1 1939 directory Joe Bloggs Deputy Editor 786 786 Herald People 0
36311 1935 316955374 1 1935 directory Jim Bloggs Advertising Manager 786 786 Herald People 0
36311 28034 316955373 1 28034 directory Jay Bloggs News Reporter 786 786 Herald People 0
I then went and attempted to modify the above SQL as additional functionality was required but I've been seeing unwanted results. Basically I am trying to JOIN 3 other tables
directorycolumn
directorysupplement
directoryprogramme
The idea being that it would return all of the columns, supplements and programmes that the contact in the contactlist has also written. Also to point out, in some cases a contact may have written more than 1 column, supplement or programme and as a result I ideally wanted to display this in the same row as the contact as opposed to duplicating the rows so I used the GROUP_CONCAT() function.
This is the modified SQL
SELECT cl.*,
c.id,
c.type,
c.firstname,
c.surname,
c.job,
c.company,
c.directorycompany_id,
dc.id, dc.name,
es.id,
GROUP_CONCAT(dirc.name) AS gcname,
GROUP_CONCAT(dirp.name) AS gpname,
GROUP_CONCAT(dirs.name) AS gsname
FROM contactlist_contact cl
INNER JOIN contact c ON cl.contact_id = c.id
LEFT JOIN directorycompany dc ON dc.id = c.directorycompany_id
LEFT JOIN expertsection es ON es.id = c.expertsection_id
LEFT JOIN directorycolumn dirc ON dirc.directorycontact_id = c.id
LEFT JOIN directoryprogramme dirp ON dirp.directorycontact_id = c.id
LEFT JOIN directorysupplement dirs ON dirs.directorycontact_id = c.id
WHERE cl.contactlist_id = 36311
ORDER BY dc.surname
This returns:
contactlist_id contact_id id active id type firstname surname job company directorycompany_id id name id gcname gpname gsname
36311 28034 316955373 1 28034 directory Jay Bloggs News Reporter 786 786 Herald People 0 The Arts Scene,Farming \N \N
So my question is, where have the other 2 results gone and why are they not showing? And also why is the information in gcname being displayed for this contact when in fact it is related to the contact with the id 1939

if you remove GROUP_CONCAT it would display correct records, because when you use this function you should have GROUP BY clause. Currently it will consider all records as a single group.
If you look values in gcname is multiple, which is correct.

Group_concat is part of mysql aggregate functions. That means it will group all equal values together into one row, in your case all three columns have the same value, thats why you only get one as result. what result would you expect using group_concat?

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

How to use group by statement on multiple fields in sql?

I have the following tables:
StudentProfile in which I have fields RollNumber, Major
StudentEnrollment in which I have fields RollNumber, CourseCode, Section, Semester
DepartmentFees in which I have fields DepartmentName, Semester, Fees
What I'm trying to do it to find the fees a student has to pay in a particular semester. The problem is the StudentEnrollment table has multiple repeated values which is making it difficult to find the exact fees.
My StudentEnrollment table is like this:
RollNO |CourseCode |Section |Semester
-----------+---------------+------------+------------
ST-0001 |BIOL 300 |A |Fall 2018
ST-0001 |BIOL 500 |A |Spring 2018
ST-0001 |BIOL 450 |B |Spring 2018
ST-0001 |BIOL 475 |A |Spring 2018
ST-0002 |CHEM 500 |A |Spring 2018
ST-0002 |CHEM 450 |B |Spring 2019
Now with repeated values of roll number and Semester how do I get the correct answer.
If I use GROUP BY (StudentEnrollment.RollNo) , the roll number does not repeat I cant get all the semesters the student has attended and if I use GROUP BY (StudentEnrollment.RollNo) I dont get all the student's rollnumbers in the semsester.
Initially I tried using
Select
a.RollNo,
b.Semester,
c.Fees
FROM StudentProfile a
LEFT JOIN StudentEnrollment b ON b.RollNo = c.RollNo
LEFT JOIN DepartmentFees C ON c.DepartmentName = a.Major //AND maybe join semester?
But it doesn't seem to work. What can I try next?
Just add the columns to the Group by clause:
Select
a.RollNo,
b.Semester,
sum(c.Fees) AS 'total'
FROM StudentProfile a
LEFT JOIN StudentEnrollment b ON b.RollNo = c.RollNo
LEFT JOIN DepartmentFees C ON c.DepartmentName = a.Major //AND maybe join semester?
GROUP BY
a.RollNo,
b.Semester
Since you have mention b.Semester, c.Fees in select statement, so to do group by RollNo and Semester, add a.RollNo and b.Semester in GROUP BY clause, I have used "JOIN" instead of "LEFT JOIN" cause use JOIN/INNER JOIN when you want to return only records having pair on both sides, and you’ll use LEFT JOIN when you need all records from the “left” table, no matter if they have pair in the “right” table or not.
Select
a.RollNo,
b.Semester,
sum(c.Fees) AS 'total'
FROM StudentProfile a
JOIN StudentEnrollment b ON b.RollNo = c.RollNo
JOIN DepartmentFees C ON c.DepartmentName = a.Major
GROUP BY
a.RollNo,
b.Semester

mySQL group records with latest entry from child table

I have 3 tables office, Computer and Maintain. Office just list of offices, computers belongs to office as well as has many Maintains.
I want to LEFT join all tables with just the latest entry from Maintain table. The code below works but it just group the oldest entry in the maintain.
SELECT `Computer`.`id`, `Computer`.`control`, `Computer`.`operator`, `Computer`.`datePurchased`, `Computer`.`type`, `Computer`.`property`, `Computer`.`printer`, `Computer`.`scanner`, `Computer`.`osx`, `Computer`.`applications`, `Computer`.`licence`, `Computer`.`isStandAlone`, `Computer`.`isInternet`, `Computer`.`isNetwork`, `Computer`.`generalStatus`, `Computer`.`ip_address`, `Computer`.`mac_address`, `Computer`.`user_id`, `Computer`.`office_id`, `Computer`.`created`, `Computer`.`modified`, `Computer`.`deleted`, `Office`.`id`, `Office`.`description`, `Office`.`main_office`, `Maintain`.`id`, `Maintain`.`dateEncoded`, `Maintain`.`findings`, `Maintain`.`checkedBy`, `Maintain`.`remarks`, `Maintain`.`computer_id`, `Maintain`.`created`, `Maintain`.`modified`, `Maintain`.`user_id` FROM `computers`.`computer` AS `Computer`
LEFT JOIN `computers`.`office` AS `Office`
ON (`Office`.`id` = `Computer`.`office_id`)
LEFT JOIN `computers`.`maintain` AS `Maintain`
ON (`Computer`.`id` = `Maintain`.`computer_id`)
LEFT JOIN (SELECT MAX(dateEncoded) maxDate, findings FROM maintain GROUP BY computer_id) AS `P2`
ON (`Maintain`.`dateEncoded` = `p2`.`maxDate`)
WHERE `Office`.`main_office` LIKE '%CVPH MON%'
GROUP BY `Computer`.`id`
ORDER BY `Office`.`description` ASC
SAMPLE
OFFICE
1 AAAA
2 BBBB
COMPUTER
id name office_id
1 CP1 1
2 CP2 1
3 CP3 2
Maintain
id description date computer_id
1 Fix 06/20/2014 1
2 Fix 06/11/2014 1
3 Fix 06/12/2014 2
4 Fix 06/15/2014 2
Result if query on computer=CP1 should be
Office Computer_name Maintain_desc Date
AAA CP1 Fix 06/20/2014 <- Latest entry in maintain
You can do so
SELECT `c`.`id`,
`c`.`name`,
`c`.`office_id` ,
`o`.`name` office_name,
`m`.`date`,
`m`.`description`
FROM `computer` AS c
LEFT JOIN `office` AS `o`
ON (`o`.`id` = `c`.`office_id`)
LEFT JOIN `maintain` AS m
ON (`c`.`id` = `m`.`computer_id`)
INNER JOIN
(SELECT computer_id,MAX(`date`) maxdate
FROM maintain
GROUP BY computer_id ) t
ON(m.`date`=t.maxdate AND m.computer_id= t.computer_id)
WHERE `c`.`name` ='CP1' ... more conditions
Demo

mySQL select with PHP - left join

I have two tables 'all' and 'jdetails'. I have an existing select query on the all table which works. I want to add some additional data from jdetails table if available.
all table:
judge, year, ...
jane doe, 2012
john doe, 2011
jdetails table:
name, designation,...
jane doe, level 1
jane doe, level 5
john doe, special
How do I change my query below to include the 'designation's (from jdetails) for each judge (in all)?
I think a left join is the solution but I have the where clause to consider. Also, I absolutely must have the results of this query below, but with added data from jdetails table if it exists.
Additionally, there can be multiple rows (jdetails.name) of designations for each all.judge which I want listed as a single value. e.g.-- jane doe would have designation value of 'level 1 level 5'.
I would join on all.judge=jdetails.name
current query:
$rows = $my->get_row("SELECT all.judge, `year`, `totlevel_avg`, `totlevel_count`, `genrank`, `poprank`, `tlevel_avg`, `tlevel_count`, `1level_avg` as `onelevel_avg`, `1level_count` as `onelevel_count`, `2level_avg` as `twolevel_avg`, `2level_count` as `twolevel_count`, `3level_avg` as `threelevel_avg`, `3level_count` as `threelevel_count`, `4level_avg` as `fourlevel_avg`, `4level_count` as `fourlevel_count`, `PSGlevel_avg`, `PSGlevel_count`, `I1level_avg`, `I1level_count`, `I2level_avg`, `I2level_count`, `GPlevel_avg`, `GPlevel_count`, `states` from `all` where `id` ='{$term}'");
any help is greatly appreciated.
I did not include everything you had in your SELECT statement, I just summarized it with ams.*. But the following links the all table to the jdetails table and then groups the designation into one field. Then I wrap the results in an outer query that pulls the rest of the fields you need in the all table (SQL Fiddle):
SELECT ams.*, am.Desigs
FROM
(
SELECT a.judge, GROUP_CONCAT(j.designation SEPARATOR ', ') AS Desigs
FROM `all` AS a
INNER JOIN jdetails AS j ON a.judge = j.name
GROUP BY a.judge
) AS am
INNER JOIN `all` AS ams ON am.judge = ams.judge
Here is an example that can help you:
`SELECT table1.column_name(s),table2.column_name(s) FROM table1
LEFT OUTER JOIN table2 ON table1.column_name=table2.column_name
AND table1.column_name='Parameter'`
Where table 1 is all and table 2 is jdetails

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

Categories