Frage

Ich muss alle Zeilen aus einer Tabelle abrufen, in der zwei Spalten zusammengenommen alle unterschiedlich sind.Ich möchte also alle Verkäufe, für die es keine anderen Verkäufe gibt, die am selben Tag zum gleichen Preis stattgefunden haben.Die auf der Grundlage von Tag und Preis eindeutigen Verkäufe werden auf einen aktiven Status aktualisiert.

Also ich denke:

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

Aber mein Gehirn schmerzt, wenn ich darüber hinausgehe.

War es hilfreich?

Lösung

SELECT DISTINCT a,b,c FROM t

ist ungefähr entspricht:

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

Es ist eine gute Idee, um sich an den GROUP BY-Syntax verwendet, da es leistungsstärker ist.

Für Ihre Abfrage, ich es so tun würde:

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
 )

Andere Tipps

Wenn Sie die Antworten zusammen so weit, aufzuräumen und zu verbessern, Sie bei dieser überlegenen Abfrage ankommen würde:

UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );

Welche ist viel schneller als jeder von ihnen. Nukes die Leistung der derzeit akzeptierte Antwort um den Faktor 10 bis 15 (in meinen Tests auf PostgreSQL 8.4 und 9.1)

.

Das ist aber bei weitem noch nicht optimal. Verwenden Sie ein NOT EXISTS (Anti-) Semi-Join für eine noch bessere Leistung. EXISTS ist Standard-SQL, gibt es schon immer (zumindest seit PostgreSQL 7.2, lange bevor diese Frage wurde gebeten) und passt die dargestellten Anforderungen perfekt:

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 <> Geige hier
Old SQL Fiddle

Eindeutiger Schlüssel zu identifizieren Zeile

Wenn Sie nicht mit einer primären oder eindeutigen Schlüssel für die Tabelle (id im Beispiel) haben, können Sie mit der Systemspalte ctid für die Zwecke dieser Abfrage ersetzen (aber nicht für einige andere Zwecke):

   AND    s1.ctid <> s.ctid

Jede Tabelle sollte einen Primärschlüssel haben. Fügen Sie ein, wenn Sie keine hat, noch nicht. Ich schlage vor, eine serial oder eine IDENTITY Spalte in Postgres 10 +.

Siehe auch:

Wie ist das schneller?

Die Unterabfrage in dem EXISTS anti-semi beitreten kann, sobald die erste Betrogene gefunden ist (keinen Punkt in der Suche weiter) stoppen zu bewerten. Für eine Basistabelle mit wenigen Duplikaten ist dies nur leicht effizienter. Mit vielen Duplikaten dieser wird Weg effizienter zu gestalten.

ausschließen leer Updates

Für Zeilen, die bereits dieses Update status = 'ACTIVE' haben würde nichts ändern, aber immer noch eine neue Zeile Version zu Vollkosten einfügen (kleinere Ausnahmen gelten). Normalerweise Sie dies nicht wollen. Ein weiteren hinzufügen WHERE Zustand wie gezeigt oben, dies zu vermeiden und macht es noch schneller:

Wenn status NOT NULL definiert ist, können Sie vereinfachen zu:

AND status <> 'ACTIVE';

Subtle Unterschied in NULL Handhabung

Diese Abfrage (im Gegensatz zu dem zur Zeit Antwort von Joel akzeptiert) behandelt nicht NULL-Wert als gleich. Die folgenden zwei Zeilen für (saleprice, saledate) würden qualifizieren als „distinct“ (obwohl die Suche identisch mit dem menschlichen Auge):

(123, NULL)
(123, NULL)

geht auch in einem eindeutigen Index und fast überall sonst, da NULL-Werte entsprechend den SQL-Standard nicht gleich vergleichen. Siehe auch:

OTOH, GROUP BY, DISTINCT oder DISTINCT ON () behandeln NULL-Werte als gleich. Verwenden Sie eine entsprechende Abfrage Stil je nachdem, was Sie erreichen wollen. Sie können immer noch diese schnellere Abfrage mit IS NOT DISTINCT FROM statt = für einige oder alle vergleiche machen gleich NULL vergleichen. Mehr:

Wenn alle Spaltenverglichenen NOT NULL definiert sind, gibt es keinen Raum für Meinungsverschiedenheiten.

Das Problem mit Ihrer Anfrage ist, dass, wenn ein GROUP BY-Klausel (die Sie im Wesentlichen durch die Verwendung verschieden tun) Sie nur Spalten verwenden können, die Sie Gruppe durch oder Aggregatfunktionen. Sie können die Spalte-ID verwenden, da es möglicherweise unterschiedliche Werte sind. In Ihrem Fall ist es immer nur ein Wert wegen der HAVING-Klausel, aber die meisten RDBMS sind nicht intelligent genug, um zu erkennen, dass.

Dies soll jedoch arbeiten (und nicht einen Join müssen):

UPDATE sales
SET status='ACTIVE'
WHERE id IN (
  SELECT MIN(id) FROM sales
  GROUP BY saleprice, saledate
  HAVING COUNT(id) = 1
)

Sie können auch anstelle von MIN verwenden MAX oder AVG, ist es nur wichtig ist, eine Funktion zu verwenden, die den Wert der Spalte zurückgibt, wenn es nur eine passende Zeile ist.

Ich mag die unterschiedlichen Werte von einer Spalte ‚GrondOfLucht‘ wählen, aber sie sollten in der Reihenfolge sortiert werden, wie in der Spalte gegeben ‚sortering‘. Ich kann nicht die unterschiedlichen Werte von nur einer Spalte erhalten mit

Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering

Es wird auch die Spalte ‚sortering‘ geben und weil ‚GrondOfLucht‘ UND ‚Sortering‘ ist nicht eindeutig, wird das Ergebnis alle Zeilen.

Bei der Gruppe verwenden, um die Aufzeichnungen von ‚GrondOfLucht‘ in der Reihenfolge von ‚sortering

gegeben wählen
SELECT        GrondOfLucht
FROM            dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)

Wenn Ihr DBMS nicht eindeutige Unterstützung mit mehreren Spalten wie folgt aus:

select distinct(col1, col2) from table

Multi wählen Sie im Allgemeinen sicher wie folgt ausgeführt werden:

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

Da es sich bei den meisten der DBMS arbeiten können und dies wird voraussichtlich schneller als Gruppe von Lösung, wie Sie die Gruppierung Funktionalität zu vermeiden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top