sql >> Base de Datos >  >> RDS >> Sqlserver

Función con valores de tabla:el orden por se ignora en la salida

Había dos cosas mal con su enfoque original.

  1. Al insertar en la tabla, nunca se garantizó que el ORDER BY en INSERT ... SELECT ... ORDER BY sería el orden en que se insertaron realmente las filas.
  2. Al seleccionarlo, SQL Server no garantiza que SELECT sin ORDER BY devolverá las filas en cualquier orden en particular, como el orden de inserción de todos modos.

En 2012 parece que el comportamiento ha cambiado con respecto al elemento 1. Ahora generalmente ignora el ORDER BY en el SELECT declaración que es la fuente de un INSERT

DECLARE @T TABLE(number int)

INSERT INTO @T 
SELECT number
FROM master..spt_values
ORDER BY name

Plan 2008

Plan 2012

El motivo del cambio de comportamiento es que en versiones anteriores SQL Server producía un plan que se compartía entre ejecuciones con SET ROWCOUNT 0 (apagado) y SET ROWCOUNT N . El operador de clasificación solo estaba allí para garantizar la semántica correcta en caso de que el plan fuera ejecutado por una sesión con un ROWCOUNT distinto de cero establecer. El TOP el operador a la izquierda es un ROWCOUNT TOP .

SQL Server 2012 ahora produce planes separados para los dos casos, por lo que no es necesario agregarlos a ROWCOUNT 0 versión del plan.

Una clasificación aún puede aparecer en el plan en 2012 si SELECT tiene un TOP explícito definido (que no sea TOP 100 PERCENT ) pero esto aún no garantiza el orden de inserción real de las filas, el plan podría tener otro tipo después del TOP N se establece para obtener las filas en orden de índice agrupado, por ejemplo.

Para el ejemplo de su pregunta, simplemente ajustaría el código de llamada para especificar ORDER BY name si eso es lo que requiere.

Con respecto a su sort_id idea de Garantías de pedido en SQL Server se garantiza al insertar en una tabla con IDENTITY que el orden en que se asignan será según el ORDER BY así que también podrías hacer

DECLARE @Customer TABLE (
  Sort_Id     INT IDENTITY PRIMARY KEY,
  Customer_ID INT,
  Name        INT,
  Expired     BIT )

INSERT INTO @Customer
SELECT Customer_ID,
       Name,
       CASE
         WHEN Expiry_Date < Getdate() THEN 1
         WHEN Expired = 1 THEN 1
         ELSE 0
       END
FROM   Customer
ORDER  BY Name 

pero aún tendría que ordenar por el sort_id en sus consultas de selección ya que no hay orden garantizado sin eso (quizás este sort_id El enfoque puede ser útil en el caso de que las columnas originales utilizadas para ordenar no se copien en la variable de la tabla)