Как мне (или я могу) ВЫБРАТЬ DISTINCT для нескольких столбцов?

Мне нужно получить все строки из таблицы, в которой 2 столбца в сочетании все разные. Поэтому я хочу, чтобы все продажи, не имеющие других продаж, произошли в тот же день, по той же цене. Продажи, уникальные в зависимости от дня и цены, будут обновлены до активного статуса.

Итак, я думаю:

UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
             FROM sales
             HAVING count = 1)

Но мой мозг болит, идя дальше этого.

Кто-нибудь знает, как я могу добиться того же в запросе критериев? У меня есть sql: select col1, col2, abs (sum (DISTINCT col3 * col4)) У меня есть это мой запрос, например select (cb.col1, col2, expr (sum (prod))). Independent (true). Но это не дает мне отличия от значений col3.

rushabh sojitra 19.02.2021 14:25
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
441
1
958 238
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

SELECT DISTINCT a,b,c FROM t

грубо эквивалентен:

SELECT a,b,c FROM t GROUP BY a,b,c

Рекомендуется привыкнуть к синтаксису GROUP BY, так как он более мощный.

По вашему запросу я бы сделал это так:

UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
    SELECT id
    FROM sales S
    INNER JOIN
    (
        SELECT saleprice, saledate
        FROM sales
        GROUP BY saleprice, saledate
        HAVING COUNT(*) = 1 
    ) T
    ON S.saleprice=T.saleprice AND s.saledate=T.saledate
 )

Этот запрос, хотя и правильный и принят в течение года, - это крайне неэффективный, и это необязательно. Не используйте это. Я предоставил альтернативу и некоторые объяснения в другом ответе.

Erwin Brandstetter 01.10.2012 00:45

разве SELECT DISTINCT a, b, c FROM t именно так не то же самое, что SELECT a, b, c FROM t GROUP BY a, b, c?

famargar 22.01.2017 22:47

@famargar для простого случая, но они имеют разные значения семантически, и они разные с точки зрения того, что вы можете сделать для шага при построении более крупного запроса. Кроме того, люди на технических форумах часто могут быть очень сильно педантичными в отношении вещей, и я считаю, что часто полезно добавлять ласковые слова в мои сообщения в этом контексте.

Joel Coehoorn 22.01.2017 22:50

Проблема с вашим запросом заключается в том, что при использовании предложения GROUP BY (что вы, по сути, делаете, используя отличные), вы можете использовать только столбцы, которые вы группируете или объединяете функции. Вы не можете использовать идентификатор столбца, потому что есть потенциально разные значения. В вашем случае всегда есть только одно значение из-за предложения HAVING, но большинство СУБД недостаточно умны, чтобы распознать это.

Однако это должно работать (и не требует соединения):

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

Вы также можете использовать MAX или AVG вместо MIN, важно использовать функцию, которая возвращает значение столбца, только если есть только одна соответствующая строка.

Если вы соберете ответы, очистите и улучшите, вы получите следующий превосходный запрос:

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

Что на много быстрее, чем любой из них. Снижает производительность принятого в настоящее время ответа в 10-15 раз (в моих тестах на PostgreSQL 8.4 и 9.1).

Но это все еще далеко от оптимального. Используйте полусоединение NOT EXISTS (анти-) для еще большей производительности. EXISTS - это стандартный SQL, он существует вечно (по крайней мере, с PostgreSQL 7.2, задолго до того, как был задан этот вопрос) и идеально соответствует представленным требованиям:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT FROM sales s1                     -- SELECT list can be empty for EXISTS
   WHERE  s.saleprice = s1.saleprice
   AND    s.saledate  = s1.saledate
   AND    s.id <> s1.id                     -- except for row itself
   )
AND    s.status IS DISTINCT FROM 'ACTIVE';  -- avoid empty updates. see below

db <> рабочий пример здесь
Старый скрипт SQL

Уникальный ключ для идентификации строки

Если у вас нет первичного или уникального ключа для таблицы (id в примере), вы можете заменить его системным столбцом ctid для целей этого запроса (но не для некоторых других целей):

   AND    s1.ctid <> s.ctid

Every table should have a primary key. Add one if you didn't have one, yet. I suggest a serial or an IDENTITY column in Postgres 10+.

Связанный:

Как это быстрее?

Подзапрос в анти-полусоединении EXISTS может перестать оцениваться, как только будет обнаружен первый дубликат (нет смысла искать дальше). Для базовой таблицы с несколькими дубликатами это лишь немного эффективнее. При большом количестве дубликатов путь становится более эффективным.

Исключить пустые обновления

Для строк, в которых уже есть status = 'ACTIVE', это обновление ничего не изменит, но все равно вставит новую версию строки за полную стоимость (применяются незначительные исключения). Обычно вы этого не хотите. Добавьте еще одно условие WHERE, как показано выше, чтобы избежать этого и сделать его еще быстрее:

