Базы данных

SELECT DISTINCT по нескольким столбцам в SQL: UPDATE уникальных

Как использовать SELECT DISTINCT для нескольких столбцов в SQL. Примеры запросов для поиска и обновления уникальных строк по дате и цене. Синтаксис distinct sql, NOT EXISTS, GROUP BY и CTE для PostgreSQL, MySQL, SQL Server.

5 ответов 1 просмотр

Как использовать SELECT DISTINCT для нескольких столбцов в SQL? Мне нужно найти и обновить строки, которые уникальны на основе комбинации двух столбцов (дата продажи и цена). Как правильно составить запрос для обновления статуса ‘ACTIVE’ для продаж, которые не имеют дубликатов по дате и цене? Какой синтаксис SQL для SELECT DISTINCT по нескольким столбцам?

SELECT DISTINCT по нескольким столбцам в SQL — это простой способ выбрать уникальные комбинации значений, например, SELECT DISTINCT saledate, saleprice FROM sales. Для обновления статуса ‘ACTIVE’ только уникальных продаж по дате и цене подойдет запрос с NOT EXISTS: UPDATE sales s SET status = 'ACTIVE' WHERE NOT EXISTS (SELECT 1 FROM sales s2 WHERE s.saledate = s2.saledate AND s.saleprice = s2.saleprice AND s.id <> s2.id). Такой подход в distinct sql гарантирует, что обновятся только строки без дубликатов по этим полям, и работает быстрее аналогов с GROUP BY.


Содержание


Что такое SELECT DISTINCT в SQL и зачем нужен distinct sql

Представьте: у вас таблица продаж с тысячами строк, и половина из них — дубликаты по дате и цене. Без distinct sql вы утонете в повторах. SELECT DISTINCT — это команда, которая фильтрует результат, оставляя только уникальные комбинации значений. Не просто уникальные строки целиком, а именно по указанным столбцам.

Зачем это нужно? В реальной работе distinct sql спасает от мусора в отчетах. Хотите список уникальных дат продаж с ценами? DISTINCT сделает это за секунды. А если данных миллионы, то без него запросы тормозят. По данным Stack Overflow, разработчики часто путают его с GROUP BY, но они почти синонимы для нескольких столбцов.

Коротко: DISTINCT убирает дубликаты. И точка. Но что, если нужно не просто выбрать, а обновить?


Синтаксис SELECT DISTINCT для нескольких столбцов

Синтаксис предельно прост: SELECT DISTINCT столбец1, столбец2 FROM таблица. Для вашего случая с датой и ценой: SELECT DISTINCT saledate, saleprice FROM sales. SQL проверит все пары и вернет только уникальные.

А если добавить WHERE? SELECT DISTINCT saledate, saleprice FROM sales WHERE status != 'CANCELLED'. DISTINCT применяется после WHERE, так что фильтр сработает сначала.

Но вот загвоздка: NULL-ы. В большинстве СУБД два NULL считаются равными в DISTINCT, в отличие от сравнений (=). Хотите игнорировать NULL? Добавьте WHERE saledate IS NOT NULL.

Из w3resource базовый пример: SELECT DISTINCT agent_code, ord_amount, ord_date FROM orders. Точно то, что нужно для distinct несколько столбцов. Пробуйте на своих данных — увидите магию сразу.


SELECT DISTINCT SQL: примеры с GROUP BY и COUNT DISTINCT

SELECT DISTINCT SQL эквивалентен GROUP BY по тем же столбцам. Хотите посчитать уникальные? SELECT COUNT(DISTINCT saledate, saleprice) FROM sales. Это вернет число уникальных пар.

А для списка с подсчетом: SELECT saledate, saleprice, COUNT(*) as cnt FROM sales GROUP BY saledate, saleprice. Здесь GROUP BY делает то же, что DISTINCT, но позволяет агрегаты вроде COUNT.

Пример из практики. Допустим, таблица sales:

id saledate saleprice status
1 2023-01-01 100 NULL
2 2023-01-01 100 NULL
3 2023-01-02 150 NULL

Запрос SELECT DISTINCT saledate, saleprice FROM sales вернет две строки: (2023-01-01,100) и (2023-01-02,150). А SELECT saledate, saleprice, COUNT(*) FROM sales GROUP BY saledate, saleprice покажет cnt=2 для первой пары.

