/ / SQL Видалити, де немає, за допомогою композитного ключа - sql, sql-server, sql-server-2012

Видалити SQL, де не входить комбінований ключ - sql, sql-сервер, sql-сервер-2012

У мене є проект системної інтеграції, який потребуєдо CRUD від однієї БД до іншої. Не особливо складно. Однак, коли справа доходить до видалення рядків, які існують у цілі, але не у джерелі, я зіткнувся з невеликою проблемою. Стандартні схеми включають: ЛІВО ПРИЄДНАЙТЕСЯ, НЕ ІСНУЄ або НЕ ВХОДИТЬ. Я вибрав ЛІВЕ ПРИЄДНАННЯ. У моїй таблиці "Телефон" використовується складений ключ, "Ідентифікатор працівника" та Тип телефону: Робота, Дім, Мобільний телефон тощо. Стандартне ліве приєднання видалить БУДЬ-який цільовий номер телефону, НЕ в джерелі. Це очищає всю таблицю. ПРИМІТКА. Я оновлюю лише ті записи, які змінилися після останнього оновлення, а не всю ціль та джерело. Отже, я написав виправлення, яке, на мою думку, є насправді поганим 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?

Це працює, але я відчуваю, що є кращий спосіб переконатися, що ми видаляємо записи лише для ЦЕГО працівника, а не для всіх інших.

Будь-які пропозиції?

Відповіді:

2 для відповіді № 1

Використовуйте 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)

Редагувати: Видалення за допомогою 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 для відповіді № 2

Я думаю, що два існуючі твердження майже вловлюють логіку: як ви це описуєте

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 для відповіді № 3

Злиття, здається, працює нормально - але вам все одно потрібно перевірити, чи є ідентифікатор у вашому наборі посилань, я не бачу чистого способу обійти це

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;