Distinct. Удаление дубликатов
Оператор DISTINCT в SELECT запросах используется для удаления дублирующихся строк из выборки. В общем виде запрос выглядит следующим образом:
select distinct col_name1, col_name2, col_name3, ...
from table_nameПодготовка данных
create table employees(
id number not null,
first_name varchar2(50 char) not null,
last_name varchar2(100 char),
bd date not null,
job varchar2(100)
);
insert into employees
values(1, 'Василий', 'Петров',
to_date('07.10.1990', 'dd.mm.yyyy'), 'Машинист');
insert into employees
values(2, 'Александр', 'Сидоров',
to_date('18.07.1980', 'dd.mm.yyyy'), 'Бухгалтер');
insert into employees
values(3, 'Евгения', 'Цветочкина',
to_date('18.07.1978', 'dd.mm.yyyy'), 'Бухгалтер');
insert into employees
values(4, 'Владимир', 'Столяров',
to_date('18.07.1977', 'dd.mm.yyyy'), 'Слесарь');
insert into employees
values(5, 'Владимир', 'Иванов',
to_date('01.10.1987', 'dd.mm.yyyy'), 'Сторож');
insert into employees
values(6, 'Ирина', 'Васина',
to_date('20.03.1962', 'dd.mm.yyyy'), 'Специалист отдела кадров');
insert into employees
values(7, 'Ирина', 'Иванова',
to_date('31.12.1990', 'dd.mm.yyyy'), 'Арт-директор');
insert into employees
values(8, 'Евгения', NULL,
to_date('18.07.1978', 'dd.mm.yyyy'), 'Бухгалтер');Итого, таблица employees выглядит следующим образом:
| ID | FIRST_NAME | LAST_NAME | BD | JOB |
|---|---|---|---|---|
| 1 | Василий | Петров | 07-OCT-90 | Машинист |
| 2 | Александр | Сидоров | 18-JUL-80 | Бухгалтер |
| 3 | Евгения | Цветочкина | 18-JUL-78 | Бухгалтер |
| 4 | Владимир | Столяров | 18-JUL-77 | Слесарь |
| 5 | Владимир | Иванов | 01-OCT-87 | Сторож |
| 6 | Ирина | Васина | 20-MAR-62 | Специалист отдела кадров |
| 7 | Ирина | Иванова | 31-DEC-90 | Арт-директор |
| 8 | Евгения | - | 18-JUL-78 | Бухгалтер |
Удаление дупликатов из одной колонки
Теперь получим список имён сотрудников:
select first_name
from employeesFIRST_NAME
------------
Василий
Александр
Евгения
Владимир
Владимир
Ирина
Ирина
ЕвгенияМожно заметить, что некоторые имена(Ирина, Владимир, Евгения) дублируются. Теперь посмотрим, какой мы получим результат, если применим оператор DISTINCT:
select distinct first_name
from employeesFIRST_NAME
-----------
Евгения
Василий
Александр
Владимир
ИринаТеперь каждое имя повторяется только один раз.
DISTINCT учитывает все колонки в строке
Теперь применим DISTINCT к выборке из нескольких строк:
select distinct id, first_name
from employees| ID | FIRST_NAME |
|---|---|
| 7 | Ирина |
| 8 | Евгения |
| 5 | Владимир |
| 6 | Ирина |
| 2 | Александр |
| 1 | Василий |
| 3 | Евгения |
| 4 | Владимир |
Теперь дубликаты имен остались, и дело здесь в том, что DISTINCT удаляет дублирующиеся строки, а они в данном случае уникальны, так как, несмотря на повторяющиеся имена сотрудников, каждая строка имеет уникальное значение в колонке ID.
NULL учитывается
Distinct учитывает NULL значения также, как и все остальные:
select distinct last_name
from employeesLAST_NAME
------------
Цветочкина
Столяров
Петров
Васина
Сидоров
Иванова
-
ИвановСтрока с пустой фамилией, как и все остальные, попала в выборку.
DISTINCT с агрегатными функциями
Когда DISTINCT используется с агрегатными функциями, дупликаты колонок не учитываются.
Для начала посчитаем количество не пустых имён в таблице:
select count(first_name) cd
from employeesCD
---
8А теперь посчитаем количество уникальных имён в таблице:
select count(distinct first_name) cd
from employeesCD
---
5Параллельно количеству уникальных имён мы можем получить и количество всех имён:
select count(distinct first_name) cd,
count(first_name) cnt
from employeesCD | CNT
---------
5 | 8Результат наглядно демонстрирует тот факт, что здесь DISTINCT применялся только к той функции, в которой был указан.
DISTINCT и GROUP BY
Получим количество должностей сотрудников и сгруппируем их по именам:
select first_name, count(job) job_cnt
from employees
group by first_name| FIRST_NAME | JOB_CNT |
|---|---|
| Евгения | 2 |
| Василий | 1 |
| Александр | 1 |
| Владимир | 2 |
| Ирина | 2 |
Здесь должно быть всё понятно — у нас есть по два сотрудника с именем «Евгения», «Владимир» и «Ирина», у которых указаны значения в поле JOB.
А теперь посчитаем, сколько уникальных наименований должностей приходится на каждое имя:
select first_name, count(distinct job) job_cnt
from employees
group by first_name| FIRST_NAME | JOB_CNT |
|---|---|
| Евгения | 1 |
| Александр | 1 |
| Василий | 1 |
| Владимир | 2 |
| Ирина | 2 |
Обратить следует внимание на строку с именем «Евгения» - теперь там указано число 1. Это потому, что в нашей таблице у сотрудников с таким именем одна и та же должность — бухгалтер, и количество уникальных значений здесь будет равно 1. Вообще, здесь следует помнить о порядке выполнения запроса — группировка выполняется первее, чем выборка значений, а значит и оператор DISTINCT будет применяться к уже сгруппированному набору данных.