mysql group_concat group by on multiple fields - mysql

I have a Table member with member_id, member_name, club_name, region, zone, email as fields.
I am using the MySQL group_concat function like
SELECT group_concat(distinct m.email
SEPARATOR ', ' ) from member m group by m.club_name
This is working fine. But I would like to be able to group_concat on other fields without creating additional queries.
Is it possible to supply the other fields as parameter?
member_id member_name club_name region zone email
1 member1 A 1 1 email1#example.com
2 member2 A 1 1 email2#example.com
3 member3 B 1 1 email3#example.com
4 member4 C 1 2 email4#example.com
5 member5 D 2 1 email5#example.com
**group by club**
email1#example.com,email2#example.com
email3#example.com
email4#example.com
email5#example.com
**group by region**
email1#example.com, email2#example.com, email3#example.com, email4#example.com
email5#example.com
**group by zone**
email1#example.com, email2#example.com, email3#example.com
email5#example.com
Say every Region has 3 Zones, every zone has more than one club. Now how can I get emails which can be grouped or related to Region, Zone or Club for that matter?

It's hard to understand what are you after exactly from your question but you can try
SELECT club_name,
GROUP_CONCAT(DISTINCT email SEPARATOR ', ' ) emails,
GROUP_CONCAT(DISTINCT member_name SEPARATOR ', ' ) members
...
FROM member
GROUP BY club_name
Sample output:
| CLUB_NAME | EMAILS | MEMBERS |
------------------------------------------------------------------------
| Club1 | m1#mail.com, m2#mail.com, m3#mail.com | Jhon, Mark, Beth |
| Club2 | m4#mail.com, m5#mail.com | Helen, Thomas |
Here is SQLFiddle demo
On a side note: providing sample data and desired output in a question like this usually improves your changes of getting your answer faster and that best fits your needs.
UPDATE: You can deeply pack information using GROUP_CONCAT() using different separators if it's what you want
SELECT 'club' group_type, GROUP_CONCAT(details SEPARATOR '|') details
FROM
(
SELECT CONCAT(club_name, ';', GROUP_CONCAT(DISTINCT email)) details
FROM member
GROUP BY club_name
) a
UNION ALL
SELECT 'region' group_type, GROUP_CONCAT(details SEPARATOR '|') details
FROM
(
SELECT CONCAT(region, ';', GROUP_CONCAT(DISTINCT email)) details
FROM member
GROUP BY region
) a
UNION ALL
SELECT 'zone' group_type, GROUP_CONCAT(details SEPARATOR '|') details
FROM
(
SELECT CONCAT(zone, ';', GROUP_CONCAT(DISTINCT email)) details
FROM member
GROUP BY zone
) a
Sample output:
| GROUP_TYPE | DETAILS |
-----------------------------------------------------------------------------------------------------------------------
| club | A;email1#example.com,email2#example.com|B;email3#example.com|C;email4#example.com|D;email5#example.com |
| region | 1;email1#example.com,email2#example.com,email3#example.com,email4#example.com|2;email5#example.com |
| zone | 1;email1#example.com,email2#example.com,email3#example.com,email5#example.com|2;email4#example.com |
Here is SQLFiddle demo
If you're using php on the client side you can then easily enough unwind details column into separate records using explode() while you're iterating over the resultset.

Related

How to bring different values from results column into single row by value from other column sql

