I have a table called " DEVICE " which contains these columns:
------------------------------------------
SN | User_ID | State | ...
------------------------------------------
1 | 1001 | deployed | ...
2 | 1001 | deploying | ...
3 | 1002 | inventory | ...
4 | 1003 | deploying | ...
5 | 1001 | deploying | ...
6 | 1002 | synced | ...
7 | 1002 | synced | ...
8 | 1010 | synced | ...
9 | 1008 | unsynced | ...
---------------------------------------
As you can see, this table lists all the devices, which are belong to different user by their user_id. Also for all these devices, their state is one of these 5 types:
"inventory",
"deployed",
"deploying",
"synced"
"unsynced".
I need a SQL Query that returns back the user_id that holds the maximum devices of each individual State. For example, for the above set of data in the first table, the return would be:
-----------------------------------------------------------
User_ID | State | Maximum
-----------------------------------------------------------
1001 | deployed | 1
1001 | deploying| 2
1002 | inventory| 1
1002 | synced | 2
1008 | unsynced | 1
------------------------------------------------------------
The SQL I have created so far is like this:
SELECT
STATE, ACCOUNT, CNT
from
( select account_id as ACCOUNT, state as STATE, count(*) as CNT
from DEVICE group by account_id, state ) T1
where
( STATE, CNT )
IN
( select STATE, MAX(CNT)
from
( select account_id as ACCOUNT, state as STATE, count(*) as CNT
from DEVICE group by account_id, state ) T2
Group by STATE
);
which is so ugly. Is there a better way to do that ?
Thanks,
Jack
You can create an intermediate summary table or a view like so:
drop table if exists device_summary;
create table device_summary as
select user_id, state, count(*) as counter
from device
group by user_id, state;
Then, you can run a query like so to get your desired results:
select d.*
from device_summary d
inner join (
select state, max(counter) as maxcounter
from device_summary
group by state
) d1 on d.state = d1.state and d.counter = d1.maxcounter;
Example: https://rextester.com/ZMZH93648
You can make use of ROW_NUMBER
analytical function as follows:
SELECT
B.USER_ID,
B.STATE,
B.CNT
FROM
(
SELECT
ROW_NUMBER() OVER(
PARTITION BY A.STATE
ORDER BY
A.CNT DESC
) AS RN,
A.USER_ID,
A.STATE,
A.CNT
FROM
(
SELECT
USER_ID,
STATE,
COUNT(1) CNT
FROM
DEVICE
GROUP BY
USER_ID,
STATE
) A
) B
WHERE
B.RN = 1
Cheers!!
Try this:
SELECT User_ID, State, count(*) AS Maximum
FROM DEVICE
GROUP BY User_ID, State
ORDER BY User_ID, State
You can use window functions, but only need one level of subquery is needed:
SELECT USER_ID, STATE, CNT
FROM (SELECT USER_ID, STATE, COUNT(*) as CNT,
ROW_NUMBER() OVER (PARTITION BY state ORDER BY COUNT(*) DESC) as seqnum
FROM DEVICE
GROUP BY USER_ID, STATE
) us
WHERE seqnum = 1;
Note: If there are ties, this returns an arbitrary user. If you want all of them, use RANK()
instead of ROW_NUMBER()
.
Note: Window functions are only available in MySQL starting with version 8.
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.