Если status определен как NOT NULL, вы можете упростить:

AND status <> 'ACTIVE';

Тип данных столбца должен поддерживать оператор <>. Некоторые типы, такие как json, этого не делают. Видеть:

Тонкая разница в обработке NULL

Этот запрос (в отличие от в настоящее время принятый ответ Джоэла) не обрабатывает значения NULL как равные. Следующие две строки для (saleprice, saledate) можно квалифицировать как "отдельные" (хотя они выглядят идентично человеческому глазу):

(123, NULL)
(123, NULL)

Также передается уникальный индекс и почти везде, поскольку значения NULL не сравниваются как равные в соответствии со стандартом SQL. Видеть:

OTOH, GROUP BY, DISTINCT или DISTINCT ON () обрабатывают значения NULL как равные. Используйте соответствующий стиль запроса в зависимости от того, чего вы хотите достичь. Вы по-прежнему можете использовать этот более быстрый запрос с IS NOT DISTINCT FROM вместо = для любого или всех сравнений, чтобы сделать сравнение NULL равным. Более:

Если все сравниваемые столбцы определены как NOT NULL, нет места разногласиям.

Хороший ответ. Я работаю с sql-сервером, поэтому первое предложение использовать кортеж с проверкой IN () мне не пришло бы в голову. Предложение не существует, как правило, заканчивается тем же планом выполнения на сервере sql, что и внутреннее соединение.

Joel Coehoorn 01.10.2012 01:03

Отлично. Объяснение значительно увеличивает ценность ответа. У меня почти возникает соблазн провести несколько тестов с Oracle, чтобы увидеть, как планы сравниваются с Postgres и SQLServer.

Peter 15.08.2013 18:59

count(*) менее эффективен, чем что-то вроде: count(saleprice) (если точность не критична, тогда да, используйте count(*))

alairock 29.09.2016 22:47

@alairock: Где ты это взял? Для Postgres противоположный истинно. При подсчете всех строк count(*) эффективнее count(<expression>) на более. Просто попробуйте. Postgres предлагает более быструю реализацию этого варианта агрегатной функции. Может быть, вы путаете Postgres с какой-то другой СУБД?

Erwin Brandstetter 30.09.2016 02:28

@alairock: Я оказался соавтором этой страницы, и на ней ничего подобного не говорится.

Erwin Brandstetter 04.10.2016 23:36

Зачем здесь вообще нужен HAVING COUNT(*) = 1?

techkuz 22.10.2018 18:31

@trthhrtz: Потому что OP ищет уникальные комбинации.

Erwin Brandstetter 23.10.2018 03:23

@ErwinBrandstetter, вы всегда в курсе своих ответов по всей стопке. Вы помогали на протяжении многих лет почти невообразимым количеством способов. Что касается этого примера, я знал несколько разных способов решения моей проблемы, но я хотел увидеть, что кто-то проверил эффективность между вариантами. Спасибо.

WebWanderer 07.05.2019 21:40

Разве «оптимальная» версия действительно не возвращает неправильный результат? Поскольку предложение «имеющий» из предыдущего запроса отсутствует, последний удалит все повторяющиеся строки из набора результатов ... Или я что-то упустил?

Wecherowski 07.09.2019 23:40

@Wecherowski: запрос обновляет все строки, в которых нет дубликатов - по запросу. Нет пункта HAVING, для начала мы ничего не собираем.

Erwin Brandstetter 09.09.2019 02:59

Я хочу выбрать отдельные значения из одного столбца «GrondOfLucht», но они должны быть отсортированы в порядке, указанном в столбце «Сортировка». Я не могу получить отдельные значения только одного столбца, используя

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

Это также даст столбцу «сортировку», и поскольку «GrondOfLucht» И «сортировка» не уникальны, результатом будут ВСЕ строки.

используйте ГРУППУ для выбора записей 'GrondOfLucht' в порядке, заданном 'сортировкой

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

Это в основном объясняет, что делает принятый ответ, но я бы рекомендовал не использовать такие имена для примера (по крайней мере, перевести их). PS: Я рекомендую всегда называть все по-английски во всех проектах, даже если вы нидерландский.

Kerwin Sneijders 14.01.2019 23:13

Если ваша СУБД не поддерживает отдельные столбцы с несколькими столбцами, например:

select distinct(col1, col2) from table

Как правило, множественный выбор можно безопасно выполнять следующим образом:

select distinct * from (select col1, col2 from table ) as x

Поскольку это может работать на большинстве СУБД, и ожидается, что это будет быстрее, чем группировка по решению, поскольку вы избегаете функциональности группировки.

Другие вопросы по теме