2009-03-17 4 views
37

Lo ideal sería que yo quiero hacer esto:Cómo actualizar y el orden mediante el uso de MS SQL

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

En Inglés: Quiero conseguir los (= 0 Estado) Los mensajes de la parte superior 10 disponibles de la base de datos y encerrarlos (estado = 10). Un mensaje con una prioridad más alta debe obtenerse primero.

lamentablemente MS SQL no permite una orden por cláusula en la actualización.

De todos modos, ¿cómo evitar esto?

Respuesta

37

Usted puede hacer una sub consulta en la que primero recibe los ID de los 10 primeros ordenados por prioridad y luego actualizar los que están en esa consulta substitución:

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

dado que me gustaría un índice para esta solución. ¿Utilizaría entonces: (prioridad desc, estado) o (estado, prioridad desc)? En otras palabras: ¿el orden utilizado es anterior al dónde? – Toad

+6

En realidad, la consulta no era correcta ... la cláusula order by no se puede usar en una subconsulta A MENOS QUE también se proporcione un TOP. (Esto es lo que dice el motor SQL). Entonces la consulta correcta debería ser: Mensajes de actualización SET status = 10 WHERE ID in (SELECCIONAR TOP (10) Id FROM Tabla DONDE estado = 0 ORDENAR por prioridad DESC); – Toad

+0

Tienes razón, me perdí la cima cuando escribí la edición final. Voy a editarlo como dijiste –

84
WITH q AS 
     (
     SELECT TOP 10 * 
     FROM messages 
     WHERE status = 0 
     ORDER BY 
       priority DESC 
     ) 
UPDATE q 
SET  status = 10 
+2

+1 para el CTE, haciéndolo de esta manera se deshace de una unión para mí cuando se utiliza una cláusula OUTPUT – nitzmahone

+4

Esta sería la respuesta preferida en lugar de la aceptada. – Carvellis

+0

Tenga en cuenta que las dos declaraciones no son atómicas. – Haroon

0

como se indica en los comentarios a continuación, también puede usar la cláusula SET ROWCOUNT, pero solo para SQL Server 2014 y anteriores.

SET ROWCOUNT 10 

UPDATE messages 
SET status = 10 
WHERE status = 0 

SET ROWCOUNT 0 

Más información: http://msdn.microsoft.com/en-us/library/ms188774.aspx

O con una tabla temporal

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) 
+4

Para aquellos que leen esta versión anterior ... (nunca se sabe). SET ROWCOUNT se enfrenta a deprecation http: // msdn.microsoft.com/en-us/library/ms188774.aspx "Usar SET ROWCOUNT no afectará las instrucciones DELETE, INSERT y UPDATE en una versión futura de SQL Server." - es bueno hasta SQL Server 2014, al menos. –

+0

Mientras 'rowcount' funciona bien si quiere 10 filas arbitrarias, no puede especificar' order by' para decidir exactamente qué 10. Su ejemplo con una tabla temporal funciona, pero depende de una columna de id. –

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

tengo que ofrecer esto como un mejor enfoque - que no siempre tienen el lujo de una campo de identidad:

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

También puede hacer que la consulta secundaria sea tan complicada como desee: unir varias tablas, etc. ...

¿Por qué es esto mejor? No se basa en la presencia de un campo de identidad (o cualquier otra columna única) en la tabla messages. Se puede usar para actualizar las N primeras filas de cualquier tabla, incluso si esa tabla no tiene ninguna clave única.

+0

Cómo esta respuesta es diferente de la respuesta de dotjoe: http://stackoverflow.com/a/655561/2279200 – Athafoud

+1

No me sorprende el voto negativo de mi respuesta si no se toma el tiempo para tratar de entenderlo. Mi respuesta es diferente de la respuesta de dotjoe, y la mayoría de las respuestas aquí, porque las otras respuestas suponen que la tabla tiene un campo de identidad (... donde ID IN ...). No siempre se puede suponer que la tabla tendrá un campo de identidad. Ofrecí una alternativa para cuando no tienes el campo ID en tu mesa. Por favor, intente comprender la respuesta antes de votar abajo. – mfascino

+0

Gracias por la breve explicación. Dedique un tiempo a editar su respuesta y agregue los detalles que acaba de mencionar. Hará que su respuesta sea más completa y fácil de entender sin pasar demasiado tiempo en ella. Una vez que edite su respuesta, revocaré mi voto. – Athafoud

Cuestiones relacionadas