I have the following tables:
Teammate ID
Teammate name
Team id
Teams
1
Amy
11
Sales
1
Amy
12
Support
1
Amy
13
Marketing
2
Peter
12
Support
2
Peter
13
Marketing
And I want to group my results so the Teams column appears in one single row by Teammate Id or Teammate name as per below:
Teammate ID
Teammate name
Team id
Teams
1
Amy
11, 12, 13
Sales, Support, Marketing
2
Peter
12, 13
Support, Marketing
Which function would be best/cleanest to use for this purpose? I tried subqueries, coalescing, some weird XML path thing but as a new SQL user I can't wrap my head around figuring this one out
My original query which gave me the results is;
SELECT
tm.teammate_id AS "Teammate ID",
tm.name AS "Teammate name",
itt.team_id AS "Team IDs",
it.team AS "Teams"
FROM
intercom_teammates AS tm
LEFT JOIN intercom_teammate_teams AS itt
ON tm.teammate_id = itt.teammate_id
LEFT JOIN intercom_teams AS it
ON tm.teammate_id = itt.teammate_id
A simple group_concat would do the trick:
select it.TeammateID,
group_concat( distinct it.Teammatename SEPARATOR ',') as Teammatename,
group_concat( it.Teamid SEPARATOR ',') as Teamid,
group_concat( it.Teams SEPARATOR ',') as Teams
from intercom_teammates it
group by it.TeammateID ;
https://dbfiddle.uk/rU8-h8rX
Note. I used distinct on Teammatename, but I think it is excess and you can remove it if for every different TeammateID the Teammatename is unique.
SELECT
tm.teammate_id AS "Teammate ID",
tm.name AS "Teammate name",
GROUP_CONCAT(DISTINCT itt.team_id ORDER BY itt.team_id ASC) AS "Team IDs",
GROUP_CONCAT(DISTINCT it.team ORDER BY it.team DESC) AS "Teams"
FROM intercom_teammates tm
LEFT JOIN intercom_teammate_teams itt ON tm.teammate_id = itt.teammate_id
LEFT JOIN intercom_teams it ON tm.teammate_id = it.teammate_id
GROUP BY tm.teammate_id, tm.name
Note: I've corrected your JOIN to intercom_teams changing itt.teammate_id to it.teammate_id; it was throwing off the result set.
Result:
| Teammate ID | Teammate name | Team IDs | Teams |
|-------------|---------------|----------|--------------------------|
| 1 | Amy | 11,12,13 | Support,Sales,Marketing |
| 2 | Peter | 12,13 | Support,Marketing |
Fiddle here.

Concatenate results from SQL query base on another column

