web-dev-qa-db-fra.com

Comment mettre à jour et commander en utilisant MS SQL

Idéalement, je veux faire ceci:

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

En anglais: je veux récupérer les 10 premiers messages disponibles (état = 0) de la base de données et les verrouiller (état = 10). Un message avec une priorité plus élevée doit être obtenu en premier.

malheureusement, MS SQL n'autorise pas de clause order by dans la mise à jour.

Quoi qu'il en soit, comment contourner cela?

49
Toad

Vous pouvez faire une sous-requête où vous obtenez d'abord les ID des 10 premiers classés par priorité, puis mettez à jour ceux qui se trouvent sur cette sous-requête:

UPDATE  messages 
SET status=10 
WHERE ID in (SELECT TOP (10) Id 
             FROM Table 
             WHERE status=0 
             ORDER BY priority DESC);
43
Eduardo Crimi
WITH    q AS
        (
        SELECT  TOP 10 *
        FROM    messages
        WHERE   status = 0
        ORDER BY
                priority DESC
        )
UPDATE  q
SET     status = 10
99
Quassnoi

Je dois proposer cela comme une meilleure approche - vous n'avez pas toujours le luxe d'un champ d'identité:

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

Vous pouvez également rendre la sous-requête aussi compliquée que vous le souhaitez - joindre plusieurs tables, etc.

Pourquoi est-ce mieux? Il ne dépend pas de la présence d'un champ d'identité (ou de toute autre colonne unique) dans la table messages. Il peut être utilisé pour mettre à jour les N premières lignes de n'importe quelle table, même si cette table n'a aucune clé unique.

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

Comme indiqué dans les commentaires ci-dessous, vous pouvez également utiliser la clause SET ROWCOUNT, mais uniquement pour SQL Server 2014 et versions antérieures.

SET ROWCOUNT 10

UPDATE messages
SET status = 10 
WHERE status = 0 

SET ROWCOUNT 0

Plus d'informations: http://msdn.Microsoft.com/en-us/library/ms188774.aspx

Ou avec une table temporaire

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)