SELECT DISTINCT по нескольким столбцам в SQL: UPDATE уникальных
Как использовать SELECT DISTINCT для нескольких столбцов в SQL. Примеры запросов для поиска и обновления уникальных строк по дате и цене. Синтаксис distinct sql, NOT EXISTS, GROUP BY и CTE для PostgreSQL, MySQL, SQL Server.
Как использовать 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
- Синтаксис SELECT DISTINCT для нескольких столбцов
- SELECT DISTINCT SQL: примеры с GROUP BY и COUNT DISTINCT
- Как найти уникальные строки по дате и цене
- Запрос для обновления строк с SELECT DISTINCT
- Производительные варианты: NOT EXISTS и CTE с ROW_NUMBER()
- Особенности в PostgreSQL, MySQL и SQL Server
- Источники
- Заключение
Что такое 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):
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:
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:
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:
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() (если нужны “первые” уникальные):
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 для сложных случаев:
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 универсален.
Источники
- Stack Overflow — Обсуждение SELECT DISTINCT по нескольким столбцам и UPDATE с NOT EXISTS: https://stackoverflow.com/questions/54418/how-do-i-or-can-i-select-distinct-on-multiple-columns
- w3resource — Примеры синтаксиса SELECT DISTINCT для нескольких столбцов с GROUP BY: https://www.w3resource.com/sql/select-statement/queries-with-distinct-multiple-columns.php
- W3Schools — Базовое объяснение SELECT DISTINCT в SQL с примерами: https://www.w3schools.com/sql/sql_distinct.asp
- 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’ встанет ровно там, где нужно.
В SQL SELECT DISTINCT по нескольким столбцам эквивалентен GROUP BY по тем же полям, например, SELECT DISTINCT saleprice, saledate FROM sales. Для обновления статуса ‘ACTIVE’ уникальных продаж по дате и цене используйте anti-semi-join с NOT EXISTS:
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 — равны.
Синтаксис select distinct sql для нескольких столбцов: SELECT DISTINCT agent_code, ord_amount FROM orders. Для уникальных комбинаций по дате и цене примените GROUP BY с HAVING COUNT(*) = 1:
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 несколько столбцов.
Базовый синтаксис select distinct в SQL: SELECT DISTINCT column1, column2 FROM table_name, что выбирает уникальные комбинации по нескольким столбцам. Для distinct sql это работает как фильтр уникальных строк. Хотя примеры обновления отсутствуют, комбинируйте с подзапросом для обновить строку sql уникальных записей по дате и цене, используя select distinct group by для проверки.
Для обновления уникальных строк используйте CTE с ROW_NUMBER():
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:
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.