По W3Schools, это стандарт для select distinct group by. Но для обновления одного недостаточно — нужен подзапрос.


Как найти уникальные строки по дате и цене

Sql уникальные строки по двум полям? Ищите те, где комбинация встречается ровно раз. Классика: SELECT * FROM sales WHERE (saledate, saleprice) IN (SELECT saledate, saleprice FROM sales GROUP BY saledate, saleprice HAVING COUNT(*) = 1).

Это вернет полные строки без дубликатов. Почему GROUP BY? Потому что DISTINCT сам по себе не считает.

Альтернатива с оконной функцией (SQL Server, PostgreSQL):

sql
SELECT * FROM (
 SELECT *, COUNT(*) OVER (PARTITION BY saledate, saleprice) as dup_cnt
 FROM sales
) t WHERE dup_cnt = 1;

Быстрее на больших таблицах. Вопрос: сколько у вас строк? Если миллионы, индексы на saledate + saleprice обязательны.

Такой подход из обсуждений на SQLServerCentral — там хвалят за точность.


Запрос для обновления строк с SELECT DISTINCT

Теперь к главному: обновить строку sql только для уникальных. Базовый вариант с IN:

sql
UPDATE sales 
SET status = 'ACTIVE' 
WHERE (saledate, saleprice) IN (
 SELECT saledate, saleprice 
 FROM sales 
 GROUP BY saledate, saleprice 
 HAVING COUNT(*) = 1
);

Работает в PostgreSQL, MySQL. Но в SQL Server IN с подзапросом иногда капризничает с NULL.

Лучше UPDATE с JOIN:

sql
UPDATE s 
SET status = 'ACTIVE' 
FROM sales s
INNER JOIN (
 SELECT saledate, saleprice 
 FROM sales 
 GROUP BY saledate, saleprice 
 HAVING COUNT(*) = 1
) uniq ON s.saledate = uniq.saledate AND s.saleprice = uniq.saleprice;

Это обновить строку sql без лишних проверок. Добавьте WHERE status IS DISTINCT FROM 'ACTIVE' — сэкономит время на повторных запусках.


Производительные варианты: NOT EXISTS и CTE с ROW_NUMBER()

IN хорош, но NOT EXISTS быстрее для анти-джойнов. Из Stack Overflow:

sql
UPDATE sales s 
SET status = 'ACTIVE' 
WHERE NOT EXISTS (
 SELECT 1 
 FROM sales s2 
 WHERE s.saledate = s2.saledate 
 AND s.saleprice = s2.saleprice 
 AND s.id <> s2.id
);

Здесь проверяем: нет ли другой строки с той же парой? Идеально для distinct sql. NULL обрабатываются корректно — два NULL не равны в EXISTS.

Для SQL Server CTE с ROW_NUMBER() (если нужны “первые” уникальные):

sql
WITH unique_sales AS (
 SELECT *, ROW_NUMBER() OVER (PARTITION BY saledate, saleprice ORDER BY id) rn
 FROM sales
)
UPDATE us 
SET status = 'ACTIVE' 
FROM unique_sales us 
WHERE rn = 1 AND COUNT_OVER_PARTITION = 1; -- Дополнить COUNT если нужно

Тестируйте на EXPLAIN ANALYZE. NOT EXISTS часто выигрывает на 20-50% по времени.

А если дубликаты — оставить первый? ROW_NUMBER решает.


Особенности в PostgreSQL, MySQL и SQL Server

В PostgreSQL distinct несколько столбцов — родная фича: SELECT DISTINCT ON (saledate, saleprice) * FROM sales ORDER BY saledate, saleprice, id. DISTINCT ON выбирает первую строку по ORDER BY!

MySQL: стандартный DISTINCT, но UPDATE с множественным IN медленнее. Используйте ключи.

SQL Server: Нет DISTINCT ON, но CTE + ROW_NUMBER — король. Плюс MERGE для сложных случаев:

sql
MERGE sales AS target
USING (SELECT saledate, saleprice FROM sales GROUP BY saledate, saleprice HAVING COUNT(*) = 1) AS source
ON target.saledate = source.saledate AND target.saleprice = source.saleprice
WHEN MATCHED THEN UPDATE SET status = 'ACTIVE';

PostgreSQL distinct по нескольким столбцам сияет в DISTINCT ON. В общем, выбирайте по СУБД — но NOT EXISTS универсален.


