2009-06-24 14 views
4

Ich habe zwei Tabellen, zum Beispiel:SQL - Prüfe Tabelle für neue Zeilen?

Table A         Table B 
=======         ======= 

Name   | Color      Name   | Color 
----------------------     ---------------------- 
Mickey Mouse | red      Mickey Mouse | red 
Donald Duck | green      Donald Duck | blue 
Donald Duck | blue      Minnie  | red 
Goofy  | black 
Minnie  | red 

Tabelle A ist meine Quelltabelle und B ist die Zieltabelle. Jetzt brauche ich eine Abfrage, die alle verschiedenen (zusätzlichen) Zeilen in Tabelle A findet, so dass Tabelle B mit diesen Zeilen aktualisiert werden kann. Also brauche ich eine Abfrage, die mir die folgenden Zeilen aus Tabelle A findet:

Name   | Color 
---------------------- 
Donald Duck | green 
Goofy  | black 

Was ist ein guter Ansatz für eine solche Abfrage? Es sollte so effizient wie möglich sein (vermeiden Sie zu viele Joins). Danke für jede Hilfe!

+2

Ist das Hausaufgaben? –

+0

Was DB-Engine ist das und was machst du mit den Unterschieden? Zum Beispiel, wenn Sie die Daten irgendwie replizieren wollen, gibt es oft bessere Ansätze, abhängig vom verwendeten Modul. –

+0

Dies war ein vereinfachtes Beispiel aus einem realen Problem, bei dem die Tabellen A und B offensichtlich nicht so einfach sind. Insbesondere Tabelle B enthält nicht die exakten Spalten 1: 1 wie Tabelle A. – blackicecube

Antwort

9

Ich würde eine Struktur NOT EXISTS verwenden.

SELECT Name, Color 
FROM TableA 
WHERE NOT EXISTS (
SELECT 1 FROM TableB 
WHERE TableA.Name = TableB.Name 
AND TableA.Color = TableB.Color) 
+2

NOT EXISTS verwendet eine korrelierte Unterabfrage, so dass sie bei größeren Datensätzen wesentlich schneller ist als "NOT IN". –

+0

+1 für die Lesbarkeit über Justins Antwort; Allerdings ist Justins wahrscheinlich schneller und IMHO besser. –

+0

Vielen Dank! Genau das habe ich gebraucht! –

1

A NOT EXISTS Unterabfrage zu einem äußeren lösen sollte beitreten:

SELECT Name, Color 
FROM TableA 
WHERE NOT EXISTS (
    SELECT 1 
    FROM TableB 
    WHERE TableA.Color = TableB.Color 
    AND TableA.Name = TableB.Name 
) 

Oder Sie könnten nur eine äußere Verknüpfung verwenden, um direkt:

SELECT TableA.Name, TableA.Color 
FROM TableA 
LEFT OUTER JOIN TableB 
    ON TableA.Name = TableB.Name 
    AND TableA.Color = TableB.Color 
WHERE TableB.Name IS NULL 

Sie sollten ebenso performant sein; Es ist eine Frage, von der Sie glauben, dass sie intuitiver ist.

3
Select A.Name, A.Color 
From A left join B on A.Name = B.Name and A.Color = B.Color 
Where B.Name is null 
2

In SQL Server 2008 können Sie den EXCEPT Operator verwenden, die wie ein UNION verwendet wird, aber alles von der ersten Abfrage zurückgibt, es sei denn, es ist auch in der zweiten:

SELECT * FROM TABLEA EXCEPT SELECT * FROM TABLEB 

I verstehen, dass Oracle einen MINUS Operator hat, der das Gleiche tut.

7
SELECT a.Name, a.Color 
FROM a LEFT OUTER JOIN b ON (a.Name = b.Name AND a.Color = b.Color) 
WHERE b.Name IS NULL AND b.Color IS NULL 
+0

Warum testen, ob Name und Farbe NULL sind? Sicherlich ist das Testen für den einen oder anderen ausreichend. –

2

Sie können den Operator EXCEPT verwenden, der das Gegenteil von UNION ist. In Oracle ist das Äquivalent MINUS.

SELECT * FROM TABLE_A 
EXCEPT 
SELECT * FROM TABLE_B 
0

SELECT TableA.Name, TableA.Color FROM TableA WHERE TableA.Name + TableA.Color NOT IN (SELECT TableB.Name + TableB.Color FROM TableB)

0
INSERT INTO B 
SELECT a.Name, a.Color 
FROM A a 
LEFT JOIN B b ON a.Name = b.Name AND a.Color = b.Color 
WHERE b.Color IS NULL AND b.Name IS NULL 
2

I in der Regel eine Spalte "aktualisiert TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" addiert, und ich verwende den Wert zu überprüfen, wenn eine neue Zeile eingefügt wird oder ein bestehendes ist geändert.

In einer Anwendung, die ich entwickelt habe, musste ich ein ähnliches Problem wie Ihres lösen, also speicherte ich irgendwo den MAX (aktualisiert) von B, und dann identifizierte ich mit einer Abfrage alle Zeilen, in denen A.updated> B.updated, und das Ergebnis sind alle neuen + modifizierten Zeilen.

Da der Standardwert des Felds CURRENT_TIMESTAMP lautet und automatisch "ON UPDATE" aktualisiert wird, muss der Wert nie explizit festgelegt werden.

1

Es gibt viele richtige Antworten auf bereits, aber ich möchte einen philosophischen Punkt bringen:

Ist das Datenbankschema wirklich lebensfähig in einer Produktionsumgebung in einem einzigen Schema?

Macht es wirklich Sinn, zwei Tabellen mit Daten zu haben und dann eine Abfrage zu schreiben, um sie miteinander zu vergleichen? Ich denke, es wäre sinnvoll, nur eine einzige Tabelle zu haben und vielleicht einen Datumsidentifikator anzulegen, um Datensätze zu finden, die nach einem bestimmten Punkt hinzugefügt wurden.

Die einzige Situation, an die ich denken kann, wo Sie dies tun möchten, ist, wo Sie zwei getrennte Datenbanken haben und Sie "synchronisieren" wollen, oder wenn Sie Unterschiede zwischen den beiden, sagen wir, vergleichen möchten eine Sicherung und Produktion.

1

In Oracle würden Sie wahrscheinlich verwenden:

MERGE INTO b USING 
    (SELECT name, color 
    FROM a) src 
ON (src.name = b.name AND color = src.color) 
WHEN NOT MATCHED THEN 
    INSERT (name, color) 
    VALUES (src.name, src.color); 

Wenn die Tabelle einen Primärschlüssel hat (haben Sie wirklich Tabellen ohne eine?) Wie Name, und Sie möchten auf die Existenz INSERT oder UPDATE abhängig des Datensatzes in Tabelle B würden Sie verwenden:

MERGE INTO b USING 
    (SELECT name, color 
    FROM a) src 
    ON (src.name = b.name) 
    WHEN NOT MATCHED THEN 
    INSERT (name, color) 
    VALUES (src.name, src.color) 
    WHEN MATCHED THEN 
    UPDATE 
    SET color = src.color; 

Ich nehme an, dass SQL Server auch eine MERGE-Anweisung oder ähnliches hat.