简体   繁体   中英

SQL group by exclude NULL value from grouping

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

(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.

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM