Получить наиболее частое значение для каждой группы

#sql #sql-server #tsql

#sql #sql-сервер #tsql

Вопрос:

У меня есть таблица (DeviceOS2), и я хотел бы получить наиболее частое значение для каждого столбца (ОС и устройства) для каждого идентификатора.

 ID      OS      Device

123     OSX     Mac 
123     OSX     PC  
123     OSX     PC  
123     Android Tablet
  

Желаемый результат:

 ID      OS      Device

123     OSX     PC  
  

Однако мой код теперь дает мне следующее:

 ID       OS            Device

123      Android       Tablet
123      OSX           Mac
123      OSX           PC
  

Похоже, он подбирает каждую комбинацию.

Текущий код (T-SQL):

 Select 
ID,
OS,
Device

FROM(
Select 
ID,
OS,
Device
FROM DeviceOS2
Group By ID,OS,Device) a 
Group By ID,OS,Device
  

Ответ №1:

Попробуйте это:

 select top 1 with ties a.ID, a.OS,a.Device
from (
select d.ID, d.OS, d.Device, ROW_NUMBER () over (partition by d.OS, d.Device order by id) rnk
from DeviceOS2 d)a
order by a.rnk desc
  

Обновить

Если вам нужно наиболее частое значение для каждого идентификатора:

 select c.ID,c.OS,c.Device from (
select d.ID, d.OS, d.Device, ROW_NUMBER () over (partition by d.id, d.OS, d.Device order by id) rnk
from DeviceOS2 d)c
join 
(
select  a.ID,max(a.rnk) AS rnk
from (
select d.ID, d.OS, d.Device, ROW_NUMBER () over (partition by d.id, d.OS, d.Device order by id) rnk
from DeviceOS2 d)a
group by a.ID) a
on c.ID = a.ID and a.rnk = c.rnk
  

Комментарии:

1. Спасибо! Однако в моих реальных данных у меня много идентификаторов. Как я могу получить этот результат для каждого идентификатора, который у меня есть, пожалуйста. Еще раз спасибо 🙂

Ответ №2:

Вы могли бы использовать:

 SELECT TOP 1 WITH TIES *
FROM tab
ORDER BY COUNT(*) OVER(PARITIION BY ID,OS) DESC
  

Ответ №3:

Это называется режимом. Вы можете использовать оконные функции:

 select o.*
from (select os, device, count(*) as cnt,
             row_number() over (partition by os order by count(*) desc) as seqnum
      from DeviceOS2
      group by os, device
     ) o
where seqnum = 1;
  

Если вам нужна наиболее частая комбинация, используйте:

 select os, device, count(*) as cnt
from DeviceOS2
group by os, device
order by count(*) desc
fetch first 1 row only;
  

(или используйте select top (1) , если вы предпочитаете).

Редактировать:

Для вашего отредактированного вопроса:

 select o.*
from (select os, device, count(*) as cnt,
             row_number() over (partition by os order by count(*) desc) as seqnum
      from DeviceOS2
      group by os, device
     ) o
where seqnum = 1;
  

Если вам нужна наиболее частая комбинация, тогда запрос немного сложнее. Один метод — это две агрегации:

 select o.id,
       max(case case when o.seqnum = 1 then os end) as most_frequent_os,
      max(case case when d.seqnum = 1 then device end) as most_frequent_device
from (select id, os, count(*) as cnt,
             row_number() over (partition by id order by count(*) desc) as seqnum
      from DeviceOS2
      group by id, os
     ) o join
     (select id, device, count(*) as cnt,
             row_number() over (partition by id order by count(*) desc) as seqnum
      from DeviceOS2
      group by id, device
     ) d
     on d.id = o.id
  

Комментарии:

1. Спасибо! Однако, когда я его запускаю, я также получаю строку с Android Tablet . Как я могу получить только OSX PC пожалуйста.

2. @яблоки-апельсины . , , Я интерпретировал вопрос как наиболее частое устройство для каждой ОС.

3.А, ладно! Спасибо, приятель 🙂 Пожалуйста, завершите: как получить наиболее частое значение для каждого отдельного столбца, для каждого ID (в моем примере ID показан только один). Так что для ID 123 , OSX является наиболее частым OS . Аналогично для Device , наиболее частым является PC . Следовательно, результирующая таблица предназначена OSX PC для ID 123 . Еще раз спасибо! 🙂