【问题标题】:How to update and order by using ms sql如何使用 ms sql 进行更新和排序
【发布时间】:2010-10-13 21:22:39
【问题描述】:

理想情况下我想这样做:

UPDATE TOP (10) messages SET status=10 WHERE status=0 ORDER BY priority DESC;

英文:我想从数据库中获取前 10 条可用 (status=0) 消息并锁定它们 (status=10)。优先级更高的消息应该首先得到。

不幸的是,MS SQL 不允许在更新中使用 order by 子句。

无论如何如何规避这个?

【问题讨论】:

    标签: sql sql-server tsql sql-order-by sql-update


    【解决方案1】:

    如下面的 cmets 所述,您也可以使用 SET ROWCOUNT 子句,但仅适用于 SQL Server 2014 及更早版本。

    SET ROWCOUNT 10
    
    UPDATE messages
    SET status = 10 
    WHERE status = 0 
    
    SET ROWCOUNT 0
    

    更多信息:http://msdn.microsoft.com/en-us/library/ms188774.aspx

    或者使用临时表

    DECLARE @t TABLE (id INT)
    INSERT @t (id)
    SELECT TOP 10 id
    FROM messages
    WHERE status = 0
    ORDER BY priority DESC
    
    UPDATE messages
    SET status = 10
    WHERE id IN (SELECT id FROM @t)
    

    【讨论】:

    • 对于那些阅读这篇文章的人来说......(你永远不会知道。) SET ROWCOUNT 面临弃用 msdn.microsoft.com/en-us/library/ms188774.aspx “使用 SET ROWCOUNT 不会影响 SQL 未来版本中的 DELETE、INSERT 和 UPDATE 语句服务器。” - 至少在 SQL Server 2014 之前它是好的。
    • 虽然 rowcount 如果您想要任意 10 行效果很好,但您不能指定 order by 来准确确定哪 10 行。您的带有临时表的示例有效,但它依赖于 id列。
    【解决方案2】:

    我必须将此作为一种更好的方法提供 - 你并不总是拥有身份字段的奢侈:

    UPDATE m
    SET [status]=10
    FROM (
      Select TOP (10) *
      FROM messages
      WHERE [status]=0
      ORDER BY [priority] DESC
    ) m
    

    您还可以根据需要使子查询变得复杂 - 连接多个表等...

    为什么这样更好?它不依赖于messages 表中是否存在标识字段(或任何其他唯一列)。它可用于更新任何表的前 N ​​行,即使该表根本没有唯一键。

    【讨论】:

    • 这个答案与 dotjoe 的答案有何不同:stackoverflow.com/a/655561/2279200
    • 如果您不花时间尝试理解它,我对我的回答被否决并不感到惊讶。我的答案与 dotjoe 的答案不同——以及这里的大多数其他答案——因为其他答案假设表有一个身份字段(......其中 ID IN......)。您不能总是假设该表将具有标识字段。当您的表中没有 ID 字段时,我提供了一种替代方法。请在投反对票之前尝试理解答案。
    • 感谢您的简短解释。请花一些时间来编辑您的答案并添加您刚才提到的细节。它将使您的答案更完整,更容易理解,而无需花费太多时间。一旦你编辑你的答案,我将撤销我的投票。
    • @Athafoud 我已经扩展了答案(尽管我不是原始发帖人);你能复习一下吗?
    【解决方案3】:

    您可以执行子查询,首先获取按优先级排序的前 10 个 ID,然后更新该子查询中的 ID:

    UPDATE  messages 
    SET status=10 
    WHERE ID in (SELECT TOP (10) Id 
                 FROM Table 
                 WHERE status=0 
                 ORDER BY priority DESC);
    

    【讨论】:

    • 鉴于我想要此解决方案的索引。然后我会使用:(priority desc,status)还是(status,priority desc)?换句话说:order by 在 where 之前使用吗?
    • 实际上查询不正确.... order by 子句不能在子查询中使用,除非还给出了 TOP。 (这就是 SQL 引擎所说的)。所以正确的查询应该是:UPDATE messages SET status=10 WHERE ID in (SELECT TOP (10) Id FROM Table WHERE status=0 ORDER BY priority DESC);
    • 你说得对,我在写最后的编辑时错过了顶部。我会按照你说的编辑它
    【解决方案4】:
    WITH    q AS
            (
            SELECT  TOP 10 *
            FROM    messages
            WHERE   status = 0
            ORDER BY
                    priority DESC
            )
    UPDATE  q
    SET     status = 10
    

    【讨论】:

    • +1 用于 CTE,这样做可以在使用 OUTPUT 子句时为我摆脱连接
    • 这实际上是首选答案,而不是接受的答案。
    • @Haroon:哪两个陈述?
    • @Quassnoi 我认为 Haroon 是说为了成为原子,您需要包装 CTE 并使用事务更新。
    • 我必须使用前 500000 来更新临时表中的所有行,该表不超过 1000 行,才能使用 order by。
    【解决方案5】:
    UPDATE messages SET 
     status=10 
    WHERE ID in (SELECT TOP (10) Id FROM Table WHERE status=0 ORDER BY priority DESC);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-06
      • 2015-08-18
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多