Il y avait deux choses qui n'allaient pas dans votre approche initiale.
- Lors de l'insertion dans le tableau, il n'a jamais été garanti que le
ORDER BY
surINSERT ... SELECT ... ORDER BY
serait l'ordre dans lequel les lignes ont été réellement insérées. - En le sélectionnant, SQL Server ne garantit pas que
SELECT
sansORDER 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)