我有一个系统集成项目,需要从一个数据库到另一个数据库的CRUD。不是特别复杂。但是,当涉及删除目标中但不存在于源中的行时,我遇到了一些麻烦。标准模式包括:LEFT JOIN,NOT EXISTS或NOT IN。我选择了LEFT JOIN。我的电话' table使用复合密钥,Employee' Id'和PhoneType:工作,家庭,移动等。标准左连接将删除源中没有的任何目标电话号码。这清除了整个表格。 注意:我只更新自上次更新以来已更改的记录,而不是整个目标&来源。所以,我写了一个修复,我怀疑它是非常糟糕的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?
这有效,但我觉得有一种更好的方法可以确保我们只删除该员工的记录,而不是所有其他员工。
有什么建议吗?
答案 0 :(得分:2)
使用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 :(得分:1)
我认为两个存在的语句几乎捕获了逻辑:正如你所描述的那样
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) ;
答案 2 :(得分:0)
合并似乎工作正常 - 但您仍然需要查看ID是否在您的参考集中,我没有看到一个干净利落的方式
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;