Mam projekt integracji systemu, który potrzebujedo CRUD z jednego DB do drugiego. Niezbyt skomplikowane. Jednak jeśli chodzi o usuwanie wierszy, które istnieją w celu, ale nie w źródle, miałem trochę problemów. Standardowe wzory to: LEWE DOŁĄCZ, NIE ISTNIEJE lub NIE. Wybrałem POŁĄCZENIE W LEWO. Moja tabela „Telefon” korzysta ze złożonego klucza, identyfikatora pracownika i typu telefonu: Praca, Dom, Telefon komórkowy itp. Standardowe lewe połączenie usuwa KAŻDY docelowy numer telefonu NIE w źródle. To usuwa cały stół. UWAGA: aktualizuję tylko rekordy, które zmieniły się od ostatniej aktualizacji, NIE cały cel i źródło. Więc napisałem poprawkę, która, jak podejrzewam, jest naprawdę kiepskim SQL:
-- 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
DECLARE@Phone 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?
To działa, ale wydaje mi się, że jest lepszy sposób, aby upewnić się, że usuwamy tylko rekordy TEGO pracownika, a nie wszystkich pozostałych.
Jakieś sugestie?
Odpowiedzi:
2 dla odpowiedzi № 1Posługiwać się 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)
Edycja: usuwanie za pomocą 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)
1 dla odpowiedzi nr 2
Myślę, że istnieją dwa stwierdzenia, które w dużym stopniu oddają logikę: tak, jak to opisujesz
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 dla odpowiedzi № 3
scalanie wydaje się działać dobrze - ale nadal musisz sprawdzić, czy identyfikator znajduje się w twoim zestawie referencyjnym, nie widzę jasnego sposobu na obejście tego
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;