Come faccio (o posso) SELECT DISTINCT su più colonne?
-
09-06-2019 - |
Domanda
Ho bisogno di recuperare tutte le righe da una tabella di 2 colonne combinato sono tutti diversi.Quindi voglio che tutte le vendite che non hanno altro di vendite che è avvenuto nello stesso giorno per lo stesso prezzo.Le vendite che sono uniche in base al giorno e il prezzo sarà aggiornata per uno stato attivo.
Così sto pensando che:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Ma il mio cervello fa male andare più in là di questo.
Soluzione
SELECT DISTINCT a,b,c FROM t
è circa equivalente a:
SELECT a,b,c FROM t GROUP BY a,b,c
E ' una buona idea per ottenere utilizzato per il GRUPPO di sintassi, come è più potente.
Per la query, mi piacerebbe farlo come questo:
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
)
Altri suggerimenti
Se si mettono insieme le risposte finora, di pulizia e di migliorare, si dovrebbe arrivare a questo superiore query:
UPDATE sales
SET status = 'ACTIVE'
WHERE (saleprice, saledate) IN (
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING count(*) = 1
);
Che è molto più veloce di uno di loro.Le armi nucleari le prestazioni attualmente accettato di rispondere con un fattore di 10 - 15 (i miei test su PostgreSQL 8.4 e 9.1).
Ma questo è ancora lontana dall'essere ottimale.Utilizzare un NOT EXISTS
(anti-)semi-join per prestazioni ancora migliori. EXISTS
è standard SQL, è stato intorno per sempre (almeno dal PostgreSQL 7.2, molto prima di questa domanda) e si adatta presentato perfettamente ai requisiti di:
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<>violino qui
Vecchio SQL Violino
Unica chiave per identificare la riga
Se non si dispone di una chiave primaria o univoca per la tabella (id
nell'esempio), si può sostituire con la colonna di sistema ctid
lo scopo di questa query (ma non per altri scopi):
AND s1.ctid <> s.ctid
Ogni tabella deve avere una chiave primaria.Aggiungere uno se non avete uno, di sicurezza.Suggerisco un serial
o un IDENTITY
colonna in Postgres 10+.
Related:
Come è il più veloce?
La subquery nella EXISTS
anti-semi-join è possibile arrestare la valutazione non appena il primo ingannare trovato nessun punto in cerca di più).Per una tabella di base con alcuni duplicati questa è solo leggermente più efficiente.Con un sacco di duplicati questo diventa modo più efficiente.
Escludere vuoto aggiornamenti
Per le righe che già hanno status = 'ACTIVE'
questo aggiornamento non sarebbe cambiato nulla, ma comunque inserire una nuova riga versione a costo pieno (minori, salvo eccezioni).Normalmente, non si vuole questo.Aggiungere un altro WHERE
condizione come dimostrato sopra per evitare questo e per rendere ancora più veloce:
Se status
è definito NOT NULL
, si può semplificare a:
AND status <> 'ACTIVE';
Sottile differenza nella gestione dei valori NULL
Questa query (a differenza di attualmente accettato risposta da Joel) non considerare i valori NULL uguali.Le seguenti due righe per (saleprice, saledate)
potrebbe qualificarsi come "distinti" (anche se cercando identico all'occhio umano):
(123, NULL)
(123, NULL)
Passa anche in un indice univoco e quasi qualsiasi altro luogo, poiché i valori NULL non uguali, secondo lo standard SQL.Vedere:
OTOH, GROUP BY
, DISTINCT
o DISTINCT ON ()
il trattamento di valori NULL uguali.Utilizzare una query appropriata stile a seconda di ciò che si desidera raggiungere.È ancora possibile utilizzare questa query, più rapido con IS NOT DISTINCT FROM
invece di =
per qualsiasi o tutti i confronti a fare nulla uguali.Di più:
Se tutte le colonne sono confrontati definito NOT NULL
, non c'è spazio per il dissenso.
Il problema con la query è che quando si utilizza una clausola GROUP BY (che è essenzialmente tramite la distinta) è possibile utilizzare solo le colonne di gruppo o funzioni di aggregazione.Non è possibile utilizzare la colonna id, perché ci sono potenzialmente valori diversi.Nel tuo caso c'è sempre un solo valore a causa della clausola HAVING, ma la maggior parte RDBMS non sono abbastanza intelligente da riconoscere che.
Questo dovrebbe funzionare, tuttavia, (e non ha bisogno di un join):
UPDATE sales
SET status='ACTIVE'
WHERE id IN (
SELECT MIN(id) FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(id) = 1
)
Si potrebbe anche usare MAX o AVG invece di MIN, è importante usare una funzione che restituisce il valore della colonna, se c'è solo una riga corrispondente.
Voglio selezionare i valori distinti da una colonna 'GrondOfLucht', ma devono essere ordinati in ordine come indicato nella colonna "sortering'.Non riesco a diversi valori di una colonna, utilizzando
Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering
Si darà anche la colonna 'sortering" e perché "GrondOfLucht' E 'sortering' non è univoco, il risultato sarà di TUTTE le righe.
utilizzare il GRUPPO per selezionare i record di 'GrondOfLucht', nell'ordine, da 'sortering
SELECT GrondOfLucht
FROM dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
Se il DBMS non supporta distinti con più colonne come questo:
select distinct(col1, col2) from table
Multi selezionare, in generale, può essere eseguita in modo sicuro come segue:
select distinct * from (select col1, col2 from table ) as x
Come questo può funzionare sulla maggior parte dei DBMS e questo dovrebbe essere più veloce di un gruppo da una soluzione come si sta evitando la funzionalità di raggruppamento.