2013-05-20 6 views
9

Esegui il seguente SQL nel 2008 e 2012. Quando viene eseguito nel 2008, il risultato restituito è nel suo corretto ordinamento. Nel 2012, il sortorder non viene mantenuto.SELECT * INTO conserva ORDER BY in SQL Server 2008 ma non 2012

Si tratta di un cambiamento noto? C'è un work-around per il 2012 per mantenere l'ordinamento?

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 
+0

Una tabella in SQL Server non ha mai alcun ordine implicito. Se è necessario un ordine specifico, è ** necessario ** fornire una clausola 'ORDER BY' all'istruzione' SELECT' per ottenerla. –

risposta

17

Come si può sapere ciò che l'ordine è all'interno di una tabella utilizzando select * from #result? Non è possibile garantire l'ordine in una query select.

Tuttavia, i risultati sono diversi su SQL Fiddle. Se vuoi garantire che i risultati siano gli stessi, aggiungi una chiave primaria. Poi l'ordine di inserimento è garantita:

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; 

ho ancora aborrire facendo select * from Result dopo questo. Ma sì, li restituisce nell'ordine corretto sia in SQL Server 2008 che nel 2012. Non solo, ma poiché SQL Server garantisce che le chiavi primarie siano inserite nell'ordine corretto, i record sono persino garantiti nell'ordine corretto in questo caso.

MA. . . solo perché i record sono in un ordine particolare sulle pagine non significa che verranno recuperati in tale ordine senza clausola order by.

+1

Grazie - la creazione della colonna Identity lo ha fatto. L'unica cosa che ho fatto in modo diverso è stata creare la tabella #Result prima con CREATE TABLE, poiché INSERT ha troncato i dati in caso contrario. – Rivka

0

Se si dispone di diversi risultati ordinati quando si interroga ogni database, la tua raccolta è probabilmente diversa tra i due.

Provare in modo esplicito impostando le regole di confronto nella query e verificare se i risultati vengono restituiti nello stesso ordine in entrambi i database, ad es.

SELECT * FROM #Result ORDER BY C1 COLLATE Latin1_General_CS_AS 
9

Quando si utilizza ORDER BY con una INSERT, non è mai stato garantito per fare altro che controllare l'ordine della colonna identità se presente.

Prima di SQL Server 2012, l'ottimizzatore ha sempre prodotto un piano come se esistesse una colonna Identity e quindi sembra che ordini correttamente. SQL Server 2012 non presuppone che esista una colonna Identity e solo ordini se la tabella ha effettivamente una colonna Identity.

Quindi è possibile risolvere questo problema aggiungendo una colonna Identity alla tabella dei risultati temporanei.

Tuttavia, dovresti semplicemente aggiungere una clausola ORDER BY all'istruzione SELECT? Le dichiarazioni SELECT senza uno ORDER BY non sono mai state garantite per restituire i risultati in qualsiasi ordine specifico. Aggiungi sempre la clausola ORDER BY per assicurarti di ricevere i risultati come ti aspetti.

+0

Grazie per aver spiegato il ragionamento che c'è dietro. BTW, l'aggiunta di ORDER BY alla selezione non è l'ideale per me, dal momento che ci sono più "set" di dati con diversi set di ordinamento. Pertanto, ORDER BY non sarebbe accurato, in quanto possono essere presenti più record con "1" come ordinamento ... – Rivka

+1

Il motivo della differenza di comportamento non è dovuto al fatto che SQL Server presupponeva sempre che esistesse una colonna "IDENTITY". È perché nelle versioni precedenti al 2012 i piani generati dovevano essere adatti indipendentemente dal fatto che venissero eseguiti o meno con l'opzione 'SET ROWCOUNT'. I piani di cache 2012 con un numero di righe diverso da zero separatamente, quindi non è necessario inquinare il piano principale con questi operatori. –

0

Soluzione: È possibile aggiungere un SET ROWCOUNT prima di questo tipo di query, quindi inserire nuovamente a zero dopo il ripristino, funziona. Questo costringerà SQL a mantenere l'ordine nella tua query.

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

Non funziona. – Oleksandr

2

In primo luogo, grazie sgeddes per la spiegazione, ha aiutato molto. La cosa sulla definizione di un variabile di tabella o la creazione di una tabella temporanea è che devi definirlo, e se avete intenzione di passare attraverso il lavoro di definizione di esso, si potrebbe anche fare l'inserto il modo corretto:

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

Nel mio caso, l'ORDER BY nell'INSERTO era dinamico, quindi quando ho chiamato "SELECT * FROM #Result", l'ordine BY era sconosciuto. La mia soluzione era aggiungere una colonna ROW_NUMBER che potessi inserire hardcode nella SELECT quando stavo ottenendo i dati. Sì, devo ancora includere un ORDER BY, ma almeno è statico. Ecco cosa ho fatto:

--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; 

Spero che questo aiuti.

0

È necessario creare ROW_NUMBER() ordine per colonna che si desidera ordinare. Ordina direttamente nella selezione, viene ignorato quando viene eseguito l'inserimento.

 
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 Name, 
     ROW_NUMBER() OVER (ORDER BY MyTable.SortOrder) AS SortOrder 
INTO #Result 
FROM #MyTable AS MyTable 
ORDER BY SortOrder 

SELECT * FROM #Result 

DROP TABLE #MyTable 
DROP TABLE #Result