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

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

Так что я думаю:

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

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

Решение
SELECT DISTINCT a,b,c FROM t

roughly эквивалентно:

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
 )
Комментарии (3)

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

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).

Но это все еще далеко не оптимально. Используйте НЕ СУЩЕСТВУЕТ (анти-) полусоединение для еще лучшей производительности. «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 < > fiddle [здесь](https://dbfiddle.uk/?rdbms = postgres_11 & fiddle = 26c7eb96c3a22330a9c271d554c869fe) * [Старая скрипка SQL][2]

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

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

   AND    s1.ctid  s.ctid

Каждая таблица должна иметь первичный ключ. Добавьте один, если у вас его еще не было. Я предлагаю столбец «серийный» или «IDENTITY» в Postgres 10+.& Лт; / sub >

Связанный:

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

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

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

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

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

AND status  'ACTIVE';

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

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

(123, NULL)
(123, NULL)

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

OTOH, GROUP BY, DISTINCT или DISTINCT ON () рассматривают значения NULL как равные. Используйте соответствующий стиль запроса в зависимости от того, чего вы хотите достичь. Вы все еще можете использовать этот более быстрый запрос с НЕ ОТЛИЧАЕТСЯ ОТ вместо =для любого или всех сравнений, чтобы сделать NULL равным. Больше:

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

[2]: http://sqlfiddle.com/#!17 / 6b5ef / 1

Комментарии (12)

Проблема с вашим запросом заключается в том, что при использовании предложения 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, важно использовать функцию, которая возвращает значение столбца, если есть только одна совпадающая строка.

Комментарии (0)

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

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

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

используйте GROUP, чтобы выбрать записи 'GrondOfLucht' в порядке, указанном 'sortering

SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
Комментарии (1)

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

select distinct(col1, col2) from table

Multi select в целом можно безопасно выполнить следующим образом:

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

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

Комментарии (0)