Источники

  1. Stack Overflow — Обсуждение SELECT DISTINCT по нескольким столбцам и UPDATE с NOT EXISTS: https://stackoverflow.com/questions/54418/how-do-i-or-can-i-select-distinct-on-multiple-columns
  2. w3resource — Примеры синтаксиса SELECT DISTINCT для нескольких столбцов с GROUP BY: https://www.w3resource.com/sql/select-statement/queries-with-distinct-multiple-columns.php
  3. W3Schools — Базовое объяснение SELECT DISTINCT в SQL с примерами: https://www.w3schools.com/sql/sql_distinct.asp
  4. SQLServerCentral — Варианты UPDATE уникальных строк с CTE и ROW_NUMBER(): https://www.sqlservercentral.com/forums/topic/update-column-but-with-distinct-values

Заключение

В итоге, для distinct sql по нескольким столбцам начните с простого SELECT DISTINCT saledate, saleprice. А для обновления уникальных продаж — NOT EXISTS или GROUP BY HAVING COUNT(*)=1, в зависимости от СУБД. Тестируйте на индексах, чтобы избежать тормозов. Такой подход сэкономит часы на очистке данных — и статус ‘ACTIVE’ встанет ровно там, где нужно.

J

В SQL SELECT DISTINCT по нескольким столбцам эквивалентен GROUP BY по тем же полям, например, SELECT DISTINCT saleprice, saledate FROM sales. Для обновления статуса ‘ACTIVE’ уникальных продаж по дате и цене используйте anti-semi-join с NOT EXISTS:

sql
UPDATE sales s 
SET status = 'ACTIVE' 
WHERE NOT EXISTS (
 SELECT FROM sales s1 
 WHERE s.saleprice = s1.saleprice 
 AND s.saledate = s1.saledate 
 AND s.id <> s1.id
);

Это быстрее IN с GROUP BY ... HAVING COUNT(*) = 1, особенно при дубликатах. Добавьте AND s.status IS DISTINCT FROM 'ACTIVE' для избежания пустых обновлений. Distinct sql обрабатывает NULL по-разному: в NOT EXISTS они не равны, в GROUP BY — равны.

w3resource / Образовательная платформа

Синтаксис select distinct sql для нескольких столбцов: SELECT DISTINCT agent_code, ord_amount FROM orders. Для уникальных комбинаций по дате и цене примените GROUP BY с HAVING COUNT(*) = 1:

sql
UPDATE orders 
SET status='ACTIVE' 
WHERE (date, price) IN (
 SELECT date, price 
 FROM orders 
 GROUP BY date, price 
 HAVING COUNT(*)=1
);

Это позволяет обновить строки sql без дубликатов по нескольким полям. Запрос select distinct возвращает уникальные пары значений, аналогично distinct несколько столбцов.

W3Schools / Образовательная платформа

Базовый синтаксис select distinct в SQL: SELECT DISTINCT column1, column2 FROM table_name, что выбирает уникальные комбинации по нескольким столбцам. Для distinct sql это работает как фильтр уникальных строк. Хотя примеры обновления отсутствуют, комбинируйте с подзапросом для обновить строку sql уникальных записей по дате и цене, используя select distinct group by для проверки.

D

Для обновления уникальных строк используйте CTE с ROW_NUMBER():

sql
WITH cte AS (
 SELECT *, ROW_NUMBER() OVER (PARTITION BY CarID ORDER BY Id) rn 
 FROM #Test
)
UPDATE cte SET status='2' WHERE rn=1;

Альтернатива — UPDATE с INNER JOIN и GROUP BY:

sql
UPDATE t 
SET status='2' 
FROM #Test t 
INNER JOIN (
 SELECT CarID, MIN(Id) 
 FROM #Test 
 GROUP BY CarID 
 HAVING COUNT(*)>1
) t2 ON t.Id=t2.Id;

Это решает задачу sql уникальные строки по нескольким полям, но учитывайте одиночные записи. Идеально для MS SQL с select count distinct.

Авторы
J
Директор информационных технологий
E
Консультант по PostgreSQL
C
Разработчик
D
Разработчик
K
Разработчик
J
Эксперт по SQL
Источники
w3resource / Образовательная платформа
Образовательная платформа
W3Schools / Образовательная платформа
Образовательная платформа
Проверено модерацией
НейроОтветы
Модерация
SELECT DISTINCT по нескольким столбцам в SQL: UPDATE уникальных