Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Fonction Table-Valued - Order by est ignoré dans la sortie

Il y avait deux choses qui n'allaient pas dans votre approche initiale.

  1. Lors de l'insertion dans le tableau, il n'a jamais été garanti que le ORDER BY sur INSERT ... SELECT ... ORDER BY serait l'ordre dans lequel les lignes ont été réellement insérées.
  2. En le sélectionnant, SQL Server ne garantit pas que SELECT sans ORDER BY renverra les lignes dans n'importe quel ordre particulier tel que l'ordre d'insertion de toute façon.

En 2012, il semble que le comportement ait changé par rapport à l'élément 1. Il ignore maintenant généralement le ORDER BY sur le SELECT instruction qui est la source d'un INSERT

DECLARE @T TABLE(number int)

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

Plan 2008

Plan 2012

La raison du changement de comportement est que dans les versions précédentes, SQL Server produisait un plan qui était partagé entre les exécutions avec SET ROWCOUNT 0 (off) et SET ROWCOUNT N . L'opérateur de tri n'était là que pour garantir la sémantique correcte dans le cas où le plan était exécuté par une session avec un ROWCOUNT non nul Positionner. Le TOP l'opérateur à sa gauche est un ROWCOUNT TOP .

SQL Server 2012 produit désormais des plans distincts pour les deux cas, il n'est donc pas nécessaire de les ajouter au ROWCOUNT 0 version du plan.

Un tri peut encore apparaître dans le plan en 2012 si le SELECT a un TOP explicite défini (autre que TOP 100 PERCENT ) mais cela ne garantit toujours pas l'ordre d'insertion réel des lignes, le plan peut alors avoir un autre tri après le TOP N est établi pour obtenir les lignes dans l'ordre de l'index clusterisé par exemple.

Pour l'exemple de votre question, je voudrais simplement ajuster le code d'appel pour spécifier ORDER BY name si c'est ce qu'il faut.

Concernant votre sort_id idée de Garanties de commande dans SQL Server il est garanti lors de l'insertion dans une table avec IDENTITY que l'ordre qui leur est attribué sera conforme au ORDER BY donc tu peux aussi faire

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 

mais vous auriez toujours besoin de commander par le sort_id dans vos requêtes de sélection car il n'y a pas de commande garantie sans cela (peut-être ce sort_id approche peut être utile dans le cas où les colonnes d'origine utilisées pour le tri ne sont pas copiées dans la variable de table)