4

I've got this situation in a table

client   staff   code   time1   time2
------------------------
c1       null    code1
c2       null    code1
null     s1      code1
null     s2      code1

Trying to grouping rows by staff and code :

SELECT GROUP_CONCAT(client),staff,code from table GROUP BY staff,code

I get obviously:

client   staff   code   ...  time1   time2
------------------------
c1,c2    null    code1
null     s1      code1   <-
null     s2      code1   <-

For the purpose of the feature requested i need the entries "focused" on the staff so i can get also relative time1 and time2. The problem is that the rows indicated by the arrows above don't have any clients id so there is no chance to retrieve their data. Client informations are into the staff = null row.

How can i achieve something like this?

client   staff   code   ...  time1   time2
------------------------
c1,c2    s1      code1   <-
c1,c2    s2      code1   <-

thanks

Fabio Santo
  • 138
  • 1
  • 3
  • 9
  • Do you want all client time for code1 for each staff? I think an example of what you want with data in the time1 field would make it easier to answer your question. – idstam Nov 03 '15 at 06:07
  • for the purpose of the question the time 1 is not the main problem. I need to have the c1,c2 related to the staff for each row. This is the main problem. – Fabio Santo Nov 03 '15 at 21:33
  • This design is going to cause you trouble in future, particularly when trying to look up info for clients c1 or c2 in some client table. You can normalise it by adding a table with tableid (fk to your table shown) and clientid (fk to client table). Some examples here- https://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-that-bad – OwlsSleeping Feb 18 '20 at 12:40

3 Answers3

3

(Little late answer :), but it may help someone else !)

First, you must realize that a single FROM can't generate a row with both c1 and s1 (for example), and another row with both c1 and s2. Except, of course, a single row with GROUP_CONCAT(client), GROUP_CONCAT(staff), but it wouldn't be useful, as it loses the link between clients and staffs.

What you have to do is to join your table with itself :

client   staff   code   
------------------------
c1       null    code1
c2       null    code1
null     s1      code1
null     s2      code1
c3       null    code1*
c4       null    code2*


SELECT c.client, s.staff, c.code
FROM `table` c
INNER JOIN `table` s ON s.code = c.code

client   staff   code
------------------------
c1       null    code1
c1       null    code1
c1       s1      code1
c1       s2      code1

c2       null    code1
c2       null    code1
c2       s1      code1
c2       s2      code1

null     null    code1
null     null    code1
null     s1      code1
null     s2      code1

null     null    code1
null     null    code1
null     s1      code1
null     s2      code1

Obviously, the cross join between two 4-rows tables give 16 result. Excluding rows with null :

SELECT c.client, s.staff, c.code
FROM `table` c
INNER JOIN `table` s ON s.code = c.code AND s.staff IS NOT NULL
WHERE c.client IS NOT NULL

client   staff   code
------------------------
c1       s1      code1
c1       s2      code1

c2       s1      code1
c2       s2      code1

Then, you can group by staff and code, and aggregates the clients :

SELECT GROUP_CONCAT(c.client), s.staff, c.code
FROM `table` c
INNER JOIN `table` s ON s.code = c.code AND s.staff IS NOT NULL
WHERE c.client IS NOT NULL
GROUP BY staff, c.code

client   staff   code
------------------------
c1,c2     s1      code1
c1,c2     s2      code1

NB : As written, it won't show the codes having only clients and not staffs, and those having staffs and not codes. If one of this case is possible, then you have to LEFT JOIN the concerned table (table c LEFT JOIN staff s, or table s LEFT JOIN table c, with the appropriate tests on NULL) instead of INNER JOIN.

client   staff   code   time1   time2
------------------------
c1       null    code1
c2       null    code1
null     s1      code1
null     s2      code1
*c3      null    code2*
*null    s3      code3*

SELECT GROUP_CONCAT(c.client), s.staff, c.code
FROM `table` c
LEFT JOIN `table` s ON s.code = c.code AND s.staff IS NOT NULL
WHERE c.client IS NOT NULL
GROUP BY staff, c.code

client   staff   code
------------------------
c1,c2     s1      code1
c1,c2     s2      code1
c3        NULL    code2

SELECT GROUP_CONCAT(c.client), s.staff, c.code
FROM `table` s
LEFT JOIN `table` c ON c.code = s.code AND c.client IS NOT NULL
WHERE s.staff IS NOT NULL
GROUP BY staff, c.code

client   staff   code
------------------------
c1,c2     s1      code1
c1,c2     s2      code1
NULL      s3      code3

It's not clear why you have rows that have either client or staff filled (but not both); maybe you should rethink your model.

Pierre-Olivier Vares
  • 1,687
  • 15
  • 20
0

put the where clause before group like this :-

SELECT GROUP_CONCAT(client),staff,code from table 
where client IS NOT NULL AND staff  IS NOT NULL
GROUP BY staff,code
Lakmi
  • 1,379
  • 3
  • 16
  • 27
  • 2
    with this i will not get any rows, cause there isn't any row with client and staff not null at the same iteration. – Fabio Santo Nov 03 '15 at 21:37
0

Use SELECT * and determine your common unique row. In my example I wanted profiles. Some people might not have messages, some people might not have authenticated. So instead of using GROUP BY on authentication or messages I used GROUP BY on the user name - all rows will have this data to return even after adding GROUP BY and rows with NULL columns will still be returned.

The code posted in the question does not return any unique rows hence commenting out the GROUP BY clause and using SELECT * to find that unique row is critical to determining which row you should use GROUP BY with. As pointed out by the other two answers you can use multiple columns for GROUP BY (and ORDER BY as well) delimited by commas.

John
  • 1
  • 13
  • 98
  • 177