So wählen Sie eindeutige Datensätze per SQL aus

86

Wenn ich "SELECT * FROM table" durchführe, erhalte ich folgende Ergebnisse:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

Wie Sie sehen können, gibt es Dup-Datensätze aus Spalte2 (Element1 wird gelöscht). Wie könnte ich also ein solches Ergebnis erzielen:

1 item1 data1
2 item2 data3
3 item3 data4

Vom Duplikat wird nur ein Datensatz zusammen mit den übrigen eindeutigen Datensätzen zurückgegeben.

Yinan
quelle

Antworten:

102

Mit dem distinctSchlüsselwort mit einzelnen und mehreren Spaltennamen erhalten Sie unterschiedliche Datensätze:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;
mjallday
quelle
14
Kann es sein, dass die Antwort tatsächlich falsch ist? DISTINCT wird auf alle ausgewählten Spalten angewendet (zumindest in einem DB2), die weiterhin doppelte Werte in einzelnen Spalten zurückgeben.
Konstantin
23

Wenn Sie nur Duplikate entfernen müssen, verwenden Sie DISTINCT. GROUP BYsollte verwendet werden, um Aggregatoperatoren auf jede Gruppe anzuwenden

GROUP BY v DISTINCT

rahul
quelle
10

Es hängt davon ab, welche Rown Sie für jeden einzelnen Artikel zurückgeben möchten. Ihre Daten scheinen den minimalen Datenwert anzugeben, also in diesem Fall für SQL Server.

SELECT item, min(data)
FROM  table
GROUP BY item
Dave Barker
quelle
9

Es gibt 4 Methoden, die Sie verwenden können:

  1. UNTERSCHEIDLICH
  2. GRUPPIERE NACH
  3. Unterabfrage
  4. Common Table Expression (CTE) mit ROW_NUMBER ()

Betrachten Sie das folgende Beispiel TABLEmit Testdaten:

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
      ,('bbb', 200, 2)
      ,('ccc', 300, 3)
      ,('bbb', 400, 4)
      ,('bbb', 200, 5)     -- duplicate
      ,('ccc', 300, 6)     -- duplicate
      ,('ddd', 400, 7)
      ,('bbb', 400, 8)     -- duplicate
      ,('aaa', 100, 9)     -- duplicate
      ,('ccc', 300, 10);   -- duplicate

Option 1: SELECT DISTINCT

Dies ist der einfachste und direkteste, aber auch der begrenzteste Weg:

SELECT DISTINCT word, num 
FROM    dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

Option 2: GRUPPE NACH

Gruppierung können Sie aggregierte Daten schreiben, die min(id), max(id), count(*), etc:

SELECT  word, num, min(id), max(id), count(*)
FROM    dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

Option 3: Unterabfrage

Mithilfe einer Unterabfrage können Sie zuerst die zu ignorierenden doppelten Zeilen identifizieren und sie dann in der äußeren Abfrage mit dem WHERE NOT IN (subquery)Konstrukt herausfiltern :

/** Find the higher id values of duplicates, distinct only added for clarity */
    SELECT  distinct d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT  *
FROM    dupes
WHERE   id NOT IN (
    SELECT  d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

Option 4: Allgemeiner Tabellenausdruck mit ROW_NUMBER ()

Wählen Sie im Common Table Expression (CTE) die Option ROW_NUMBER () aus, die nach Gruppenspalten unterteilt und in der gewünschten Reihenfolge sortiert ist. Wählen Sie dann nur die Datensätze aus, die Folgendes haben ROW_NUMBER() = 1:

WITH CTE AS (
    SELECT  *
           ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
    FROM    dupes
)
SELECT  word, num, id 
FROM    cte
WHERE   row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/
Isapir
quelle
5

Verwenden Sie einfach den inneren Join, da das Gruppieren nach nicht mit mehreren Spalten funktioniert, die besagen, dass sie in keiner der Aggregatfunktionen enthalten sind.

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;
Ankit Kashyap
quelle
Das ist die Antwort auf eine andere Frage, wahrscheinlich eine, die mit dem größten n pro Gruppe gekennzeichnet werden sollte
a_horse_with_no_name
Dies und die Lösung von Dave Baker sind die richtigen Lösungen für die SO-Frage. Der Vorteil dieser Lösung besteht darin, dass Zeilen mit nur bestimmten angegebenen Spalten ausgewählt werden können und eine Spalte MIN (id) AS-ID definiert werden muss, um nur eine der mehreren angegebenen Spalten auszuwählen.
Giordano
1

Ich finde, wenn ich DISTINCT aus irgendeinem Grund nicht verwenden kann, funktioniert GROUP BY.

John Hamelink
quelle
1

Um alle Spalten in Ihrem Ergebnis zu erhalten, müssen Sie Folgendes platzieren:

SELECT distinct a, Table.* FROM Table

Es wird a als erste Spalte platziert und der Rest besteht aus ALLEN Spalten in derselben Reihenfolge wie Ihre Definition. Dies ist, Spalte a wird wiederholt.

htafoya
quelle
1
Bist du dir da sicher? Ich habe dies auf w3schools versucht und es gab das gleiche wie SELECT * zurück, außer dass a die erste Spalte war
Freakishly
@Freakishly ja und das ist genau das, was es in meiner Antwort sagt: /
htafoya
Dies wird nicht funktionieren, Sie können nicht * nach dem Unterschied so auswählen (Sie erhalten einen 1064-Fehler - Fehler in Ihrer SQL-Syntax)
tim.baker
@Mohsinkhan Nun, ich habe vergessen zu platzieren, dass Sie den Tabellennamen schreiben müssen. Irgendwie hat es funktioniert, als ich das geschrieben habe, aber ich habe es gerade getestet und es war nicht ohne den Tabellennamen vor dem *
htafoya
1
Dies ist genau das gleiche wieselect distinct * from ...
a_horse_with_no_name
-4

Wählen Sie Eff_st aus (wählen Sie EFF_ST, ROW_NUMBER () über (PARTITION BY eff_st) XYZ - aus ABC.CODE_DIM

) wobei XYZ = 1 Auftrag von EFF_ST nur die ersten 5 Zeilen abruft

Shailendra Singhai
quelle