从SQL Server中的两个表中删除相等的数据

时间:2016-01-16 12:19:06

标签: sql sql-server tsql sql-delete

我有两个包含这些列的表:

表A

Id | Name  | Salary  
1  | TEST1 | 100  
2  | TEST2 | 200  
3  | TEST3 | 300

表B

Id | Name  | Salary  
1  | TEST1 | 100  
2  | TEST2 | 200  
4  | TEST4 | 400

我想从两个表中删除类似的数据(不使用连接)。当我查询

SELECT * 
FROM A 

SELECT * 
FROM B

我应该得到这个结果:

表A

Id | Name  | Salary   
3  | TEST3 | 300

表B

Id | Name  | Salary   
4  | TEST4 | 400

非常感谢任何帮助。提前谢谢。

PS:我要加载约1000万行的表格

3 个答案:

答案 0 :(得分:3)

使用NOT EXISTS

SELECT * 
FROM   a 
WHERE  NOT EXISTS (SELECT 1 
                   FROM   b 
                   WHERE  a.id = b.id) 

SELECT * 
FROM   b 
WHERE  NOT EXISTS (SELECT 1 
                   FROM   a 
                   WHERE  a.id = b.id) 

对于所有字段的使用EXCEPT

SELECT Id, Name, Salary FROM A
EXCEPT
SELECT Id, Name, Salary FROM B

SELECT Id, Name, Salary FROM B
EXCEPT
SELECT Id, Name, Salary FROM A

要从tablea删除记录,请使用以下查询

WITH cte 
     AS (SELECT * 
         FROM   tablea a 
         WHERE  EXISTS (SELECT 1 
                        FROM   tableb b 
                        WHERE  a.id = b.id 
                               AND a.NAME = b.NAME 
                               AND a.salary = b.salary)) 
DELETE FROM cte 

SELECT * 
FROM   tablea 

tableA删除数据之前,将数据插入临时表,以便在从tableB删除数据时引用

答案 1 :(得分:1)

使用DELETE FROM

SELECT *
INTO #temp
FROM TableA;    -- to get the same data to compare with second DELETE

DELETE t
FROM TableA t
WHERE EXISTS(SELECT Id,Name,Salary
             FROM TableB
             INTERSECT
             SELECT t.ID, t.Name, t.Salary);

DELETE t
FROM TableB t
WHERE EXISTS(SELECT Id,Name,Salary
             FROM #temp
             INTERSECT
             SELECT t.ID, t.Name, t.Salary);  


SELECT * FROM TableA;
SELECT * FROM TableB;

LiveDemo

输出:

 TableA:
╔════╦═══════╦════════╗
║ Id ║ Name  ║ Salary ║
╠════╬═══════╬════════╣
║  3 ║ TEST3 ║    300 ║
╚════╩═══════╩════════╝


TableB:
╔════╦═══════╦════════╗
║ Id ║ Name  ║ Salary ║
╠════╬═══════╬════════╣
║  4 ║ TEST4 ║    400 ║
╚════╩═══════╩════════╝

修改

为避免复制整个表格,请使用OUTPUT子句;

CREATE TABLE #temp(ID INT, NAME VARCHAR(100), Salaray INT);

DELETE t
OUTPUT deleted.Id, deleted.Name, deleted.Salary
INTO #temp
FROM TableA t
WHERE EXISTS(SELECT Id,Name,Salary
             FROM TableB
             INTERSECT
             SELECT t.ID, t.Name, t.Salary);

DELETE t
FROM TableB t
WHERE EXISTS(SELECT Id,Name,Salary 
             FROM (SELECT Id,Name,Salary FROM TableA
                   UNION ALL
                   SELECT Id,Name,Salary FROM #temp) AS sub
             INTERSECT
             SELECT t.ID, t.Name, t.Salary); 

LiveDemo2

为避免删除问题(日志增长,tempdb压力等),您可以使用每个100k块处理数据。添加WHILE LOOP包含2个变量@range_start, @range_stop并增加100k或任何其他适合您系统的值。

答案 2 :(得分:0)

您最好将“删除大量行”替换为“创建只包含剩余行的新表

如果您的SQL Server版本支持EXCEPT,则非常简单:

SELECT * INTO newA FROM a
EXCEPT
SELECT * FROM b
;

SELECT * INTO newB FROM b
EXCEPT
SELECT * FROM a
;

请参阅fiddle

EXISTS也简化了NULL治疗。