2016-04-06 14 views
0

Ich habe ein System Integrationsprojekt, CRUD von einem DB zu einem anderen benötigt. Nicht besonders kompliziert. Wenn es jedoch darum geht, Zeilen zu löschen, die im Ziel vorhanden sind, aber nicht in der Quelle, stieß ich auf ein kleines Problem. Zu den Standardmustern gehören: LINKE VERBINDUNG, NICHT VORHANDEN oder NICHT IN. Ich wählte die LINKE VERBINDUNG. Meine 'Telefon'-Tabelle verwendet einen zusammengesetzten Schlüssel, Mitarbeiter-ID' und den PhoneType: Arbeit, Privat, Mobil usw. Der Standard-Link-Join löscht JEDE Ziel-Telefonnummer, die NICHT in der Quelle enthalten ist. Dies löscht die gesamte Tabelle. HINWEIS: Ich aktualisiere nur Datensätze, die seit der letzten Aktualisierung geändert wurden, NICHT das gesamte Ziel & Quelle. Also schrieb ich ein Update, das ich wirklich schlecht SQL vermuten:SQL Löschen, wo nicht mit zusammengesetzten Schlüssel

-- SOURCE 
DECLARE @tmpPhones TABLE(Id varchar(8), PhoneType int, PhoneNumber varchar(30), PRIMARY KEY (Id, PhoneType)) 
INSERT into @tmpPhones values 
('TEST123', 1, '12345678'), 
('TEST123', 2, '12345678'), 
('TEST123', 3, '12345678') 

-- TARGET 
[email protected] TABLE(Id varchar(8), PhoneType int, PhoneNumber varchar(30), PRIMARY KEY (Id, PhoneType)) 
INSERT into @Phone values 
('TEST123', 1, '12345678'), <-- Exists in both, leave 
('TEST123', 2, '12345678'), <-- Exists in both, leave 
('TEST123', 3, '12345678'), <-- Exists in both, leave 
('TEST123', 4, '12345678'), <-- ONLY delete this one! 
('TEST456', 2, '12345678'), <-- Ignore this employee Id 
('TEST456', 3, '12345678'),  "" 
('TEST456', 4, '12345678')  "" 

DELETE p 
FROM @Phone p 
    LEFT JOIN @tmpPhones t 
    ON t.Id = p.Id AND t.PhoneType = p.PhoneType 
WHERE t.Id IS NULL AND t.PhoneType IS NULL 
    AND p.Id IN (SELECT Id FROM @tmpPhones) <-- a sad hack? 

Dies funktioniert, aber ich fühle mich wie es eine bessere Art und Weise ist sicherzustellen, dass wir nur Datensätze für diese Mitarbeiter zu löschen, die nicht alle der andere.

Irgendwelche Vorschläge?

+0

ist dieser SQL Server? – Nikki9696

+0

Ja, SQL Server 2012. –

+0

LINKER JOIN ist hier völlig falsch – wildplasser

Antwort

2

Verwenden Sie exists.

DELETE p 
FROM @Phone p 
where exists (select 1 from @tmpPhones where Id = p.Id) 
AND not exists (select 1 from @tmpPhones where PhoneType = p.PhoneType) 

Bearbeiten: Löschen mit cte.

with todelete as (
    select id,phonetype from phone 
    except 
    select id,phonetype from tmpphones t 
    where exists (select 1 from phone where id = t.id) 
    ) 
delete from phone 
where exists (select 1 from todelete where phone.id = id and phone.phonetype = phonetype) 
+0

Dies lief nicht im Beispielcode? Würde das nicht alle anderen Telefonnummern der Angestellten löschen? Das Überprüfen mit einer Auswahl gibt diejenigen zurück, die wir nicht löschen wollen mit ID = TEST456 (Ihre Bearbeitung wird nicht funktionieren, wenn mehr als eine Mitarbeiter-ID in der Menge ist) – Nikki9696

+0

Die erste funktionierte perfekt aus der Box meiner Probe heraus Daten. Keine Ahnung ob es schneller ist als mein Hack, aber es sieht echt echt aus. Danke vielmals! –

0

merge scheint ok zu arbeiten - aber Sie müssen noch, wenn die ID in Ihrer Referenzsatz zu sehen ist, sehe ich nicht eine saubere Art und Weise um diese

MERGE @Phone AS TGT 
USING (
SELECT * FROM @tmpPhones 
) AS SRC 
ON TGT.ID=SRC.ID AND TGT.PHONETYPE=SRC.PHONETYPE 
WHEN NOT MATCHED BY SOURCE AND tgt.id IN (SELECT id FROM @tmpPhones) THEN DELETE; 
1

denke ich, zwei Aussagen existiert Ziemlich viele erfassen die Logik: wie Sie es beschreiben

DELETE p 
FROM @Phone p 
WHERE EXISTS (SELECT 1 FROM @tmpPhone t WHERE t.id = p.id) AND 
     NOT EXISTS (SELECT 1 FROM @tmpPhone t WHERE t.id = p.id AND t.PhoneType = p.PhoneType) ; 
+0

Ja, das funktioniert perfekt. Das gleiche wie oben. Vielen Dank Gordon. Stehe zu lange auf ein Problem und du musst nach neuen Augen fragen. –

Verwandte Themen