在SQL Server更新语句中使用相关子查询会产生意外结果

时间:2012-02-06 14:07:47

标签: sql sql-server correlated-subquery

我正在将一个主键列引入一个尚未拥有的列。在我添加了一个默认值为0的普通字段Id(int)之后,我尝试使用以下更新语句为每条记录创建唯一值:

update t1
set t1.id = (select count(*) from mytable t2 where t2.id <> t1.id)
from mytable t1

我希望每行都能执行子查询,因为我引用了t1。每次执行子查询时,计数应少一个,但不起作用。

结果是Id在每条记录中仍为0。我以前在其他DBMS上使用过这个成功的。我在这里使用SQL Server 2008。

如何为每条记录生成唯一值并更新Id字段?

2 个答案:

答案 0 :(得分:4)

尝试解释为什么它不能按预期工作

  

我希望每行都能执行子查询,因为我引用了t1。

执行它会影响所有行。但UPDATE stetement是一个语句,它作为一个语句执行,影响整个表(如果你有一个WHERE子句,则会影响它的一部分。)

  

每次执行子查询时,计数应少一个,但不起作用。

您期望通过每行对子查询进行一次评估来执行UPDATE。但它是首先评估的一个语句 - 对于所有受影响的行 - 然后更改(更新)行。 (DBMS可能会这样做,但结果应该好像它正是这样做的。)

  

结果是Id在每条记录中仍为0。

当执行前所有行具有相同的0值时,这是此语句的正确和预期行为。 COUNT(*)0

  

我以前在其他DBMS上使用过此功能。

我的“疯狂”猜测是你在MySQL中使用它。 (更正/更新:我的猜测错了,Update的这种语法对MySQL无效,显然查询在Firebird中“正确”工作)。 UPDATE在DBMS中以标准方式不起作用。它可以 - 正如您所了解的那样 - 逐行,而不是全表。

  

我在这里使用SQL Server 2008。

此DBMS与UPDATE一起正常运行。您可以编写一个具有所需结果的不同Update语句,或者更好地使用自动生成的IDENTITY列,正如其他人所建议的那样。

答案 1 :(得分:1)

SQL正在使用ID不等于0的记录数更新每一行。由于所有行ID等于0,因此没有不等于0的行,因此没有任何更新。

试着在这里查看这个答案:

Adding an identity to an existing column