【问题标题】:SQL Delete clears the table instead of erroringSQL Delete 清除表而不是出错
【发布时间】:2013-12-21 02:55:33
【问题描述】:

我有一段 SQL(您会认为)不会编译,而是从目标表中删除所有行。

考虑这个设置:

create table TableA (ColumnA varchar(200));
create table TableB (ColumnB varchar(200));

insert TableA values ('A'),('B'),('C');
insert TableB values ('A');

然后是下面的sql:

--Returns all rows from TableA
select * from TableA;

--Does not error (ColumnA does not exist on TableB)
delete TableA where ColumnA in (select ColumnA from TableB)

--No Rows are returned
select * from TableA;

上面的删除语句会导致从TableA 中删除所有行,而不是报错ColumnATableB 中不存在

这里有一个 SQL Fiddle 证明了这一点:http://www.sqlfiddle.com/#!3/9d883/6

似乎来自TableAColumnA 正在被提取,但预计它会“超出范围”。

这是为什么?

【问题讨论】:

    标签: sql-server sql-server-2008 tsql correlated-subquery


    【解决方案1】:

    由于内部查询中的 ColumnA 与外部查询之间的相关性,这按预期工作。

    这种常用的关联查询模式是有效的

    DELETE TableA WHERE NOT EXISTS (select * from TableB where TableB.ID=TableA.ID)
    

    它会删除在 TableB 中没有依赖记录的 TableA 条目。

    它表明您可以在相关查询中引用 TableA 列。在您的查询中

    delete TableA where ColumnA in (select ColumnA from TableB)
    

    内部查询正在产生

    • TableB 中的每条记录对应一行
    • 每行一列,其值为来自外部查询的ColumnA

    所以删除通过

    【讨论】:

      【解决方案2】:

      虽然我理解这种困惑,但它的行为应如此。 ColumnA 仍在“范围内”。事实上,如果你愿意,你可以在你的子查询中加入它。括号不限制范围,但从可读性的角度来看,我可以看到它造成的混乱。

      这是另一个例子,说明为什么总是在列名前加上表名(或别名)是个好主意。

      【讨论】:

      • 绝对不要在列名前加上表名,那会是一些丑陋的架构,但绝对要使用别名...
      猜你喜欢
      • 2021-04-07
      • 2013-01-10
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 2022-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多