web-dev-qa-db-fra.com

SELECT * INTO conserve ORDER BY dans SQL Server 2008 mais pas 2012

Exécutez le code SQL suivant en 2008 et 2012. Une fois exécuté en 2008, le résultat renvoyé se trouve dans le bon ordre de tri. En 2012, l'ordre de tri n'est pas retenu.

Est-ce un changement connu? Existe-t-il une solution pour 2012 afin de conserver l'ordre de tri?

CREATE TABLE #MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO #MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4

SELECT * INTO #Result FROM #MyTable ORDER BY SortOrder

SELECT * FROM #Result

DROP TABLE #MyTable
DROP TABLE #Result
10
Rivka

Comment savoir quelle est la commande dans une table en utilisant select * from #result? Il n'y a aucune garantie quant à l'ordre dans une requête select.

Cependant, les résultats sont différents sur SQL Fiddle. Si vous voulez vous assurer que les résultats sont identiques, ajoutez une clé primaire. Alors l'ordre d'insertion est garanti:

CREATE TABLE MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4


select top 0 * into result from MyTable;

alter table Result add id int identity(1, 1) primary key;

insert into Result(name, sortorder)
    SELECT * FROM MyTable
    ORDER BY SortOrder;

J'ai encore horreur de faire select * from Result après cela. Mais oui, il les renvoie dans le bon ordre dans SQL Server 2008 et 2012. Non seulement cela, mais comme SQL Server garantit que les clés primaires sont insérées dans le bon ordre, il est même garanti que les enregistrements sont dans le bon ordre. ce cas.

MAIS . . . le fait que les enregistrements soient dans un ordre particulier sur les pages ne signifie pas qu'ils seront récupérés dans cet ordre sans clause order by.

17
Gordon Linoff

Lors de l'utilisation de ORDER BY avec une INSERT, il n'a jamais été garanti de faire quoi que ce soit autre que le contrôle de l'ordre de la colonne identity si présent. 

Avant SQL Server 2012, l'optimiseur produisait toujours un plan comme si une colonne d'identité existait et semble donc s'ordonner correctement. SQL Server 2012 n'assume pas correctement une colonne d'identité et ne commande que si la table a réellement une colonne d'identité.

Vous pouvez donc résoudre ce problème en ajoutant une colonne Identity à votre table de résultats temporaire. 

Cependant, vous devriez vraiment juste ajouter une clause ORDER BY à votre instruction SELECT? Les instructions SELECT sans ORDER BY n'ont jamais été garanties de renvoyer les résultats dans un ordre spécifique. Ajoutez toujours la clause ORDER BY pour vous assurer de recevoir les résultats comme vous le souhaitez.

9
sgeddes

Tout d’abord, merci pour l’explication, cela nous a beaucoup aidé. Le problème de la définition d’une variable de table ou de la création d’une table temporaire, c’est que vous devez la définir, et si vous allez le définir, vous pouvez aussi bien insérer l’insert de la bonne manière:

INSERT INTO #Result (col1, col2...)
SELECT Col1, Col2... FROM #MyTable....

Dans mon cas, ORDER BY dans INSERT était dynamique et lorsque j'ai appelé "SELECT * FROM #Result", ORDER BY était inconnu. Ma solution a été d’ajouter une colonne ROW_NUMBER que je pouvais coder en dur dans SELECT en même temps que les données. Oui, je dois encore inclure un ORDER BY, mais au moins c'est statique. Voici ce que j'ai fait:

--Insert
SELECT ROW_NUMBER() OVER (ORDER BY T.SortOrder ASC) AS RowNum, T.*  
INTO #Result 
FROM (SELECT * FROM #MyTable ...) AS T;

--Get data out
SELECT * FROM #Result ORDER BY RowNum;

J'espère que cela t'aides.

2
Losbear

Solution: Vous pouvez ajouter un SET ROWCOUNT avant ce type de requête, puis le remettre à zéro après pour le réinitialiser. Cela fonctionne. Cela forcera SQL à conserver l'ordre dans votre requête.

SET ROWCOUNT 1000000000

CREATE TABLE #MyTable(Name VARCHAR(50), SortOrder INT)
INSERT INTO #MyTable SELECT 'b', 2 UNION ALL SELECT 'c', 3 UNION ALL SELECT 'a', 1 UNION ALL SELECT 'e', 5 UNION ALL SELECT 'd', 4

SELECT * INTO #Result FROM #MyTable ORDER BY SortOrder

SELECT * FROM #Result

SET ROWCOUNT 0

DROP TABLE #MyTable
DROP TABLE #Result
0
patrick imbault

Si vous avez différents résultats de tri lorsque vous interrogez chaque base de données, votre classement est probablement différent entre les deux.

Essayez explicitement en définissant le classement dans votre requête et voyez si vos résultats sont renvoyés dans le même ordre dans les deux bases de données, par exemple.

SELECT * FROM #Result ORDER BY C1 COLLATE Latin1_General_CS_AS
0
George Johnston

Vous devez créer ROW_NUMBER () ordre par colonne que vous souhaitez commander. Ordre directement dans la sélection, est ignoré lors de l’insertion.

 CREATE TABLE #MyTable (Nom VARCHAR (50), SortOrder INT) 
 
 INSÉRER DANS #MyTable 
 SÉLECTIONNER 'b', 2 
 UNION TOUT SELECTIONNER 'c', 3 
 UNION TOUT SELECTIONNER 'a', 1 
 TUNION TOUT SELECTIONNER 'e', ​​5 
 UNION TOUT SELECTIONNER 'd', 4 
 
 SELECT Nom, 
 ROW_NUMBER () OVER (ORDER BY MyTable.SortOrder) AS SortOrder 
 IN #Résultat 
 DE #MyTable AS MyTable 
 ORDER BY SortOrder 
 
 SELECT * FROM #Result 
 
 TABLEAU D'ALIMENTATION #MyTable 
 TABLEAU D'ALIMENTATION #Résultat 
0
Snowww