DELETE 子句删除的行多于 SELECT 子查询 returns
DELETE clause deletes more rows than the SELECT subquery returns
我有两个 table 具有相同的列但行数不同,table 有一个 3 列复合主键。
有 table1 原始 table 和 table2 更新后的 table,由于数据已删除,行数较少。我有一个 SELECT 声明 returns table1 中的行,但不在 table2 中;然而,当我使用 WHERE EXISTS 将 SELECT 语句作为子查询放在 DELETE 子句中时,它想要删除 table 1 中的所有行,而不仅仅是子查询中的行。
代码:
DELETE FROM table1
WHERE EXISTS(
SELECT t1.*
FROM table1 AS t1 LEFT JOIN table2 AS t2
ON (t1.compositekey1 = t2.compositekey1)
AND (t1.compositekey2 = t2.compositekey2)
AND (t1.compositekey3 = t2.compositekey3)
WHERE (t2.compositekey1 IS NULL) AND
(t2.compositekey2 IS NULL) AND (t2.compositekey3 IS
NULL)
);
我将子查询作为独立的 SELECT 查询进行了测试,它返回了 110 行,这是正确的数量,但是当放入上面的 DELETE 查询时,它想要删除所有 9600 行。我的印象是 WHERE EXISTS 应该只删除子查询返回的虚拟 table 中的行。
当我将反向查询用作 INSERT 查询时,将 table2 中不在 table1 中的所有行插入到 table1 中,它也工作正常.
所以我不知道我在哪里搞砸了 DELETE 语句。
我尝试使用:
WHERE t1.compositekey1, t1.compositekey2, t1.compositekey3 IN (......)
但是我收到一条错误消息说使用 EXISTS。这是在访问数据库中使用的,所以我猜同样的规则适用于 sql 服务器。
在此先感谢您的帮助。
您的子查询不相关,并且 return 至少有一行。因此 exists
总是 return true 并且删除操作会尝试删除所有内容。
尝试将 not exists
与相关子查询一起使用:
delete
from table1 t1
where not exists (
select 1
from table2 t2
where t1.compositekey1 = t2.compositekey1
and t1.compositekey2 = t2.compositekey2
and t1.compositekey3 = t2.compositekey3
);
您也可以使用左连接来做到这一点:
delete t1
from table1 t1
left join table2 t2 on t1.compositekey1 = t2.compositekey1
and t1.compositekey2 = t2.compositekey2
and t1.compositekey3 = t2.compositekey3
where t2.compositekey1 is null;
此外,我注意到您试图在子查询中检查所有三列是否为空。您只需检查一个 - 任何一个。
这也应该有效:
DELETE
FROM
table1
WHERE
EXISTS
(
SELECT
*
FROM
table2
WHERE
table1.compositekey1 = table2.compositekey1
AND table1.compositekey2 = table2.compositekey2
AND table1.compositekey3 = table2.compositekey3 );
我有两个 table 具有相同的列但行数不同,table 有一个 3 列复合主键。
有 table1 原始 table 和 table2 更新后的 table,由于数据已删除,行数较少。我有一个 SELECT 声明 returns table1 中的行,但不在 table2 中;然而,当我使用 WHERE EXISTS 将 SELECT 语句作为子查询放在 DELETE 子句中时,它想要删除 table 1 中的所有行,而不仅仅是子查询中的行。
代码:
DELETE FROM table1
WHERE EXISTS(
SELECT t1.*
FROM table1 AS t1 LEFT JOIN table2 AS t2
ON (t1.compositekey1 = t2.compositekey1)
AND (t1.compositekey2 = t2.compositekey2)
AND (t1.compositekey3 = t2.compositekey3)
WHERE (t2.compositekey1 IS NULL) AND
(t2.compositekey2 IS NULL) AND (t2.compositekey3 IS
NULL)
);
我将子查询作为独立的 SELECT 查询进行了测试,它返回了 110 行,这是正确的数量,但是当放入上面的 DELETE 查询时,它想要删除所有 9600 行。我的印象是 WHERE EXISTS 应该只删除子查询返回的虚拟 table 中的行。
当我将反向查询用作 INSERT 查询时,将 table2 中不在 table1 中的所有行插入到 table1 中,它也工作正常.
所以我不知道我在哪里搞砸了 DELETE 语句。
我尝试使用:
WHERE t1.compositekey1, t1.compositekey2, t1.compositekey3 IN (......)
但是我收到一条错误消息说使用 EXISTS。这是在访问数据库中使用的,所以我猜同样的规则适用于 sql 服务器。
在此先感谢您的帮助。
您的子查询不相关,并且 return 至少有一行。因此 exists
总是 return true 并且删除操作会尝试删除所有内容。
尝试将 not exists
与相关子查询一起使用:
delete
from table1 t1
where not exists (
select 1
from table2 t2
where t1.compositekey1 = t2.compositekey1
and t1.compositekey2 = t2.compositekey2
and t1.compositekey3 = t2.compositekey3
);
您也可以使用左连接来做到这一点:
delete t1
from table1 t1
left join table2 t2 on t1.compositekey1 = t2.compositekey1
and t1.compositekey2 = t2.compositekey2
and t1.compositekey3 = t2.compositekey3
where t2.compositekey1 is null;
此外,我注意到您试图在子查询中检查所有三列是否为空。您只需检查一个 - 任何一个。
这也应该有效:
DELETE
FROM
table1
WHERE
EXISTS
(
SELECT
*
FROM
table2
WHERE
table1.compositekey1 = table2.compositekey1
AND table1.compositekey2 = table2.compositekey2
AND table1.compositekey3 = table2.compositekey3 );