Jak Mogę (lub Mogę) wybrać różne na wielu kolumnach?
Muszę pobrać wszystkie wiersze z tabeli, w której połączone 2 kolumny są różne. Więc chcę wszystkie sprzedaży, które nie mają żadnych innych sprzedaży, które miały miejsce w tym samym dniu za tę samą cenę. Sprzedaż, która jest unikalna w zależności od dnia i ceny, zostanie zaktualizowana do stanu aktywnego.
Tak sobie myślę:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Ale boli mnie mózg. 4 answers
SELECT DISTINCT a,b,c FROM t
Jest mniej więcej równoważne:
SELECT a,b,c FROM t GROUP BY a,b,c
To dobry pomysł, aby przyzwyczaić się do grupy przez składnię, ponieważ jest bardziej wydajny.
Dla Twojego zapytania, zrobiłbym to tak:
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
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-10 15:55:08
Jeśli zbierzesz odpowiedzi do tej pory, posprzątaj i popraw, dojdziesz do tego nadrzędnego zapytania:
UPDATE sales
SET status = 'ACTIVE'
WHERE (saleprice, saledate) IN (
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING count(*) = 1
);
Który jest znacznie szybszy niż którykolwiek z nich. W moich testach na PostgreSQL 8.4 i 9.1 sprawdzam poprawność aktualnie akceptowanej odpowiedzi przez współczynnik 10 - 15 (W moich testach na PostgreSQL 8.4 i 9.1).
Ale to wciąż nie jest optymalne. Użyj a NOT EXISTS
(anti -) semi-join dla jeszcze lepszej wydajności. EXISTS
jest standardowym SQL, istnieje od zawsze (przynajmniej od PostgreSQL 7.2, na długo przed tym pytaniem) i idealnie pasuje do przedstawionych wymagań: {]}
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 Fiddle.
Unikalny klucz do identyfikacji wiersza
Jeśli nie masz klucza głównego lub unikalnego dla tabeli (id
w przykładzie), możesz zastąpić kolumną systemową ctid
dla celów tego zapytania (ale nie dla niektórych innych celów):
AND s1.ctid <> s.ctid
każdy stół powinien mieć klucz podstawowy. Dodaj jeden, jeśli jeszcze go nie masz. Proponuję serial
lub IDENTITY
kolumnę w Postgres 10+.
Powiązane:
Jak to jest szybciej?Subquery w EXISTS
(anty-)Semi-join mogą przestać Oceniać, gdy tylko znajdzie się pierwszy dupe (nie ma sensu szukać dalej). W przypadku tabeli bazowej z kilkoma duplikatami jest to tylko nieznacznie bardziej wydajne. Z dużą ilością duplikatów staje się to sposób bardziej efektywny.
Wyklucz puste aktualizacje
Jeśli niektóre lub wiele wierszy ma już status = 'ACTIVE'
, twoja aktualizacja niczego nie zmieni, ale nadal wstawia nową wersję wiersza za pełnym kosztem (obowiązują drobne wyjątki). Normalnie tego nie chcesz. Dodaj kolejnyWHERE
warunek, jak pokazano powyżej, aby to jeszcze szybciej:
Jeśli status
jest zdefiniowane NOT NULL
, można uprościć do:
AND status <> 'ACTIVE';
Subtelna różnica w obsłudze NULL
To zapytanie (w przeciwieństwie do obecnie akceptowana odpowiedź przez Joela ) nie traktuje wartości NULL jako równych. Te dwa rzędy dla (saleprice, saledate)
kwalifikowałyby się jako " odrębne "(choć wyglądające identycznie jak ludzkie oko): {]}
(123, NULL)
(123, NULL)
Również przechodzi w unikalnym indeksie i prawie wszędzie indziej, ponieważ wartości NULL nie są równe zgodnie ze standardem SQL. Zobacz:
Otoh, GROUP BY
lub DISTINCT
lub DISTINCT ON ()
traktują wartości NULL jako równe. Użycie odpowiedni styl zapytań w zależności od tego, co chcesz osiągnąć. Możesz nadal używać tego szybszego stylu zapytań za pomocą IS NOT DISTINCT FROM
zamiast =
dla dowolnych lub wszystkich porównań, aby null było równe. Więcej:
Jeśli wszystkie porównywane kolumny są zdefiniowane NOT NULL
, nie ma miejsca na nieporozumienia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-13 12:24:49
Problem z zapytaniem polega na tym, że gdy używasz klauzuli GROUP BY (co zasadniczo robisz, używając distinct), możesz używać tylko kolumn, które grupujesz lub agregujesz funkcje. Nie można użyć identyfikatora kolumny, ponieważ istnieją potencjalnie różne wartości. W Twoim przypadku zawsze jest tylko jedna wartość ze względu na klauzulę HAVING, ale większość RDBM nie jest wystarczająco inteligentna, aby to rozpoznać.
To powinno jednak działać (i nie wymaga połączenia):
UPDATE sales
SET status='ACTIVE'
WHERE id IN (
SELECT MIN(id) FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(id) = 1
)
Możesz też użyć Maxa lub AVG zamiast MIN, ważne jest tylko użycie funkcji, która zwraca wartość kolumny, jeśli jest tylko jeden pasujący wiersz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-10 16:17:13
Chcę wybrać różne wartości z jednej kolumny 'GrondOfLucht', ale powinny być sortowane w kolejności podanej w kolumnie 'sortowanie'. Nie mogę uzyskać odrębnych wartości tylko jednej kolumny używając
Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering
Da również kolumnę "sortowanie", a ponieważ "GrondOfLucht" i "sortowanie" nie są unikalne, wynikiem będą wszystkie wiersze.
Użyj grupy, aby wybrać rekordy 'GrondOfLucht' w kolejności podanej przez ' sorting
SELECT GrondOfLucht
FROM dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-13 10:41:47