如何使用subselect更新TOP 5?

时间:2009-08-03 06:12:25

标签: sql sql-server

我很惊讶地发现以下更新了34行...而不是5行:

UPDATE 
 Message
 SET StatusRawCode = 25
WHERE StatusRawCode in
  ( 
     Select TOP 5 
      M2.StatusRawCode
       From Message as M2
        Where M2.StatusRawCode = 5
  ) 

关于如何将其打造成正确形状的任何想法?

谢谢!

6 个答案:

答案 0 :(得分:4)

我的猜测是从您的子查询返回的StatusRawCode值是在更新的34条记录中使用的值。而不是

WHERE StatusRawCode IN

使用此:

UPDATE 
    Message
SET StatusRawCode = 25
    WHERE PrimaryKey in
    ( 
        Select TOP 5 
            PrimaryKey
        From Message as M2
        Where M2.StatusRawCode = 5
    )

实际上,您将在子查询中选择要更新的5行的主键。请记住,这将根据表的聚簇索引顺序仅更新前5条记录。如果需要为TOP 5记录指定特定条件,则需要添加order by子句。

例如,如果您要将一个名为Rank的列用作条件,请按以下方式编写查询:

UPDATE 
    Message
SET 
    StatusRawCode = 25
WHERE 
    PrimaryKey IN
    ( 
        SELECT TOP 5 
            PrimaryKey
        FROM 
            Message as M2
        WHERE 
            M2.StatusRawCode = 5
        ORDER BY
            Rank DESC
    )

这将根据Rank列值为您提供TOP 5记录。您可以根据需要替换列。

答案 1 :(得分:2)

有没有办法明确识别TOP 5行?

根据您的查询,如果您执行TOP 5并不重要(因为您选择StatusRawCode = 5的记录)。因此,在某种程度上,您的查询与

相同
UPDATE 
 Message
 SET StatusRawCode = 25
WHERE StatusRawCode = 5

答案 2 :(得分:2)

StatusRawCode似乎远非独一无二。您想要撤回主键或其他唯一列以识别前五个。您正在更新StatusRawCode等于5的任何行。显然,有34行符合该条件。

此外,top 5仅表示具有order by子句的任何内容。 SQL Server不会以任何特定顺序存储行,并且不会保证每次都返回相同的五行。 SQL Server将行存储在8k页中,并且它不保证也不提供行集的一致顺序。您不能依赖于此,并且必须使用order by以确保您获得正确的五行。否则,您将更新五个随机行

答案 3 :(得分:1)

您需要将IN条件置于唯一的主键上。

在SQL 2K5和转发版中,您还可以使用CTE:

  WITH cte AS (
     Select TOP 5 
      M2.StatusRawCode
       From Message as M2
        Where M2.StatusRawCode = 5
    ORDER BY ...
  )
  UPDATE cte 
  SET StatusRawCode = 25

答案 4 :(得分:0)

我想介入并建议您始终使用SELECT语句启动UPDATE语句。像这样:

SELECT * 
--UPDATE m SET StatusRawCode = 25
FROM Message m
WHERE StatusRawCode in  (
        Select TOP 5
       M2.StatusRawCode
       From Message as M2
       Where M2.StatusRawCode = 5  
);

...但是一旦你可以看到你出错的地方(在这种情况下,可能与KG的回应类似),肯定会根据你的实际要求修改你的查询。

这将显示将受您的查询影响的行...所以一旦你有了正确的,更改UPDATE行的SELECT *(当前已注释),你应该得到可预测的结果。

请记住,UPDATE不支持ORDER BY,所以如果你最终尝试UPDATE TOP(5)...,那么你将无法得到你想要的结果。

罗布

答案 5 :(得分:0)

如果您没有主键且CTE不可用,则以下内容也适用:

UPDATE M
SET StatusRawCode = 25
FROM (Select TOP 5 
    M2.StatusRawCode
    FROM Message as M2
    WHERE M2.StatusRawCode = 5
    ORDER BY ...) M