Выберите наиболее часто встречающиеся записи, используя два или более столбцов группировки - PullRequest
1 голос
/ 30 июля 2009

У меня есть таблица, у которой нет первичного ключа, и я не могу добавить ее - соответствующие столбцы из нее:

Department   | Category  | 
-------------+-----------+
0001         | A         |
0002         | D         |
0003         | A         | 
0003         | A         |
0003         | C         |
0004         | B         |

Я хочу получить по одной строке для каждого Department, который дает мне код отдела и Category, который чаще всего появляется в таблице, т.е.

Department   | Category  | 
-------------+-----------+
0001         | A         |
0002         | D         |
0003         | A         | 
0004         | B         |

Каков наилучший способ достичь этого? Моя текущая попытка включает в себя Count(Category) в подзапросе, из которого затем берется Max(CountofCategory), но включение поля Category на этом этапе означает слишком много строк при возврате (поскольку GROUP BY применяется на уровне Category как а также Department). В случае ничьей, я бы просто выбрал мин / макс категории произвольно. В идеале это должно быть независимым от базы данных, но, скорее всего, будет работать на Oracle или MySQL.

Ответы [ 4 ]

3 голосов
/ 30 июля 2009

Работает как в Oracle, так и в SQL Server, я полагаю, что все это стандартный SQL, от более поздних стандартов:

with T_with_RN as
    (select Department
        , Category
        , row_number() over (partition by Department order by count(*) Desc) as RN
    from T
    group by Department, Category)
select Department, Category
from T_with_RN
where RN = 1

РЕДАКТИРОВАТЬ Я не знаю, почему я использовал WITH, решение, вероятно, легче читать с помощью встроенного представления:

select Department, Category
from (select Department
    , Category
    , row_number() over (partition by Department order by count(*) Desc) as RN
    from T
    group by Department, Category) T_with_RN
where RN = 1

КОНЕЦ РЕДАКТИРОВАНИЯ

Контрольные примеры:

create table T (
    Department varchar(10) null,
    Category varchar(10) null
);

-- Original test case
insert into T values ('0001', 'A');
insert into T values ('0002', 'D');
insert into T values ('0003', 'A');
insert into T values ('0003', 'A');
insert into T values ('0003', 'C');
insert into T values ('0004', 'B');
-- Null Test cases:
insert into T values (null, 'A');
insert into T values (null, 'B');
insert into T values (null, 'B');
insert into T values ('0005', null);
insert into T values ('0005', null);
insert into T values ('0005', 'X');
-- Tie Test case
insert into T values ('0006', 'O');
insert into T values ('0006', 'P');
1 голос
/ 13 февраля 2017

Вы также можете попробовать следующее. Окно здесь возвращает категории, упорядоченные по частоте совпадения с каждым отделом. FIRST_VALUE () выбирает первое из этого.

SELECT DISTINCT (department), 
  FIRST_VALUE(category) OVER
    (PARTITION BY department ORDER BY count(*) DESC ROWS UNBOUNDED PRECEDING)
FROM T
GROUP BY department, category;
0 голосов
/ 29 марта 2013

Есть более простой способ:

select department, stats_mode(category) from T ;

прекрасно работает, когда требуется только наиболее частое значение, когда вам нужно 2-е, 3-е ... чаще всего вы должны выполнять подсчет, как указано выше.

0 голосов
/ 30 июля 2009

Вам придется это исправить, если вы лучше справляетесь с подзапросами, чем я, но в моем тестировании это дало желаемый результат:

SELECT
  main.Department as Department,
  (SELECT 
     Category
   FROM yourtable
   WHERE Department=main.Department
   GROUP BY Category
   ORDER BY COUNT(Category) DESC
   LIMIT 1) AS Category
FROM yourtable main
GROUP BY main.Department

Хитрость заключается в том, чтобы просто получить одну строку в подзапросе, чтобы вернуть максимальное значение, которое вы хотите, с помощью ORDER BY и "LIMIT 1"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...