COUNT DISTINCT - scrappyCoco/SQL-Note GitHub Wiki
В MS SQL есть аггрегирующая функция COUNT с возможностью подссчета уникального количества записей по одному столбцу. Но иногда возникает необходимость получить уникальное количество по нескольким столбцам. Для этого придется применять небольшой трюк с оконной функцией DENSE_RANK.
В качестве примера предоставлена история изменений сотрудников:
DECLARE @EmployeeHistory TABLE (
EmployeeId INT,
Name VARCHAR(100),
Department VARCHAR(100),
City VARCHAR(100),
Salary DECIMAL(10, 2)
);
INSERT
INTO @EmployeeHistory (EmployeeId, Name, Department, City, Salary)
VALUES
(0, 'Abraham', 'IT department', 'Moscow', 2000),
(0, 'Abraham', 'IT department', 'Moscow', 2500),
(0, 'Abraham', 'IT department', 'London', 5000),
(1, 'Daniel', 'IT department', 'Moscow', 1000),
(1, 'Daniel', 'IT department', 'London', 1000),
(1, 'Daniel', 'Salary', 'London', 4000);
Для получения количество изменений зарплат по сотрудникам можно воспользоваться аггрегирующей функцией COUNT DISTINCT:
SELECT
Name,
SalaryChanges = COUNT(DISTINCT Salary)
FROM @EmployeeHistory
GROUP BY Name;
Name | SalaryChanges |
---|---|
Abraham | 3 |
Daniel | 2 |
Из данной таблицы видно, что у Abraham возрастала 3 раза, а у Daniel 2.
При возникновении необходимость подссчитать сколько раз менялось местонахождения или отдел, то хотелось бы написать следующий код:
-- Сколько раз менялся местонахождение и отдел.
/*
SELECT
Name,
SalaryChanges = COUNT(DISTINCT Department, City)
FROM @EmployeeHistory
GROUP BY Name;
*/
К сожаленияю, COUNT DISTINCT не принимает несколько аргументов. Но не стоит отчаиваться, ведь есть более извращенный способ с применением оконной функции:
SELECT DISTINCT
Name,
ChangesCount
FROM (
SELECT *,
ChangesCount = DENSE_RANK() OVER (PARTITION BY EmployeeId ORDER BY Department, City) +
DENSE_RANK() OVER (PARTITION BY EmployeeId ORDER BY Department DESC, City DESC) - 1
FROM @EmployeeHistory
) AS DistinctData
Name | ChangesCount |
---|---|
Abraham | 2 |
Daniel | 3 |
Как видно, у Abraham 2 раза менялись офис/отдел, у Daniel - 3.
Также можно воспользоваться стандартной аггрегирующей функцией COUNT DISTINCT, передав ей сконкатенированную строку:
SELECT
Name,
ChangesCount = COUNT(DISTINCT Department + '#' + City)
FROM @EmployeeHistory
GROUP BY Name;