SQL删除复合键不在的位置

时间:2016-04-06 18:23:35

标签: sql sql-server sql-server-2012

我有一个系统集成项目,需要从一个数据库到另一个数据库的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? 

这有效,但我觉得有一种更好的方法可以确保我们只删除该员工的记录,而不是所有其他员工。

有什么建议吗?

3 个答案:

答案 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;