Мне нужно извлечь все строки из таблицы, где 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
)
Если вы соберете ответы до сих пор, очистите и улучшите, вы получите этот превосходный запрос:
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
Если у вас нет первичного или уникального ключа для таблицы (id
в примере), вы можете заменить системный столбец ctid
для целей данного запроса (но не для некоторых других целей):
AND s1.ctid <> s.ctid
Каждая таблица должна иметь первичный ключ. Добавьте один, если у вас его еще не было. Я предлагаю столбец «серийный» или «IDENTITY» в Postgres 10+.& Лт; / sub >
Связанный:
Подрайон в анти-полу-сое EXISTS
может перестать оценивать, как только будет найден первый дупе (нет смысла смотреть дальше). Для базовой таблицы с несколькими дубликатами это лишь немного эффективнее. С большим количеством дубликатов это становится намного более эффективным.
Для строк, которые уже имеют status = 'ACTIVE'
, это обновление ничего не изменит, но все же вставит новую версию строки по полной цене (применяются незначительные исключения). Обычно вы этого не хотите. Добавьте еще одно условие «ГДЕ», как показано выше, чтобы избежать этого и сделать его еще быстрее:
Если status
определен NOT NULL
, вы можете упростить:
AND status <> 'ACTIVE';
Этот запрос (в отличие от в настоящее время принятого ответа Джоэла) не рассматривает значения NULL как равные. Следующие два ряда для (салеприс, саледат)
будут квалифицироваться как «отличительные» (хотя выглядят идентично человеческому глазу):
(123, NULL)
(123, NULL)
Также проходит уникальный индекс и почти в любом другом месте, поскольку значения NULL не сравниваются равными в соответствии со стандартом SQL. Видеть:
OTOH, GROUP BY
, DISTINCT
или DISTINCT ON ()
рассматривают значения NULL как равные. Используйте соответствующий стиль запроса в зависимости от того, чего вы хотите достичь. Вы все еще можете использовать этот более быстрый запрос с НЕ ОТЛИЧАЕТСЯ ОТ
вместо =
для любого или всех сравнений, чтобы сделать NULL равным. Больше:
Если все сравниваемые столбцы определены как «НЕ NULL», нет места для разногласий.
[2]: http://sqlfiddle.com/#!17 / 6b5ef / 1
Проблема с вашим запросом заключается в том, что при использовании предложения 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, важно использовать функцию, которая возвращает значение столбца, если есть только одна совпадающая строка.
Я хочу выбрать отдельные значения из одного столбца «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)
Если ваша СУБД не поддерживает различные столбцы, как это:
select distinct(col1, col2) from table
Multi select в целом можно безопасно выполнить следующим образом:
select distinct * from (select col1, col2 from table ) as x
Поскольку это может работать на большинстве СУБД, ожидается, что это будет быстрее, чем групповое решение, поскольку вы избегаете функциональности группировки.