2010-08-17 16 views
17

Ich habe Zeilen in einer Oracle-Datenbanktabelle, die für eine Kombination aus zwei Feldern eindeutig sein sollte, aber die eindeutige Einschränkung ist nicht in der Tabelle eingerichtet, so dass ich alle Zeilen finden muss, die die Einschränkung selbst mit SQL verletzen. Leider sind meine mageren SQL-Kenntnisse nicht für die Aufgabe geeignet.SQL: Wie finde ich Dubletten basierend auf zwei Feldern?

Meine Tabelle hat drei Spalten, die relevant sind: entity_id, station_id und obs_year. Für jede Zeile sollte die Kombination von stations_id und obs_year eindeutig sein, und ich möchte herausfinden, ob es Zeilen gibt, die dies verletzen, indem sie sie mit einer SQL-Abfrage ausspülen.

Ich habe die folgende SQL (vorgeschlagen von this previous question) versucht, aber es funktioniert nicht für mich arbeiten (ich ORA-00918 Spalte zweideutig definiert):

SELECT 
entity_id, station_id, obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

Kann jemand vorschlagen, was ich falsch mache und/oder wie löst man das?

Antwort

33
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 
+0

Vielen Dank für diese Antwort. Leider bekomme ich beim Aufruf eine "ORA-00923: FROM Schlüsselwort nicht gefunden wo erwartet" Nachricht. –

+0

@James: versuchen Sie es jetzt – Quassnoi

+0

In mssql in musste ein 'wie x' setzen (Name ist nicht wirklich wichtig) hinter der FROM() - Paranthesis, damit es funktioniert. Gute Antwort! – Mafii

2

Re-write der Anfrage

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

Ich denke, die mehrdeutige Spalte Fehler (ORA-00918) war, weil Sie select waren ing Spalten, deren Namen in den beiden erschien der Tabelle und der Unterabfrage, aber du hast nicht Spezifizieren, wenn Sie es von dupes oder von mytable (aliased als t1) wollten.

1

Konnten Sie keine neue Tabelle erstellen, die die eindeutige Einschränkung enthält, und dann Zeile für Zeile über die Daten kopieren und dabei Fehler ignorieren?

+0

Ja, das ist eine gute Idee, danke! BTW Ich versuche herauszufinden, wie die Einschränkung für meine Tabelle mithilfe von Anmerkungen in meiner Entitätsklasse erstellt werden kann (ich bin ein Java-Entwickler mit JPA/Hibernate), siehe http://StackOverflow.com/Questions/3504477/ how-to-specify-that-a-combination-of-columns-sollte-ein-unique-constraint-using –

2

Ändern Sie die drei Felder in der Anfangs wählen

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
10
SELECT entity_id, station_id, obs_year 
FROM mytable t1 
WHERE EXISTS (SELECT 1 from mytable t2 Where 
     t1.station_id = t2.station_id 
     AND t1.obs_year = t2.obs_year 
     AND t1.RowId <> t2.RowId) 
+0

Sieht so aus, als könnten wir dies nicht in einer Ansicht machen: ORA-01445: ROWID kann nicht ausgewählt werden, oder Beispiel einer Join-Ansicht ohne Schlüssel-beibehaltene Tabelle – Thyag

1

Sie die Tabelle in der Haupt wählen Sie für die Spalten angeben müssen sein. Wenn Sie außerdem annehmen, dass entity_id der eindeutige Schlüssel für mytable ist und für das Auffinden von Duplikaten irrelevant ist, sollten Sie in der Duplikat-Unterabfrage nicht darauf gruppieren.

Versuchen:

SELECT t1.entity_id, t1.station_id, t1.obs_year 
FROM mytable t1 
INNER JOIN (
SELECT station_id, obs_year FROM mytable 
GROUP BY station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 
+0

Danke, Mark, für den Tipp über die Verwendung von entity_id in der Gruppierungs-Unterabfrage und für das illustrative Beispiel. –

0
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 

von Quassnoi ist die effizienteste für große Tabellen. Ich hatte diese Analyse der Kosten:

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
WHERE EXISTS (SELECT 1 from trn_refil_book b Where 
     a.dist_code = b.dist_code and a.book_date = b.book_date and a.book_no = b.book_no 
     AND a.RowId <> b.RowId) 
     ; 

gab Kosten in Höhe von 1322341

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
INNER JOIN (
SELECT b.dist_code, b.book_date, b.book_no FROM trn_refil_book b 
GROUP BY b.dist_code, b.book_date, b.book_no HAVING COUNT(*) > 1) c 
ON 
a.dist_code = c.dist_code and a.book_date = c.book_date and a.book_no = c.book_no 
; 

gab Kosten in Höhe von 1271699

während

SELECT dist_code, book_date, book_no 
FROM (
     SELECT t.dist_code, t.book_date, t.book_no, ROW_NUMBER() OVER (PARTITION BY t.book_date, t.book_no 
      ORDER BY t.dist_code) AS rn 
     FROM trn_refil_book t 
     ) p 
WHERE p.rn > 1 
; 

gab eine Gebühr von

Die Tabelle nicht indiziert wurde ....

+0

Formatieren Sie Ihre Antwort richtig. – SSP

0
SELECT entity_id, station_id, obs_year 
    FROM mytable 
GROUP BY entity_id, station_id, obs_year 
HAVING COUNT(*) > 1 

die Felder angeben Duplikate sowohl auf der SELECT und der GROUP BY zu finden.

Mithilfe von GROUP BY können Sie nach Zeilen suchen, die auf der Grundlage der angegebenen Spalten mit anderen Zeilen übereinstimmen. Die HAVING COUNT(*) > 1 sagt, dass wir nur daran interessiert sind, irgendwelche Zeilen zu sehen, die mehr als einmal vorkommen (und sind daher Duplikate)

+0

Hiya, das könnte das Problem lösen ... aber es wäre gut, wenn Sie eine kleine Erklärung geben könnten, wie und warum es funktioniert :) Vergessen Sie nicht - es gibt Haufen von Neulingen auf Stack Overflow, und sie könnten Lernen Sie ein oder zwei Dinge von Ihrem Fachwissen - was für Sie offensichtlich ist, ist ihnen vielleicht nicht so. –

+0

Danke Taryn. Es funktioniert mit GROUP BY, um alle Zeilen zu finden, die mit anderen Zeilen auf der Basis der angegebenen Spalten übereinstimmen. Das HAVING COUNT (*)> 1 sagt, dass wir nur daran interessiert sind, Zeilen zu sehen, die mehr als einmal vorkommen (und daher Duplikate sind) – grokster

+0

Hallo, erzähl mir nicht (in den Kommentaren). Ich kenne SQL, ich frage nicht nach mir ... Diese Art von Erklärung ist "Teil Ihrer vollständigen Antwort" ... also editieren Sie bitte Ihre Antwort und fügen Sie sie dort hinzu. :) –

Verwandte Themen