SELECT DISTINCT * FROM ( SELECT hostname, table2.user-id, table2.user-team from
INNER JOIN table2 on table1.id = table2.id)
So at the moment my SQL query outputs this:
hostname user-id user-team
a 1 alpha
a 2 beta
b 3 beta
c 4 alpha
c 1 null
c 3 alpha
but what I want is something like this:
hostname user-id user-team
a 1, 2 alpha, beta
b 3 beta
c 4, 1, 3 alpha
I'm trying to use a GROUP BY hostname statement at the end of my query, and a GROUP_CONCAT(DISTINCT user_id SEPARATOR ', '), GROUP_CONCAT(DISTINCT user_team SEPARATOR ', '),
But this then only returns the first hostname result and all the values possible for the user-id and team-id. I feel like I'm close, but I can't quite get it. Any help?
(At present it returns)
hostname user-id user-team
a 1,2,3,4 alpha, beta
with this as the SQL query
SELECT DISTINCT *
FROM ( SELECT hostname,
GROUP_CONCAT(DISTINCT table2.user-id SEPARATOR(', '),
GROUP_CONCAT(DISTINCT table2.team-id SEPARATOR(', ')
from table1
INNER JOIN table2 on table1.id = table2.id)
GROUP BY hostname
Although the queries arean't 100% accurate, that is the logic in them (they just contain far more columns in the real world problem I have.)
I think you miss the GROUP BY
SQL DEMO
SELECT hostname,
GROUP_CONCAT(DISTINCT user_id SEPARATOR ', ') as users,
GROUP_CONCAT(DISTINCT user_team SEPARATOR ', ') as teams
FROM Table1
GROUP BY hostname
OUTPUT
| hostname | users | teams |
|----------|---------|-------------|
| a | 1, 2 | alpha, beta |
| b | 3 | beta |
| c | 4, 1, 3 | alpha |
EDIT: After you edit your question, the problem was you put the GROUP BY outside of the subquery

Use a GROUP_CONCAT and JOIN in a subquery

I have a DB under MySQL with one main table with unique id, few tables that list different choices (with one id column, one text column to describe the item). So, for one record in the main table, I can have multiple choices associated to the choice table.
I'd like to create a View where all information could be visible, using GROUP_CONCAT to concatenate into one field the different choices from a given 'choice' table. However, my query repeats many times each list of choices when the record is related to other multiple choices from another 'choice' table. The query returns all the possible combinations between those choices...
Here my query (reduced to 2 'choice' tables -t_age, t_animal- for the example)
SELECT general.id_g,
GROUP_CONCAT(CAST(t_age AS CHAR) SEPARATOR ', ') AS age,
GROUP_CONCAT(CAST(t_animal AS CHAR) SEPARATOR ', ') AS animal
FROM general
LEFT JOIN interm_age
INNER JOIN t_age ON interm_age.id_age = t_age.id_age
ON general.id_g = interm_age.id_g
LEFT JOIN interm_animal
INNER JOIN t_animal ON interm_animal.id_animal = t_animal.id_animal
ON general.id_g = interm_animal.id_g
GROUP BY id_g;
I tried to include each CONCAT/JOIN within a subquery into a main SELECT as followed, but MySQL tells me "returns more than 1row", which is the case indeed. And?
SELECT id_g, (
SELECT GROUP_CONCAT(CAST(t_age AS CHAR) SEPARATOR ', ')
FROM general
LEFT JOIN interm_age
INNER JOIN t_age ON interm_age.id_age = t_age.id_age
ON general.id_g = interm_age.id_g
GROUP BY general.id_g )
FROM general;
[EDIT]
In more details, this is my DB (with FK)
general
-----------
id_g | date
902 | 2016/01/01
956 | 2016/02/01
959 | 2016/02/01
interm_age
-----------
id_age | id_g
1 | 902
3 | 902
1 | 956
4 | 956
interm_animal
-----------
id_animal | id_g
1 | 902
5 | 902
5 | 959
7 | 959
t_age
-----------
id_age | age
1 | <10y
3 | >10y
4 | >60y
t_animal
-----------
id_animal | animal
1 | bird
5 | mammal
7 | insect
And I would like something like :
id_g | date | age | animal
902 | 2016/01/01 | <10y, >10y | bird, mammal
and so on...
Thanks in advance!
Although it would be better if you provided some sample data, actual results, and expected results, I'll have a stab at the solution.
The issue probably is that you have multiple matching records in the joined tables, which leads to duplication of values within group_concat().
As MySQL documentation on group_concat() indicates, you can use the distinct keyword to remove duplicate values:
To eliminate duplicate values, use the DISTINCT clause.
SELECT general.id_g,
GROUP_CONCAT(DISTINCT CAST(t_age AS CHAR) SEPARATOR ', ') AS age,
GROUP_CONCAT(DISTINCT CAST(t_animal AS CHAR) SEPARATOR ', ') AS animal
FROM general
LEFT JOIN interm_age
INNER JOIN t_age ON interm_age.id_age = t_age.id_age
ON general.id_g = interm_age.id_g
LEFT JOIN interm_animal
INNER JOIN t_animal ON interm_animal.id_animal = t_animal.id_animal
ON general.id_g = interm_animal.id_g
GROUP BY id_g;
Try this
SELECT general.id_g,
GROUP_CONCAT(CAST(t_age AS CHAR) SEPARATOR ', ') AS age,
GROUP_CONCAT(CAST(t_animal AS CHAR) SEPARATOR ', ') AS animal
FROM general
LEFT JOIN interm_age
INNER JOIN t_age ON interm_age.id_age = t_age.id_age AND general.id_g = interm_age.id_g
LEFT JOIN interm_animal
INNER JOIN t_animal ON interm_animal.id_animal = t_animal.id_animal AND general.id_g = interm_animal.id_g
GROUP BY id_g;
Hope this helps.

MySQL results by userd_id?

I have the following MySQL database table structure:
name | product | client_id
JOHN BROWN | test1.com | 122
JANE SMITH | hosting1 | 122
DAN JOHNSON | test2.com | 355
How to show mysql query results in php in order to get tables with results grouped by client_id. The main point is I need those details emailed by client_id, so in the current example I should get two separated tables fore those two clients.
Assuming your table is called signups
SELECT client_id,
GROUP_CONCAT(DISTINCT name_product_email
ORDER BY name_product_email DESC SEPARATOR ',')
FROM (
SELECT CONCAT(name, ' has this product: ', product) as name_product_email, client_id FROM signups)
GROUP BY client_id;
select client_id, group_concat(product)
from my_table
group by 1;
will produce output like:
122, "test1.com,hosting1"
355, "test2.com"
etc

MySQL: Finding repeated names in my User table

I want to find all users whose name appears at least twice in my User table. 'email' is a unique field, but the combination of 'firstName' and 'lastName' is not necessarily unique.
So far I have come up with the following query, which is very slow, and I am not even sure it is correct. Please let me know a better way to rewrite this.
SELECT CONCAT(u2.firstName, u2.lastName) AS fullName
FROM cpnc_User u2
WHERE CONCAT(u2.firstName, u2.lastName) IN (
SELECT CONCAT(u2.firstName, u2.lastName) AS fullNm
FROM cpnc_User u1
GROUP BY fullNm
HAVING COUNT(*) > 1
)
Also, note that the above returns the list of names that appear at least twice (I think so, anyway), but what I really want is the complete list of all user 'id' fields for these names. So each name, since it appears at least twice, will be associated with at least two primary key 'id' fields.
Thanks for any help!
Jonah
SELECT u.*
FROM cpnc_User u JOIN
(
SELECT firstName, lastName
FROM cpnc_User
GROUP BY firstName, lastName
HAVING COUNT(*) > 1
) X on X.firstName = u.firstName AND x.lastName = u.lastName
ORDER BY u.firstName, u.lastName
There is no need to make up a concatenated field, just use the 2 fields separately
SELECT u.id, u.firstName, u.lastName
FROM cpnc_User u, (
SELECT uc.firstName, uc.lastName
FROM cpnc_User uc
GROUP BY uc.firstName, uc.lastName
HAVING count(*) > 1
) u2
WHERE (
u.firstName = u2.firstName
AND u.lastName = u2.lastName
)
To experiment I created a simple table with two columns a user id, and a name. I inserted a bunch of records, including some duplicates. Then ran this query:
SELECT
count(id) AS count,
group_concat(id) as IDs
FROM
test
GROUP BY
`name`
ORDER BY
count DESC
It should give you results like this:
+-------+----------+
| count | IDs |
+-------+----------+
| 4 | 7,15,4,1 |
| 2 | 2,8 |
| 2 | 6,13 |
| 2 | 14,9 |
| 1 | 11 |
| 1 | 10 |
| 1 | 3 |
| 1 | 5 |
| 1 | 17 |
| 1 | 12 |
| 1 | 16 |
+-------+----------+
You'll need to filter out the later results using something else.
SELECT u.id
, CONCAT(u.firstName, ' ', u.lastName) AS fullname
FROM cpnc_User u
JOIN
( SELECT min(id) AS minid
, firstName
, lastName
FROM cpnc_User
GROUP BY firstName, lastName
HAVING COUNT(*) > 1
) AS grp
ON u.firstName = grp.firstName
AND u.lastName = grp.lastName
ORDER BY grp.minid
, u.id
The ORDER BY grp.minid ensures that users with same first and last name stay grouped together in the output.
OK, you are doing a concatenation, then doing a compare on this, which essentially means that the DB is going to have to do something to every single row of the database.
How about a slightly different approach, you are holding surname and first name separately. So first select all those instances where surname appears > 1 time in your database. Now this has cut your population down dramatically.
Now you can do a compare on the first name to find out where the matches are.