Как мне (или Могу ли я) выбрать DISTINCT на нескольких столбцах?

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

поэтому я думаю:

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

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

4 ответов


SELECT DISTINCT a,b,c FROM t

is примерно эквивалентно:

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

это хорошая идея, чтобы привыкнуть к группе по синтаксису, так как она более мощная.

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

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
 )

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

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 (anti-)semi-join для еще лучшей производительности. EXISTS стандартный SQL, имеет был вокруг навсегда (по крайней мере, с PostgreSQL 7.2, задолго до того, как этот вопрос был задан) и идеально подходит для представленных требований:

UPDATE sales s
SET    status = 'ACTIVE'
WHERE  NOT EXISTS (
   SELECT 1
   FROM   sales s1
   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

Скрипка SQL.

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

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

   AND    s1.ctid <> s.ctid

каждая таблица должна иметь первичный ключ. Добавьте один, если у вас его еще нет. Я предлагаю serial или


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


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

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

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

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

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