Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Funzione con valori di tabella - L'ordine per viene ignorato nell'output

C'erano due cose che non andavano nel tuo approccio originale.

  1. Al momento dell'inserimento nella tabella non è mai stato garantito che il ORDER BY sul INSERT ... SELECT ... ORDER BY sarebbe l'ordine in cui le righe sono state effettivamente inserite.
  2. Se si seleziona da esso, SQL Server non garantisce che SELECT senza un ORDER BY restituirà comunque le righe in un ordine particolare come l'ordine di inserzione.

Nel 2012 sembra che il comportamento sia cambiato rispetto all'articolo 1. Ora generalmente ignora il ORDER BY sul SELECT istruzione che è l'origine di un INSERT

DECLARE @T TABLE(number int)

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

Piano 2008

Piano 2012

Il motivo del cambiamento di comportamento è che nelle versioni precedenti SQL Server produceva un piano condiviso tra le esecuzioni con SET ROWCOUNT 0 (off) e SET ROWCOUNT N . L'operatore di ordinamento era presente solo per garantire la semantica corretta nel caso in cui il piano fosse eseguito da una sessione con un ROWCOUNT diverso da zero impostare. Il TOP l'operatore alla sua sinistra è un ROWCOUNT TOP .

SQL Server 2012 ora produce piani separati per i due casi, quindi non è necessario aggiungerli a ROWCOUNT 0 versione del piano.

Un ordinamento potrebbe ancora essere visualizzato nel piano nel 2012 se SELECT ha un esplicito TOP definito (diverso da TOP 100 PERCENT ) ma ciò non garantisce ancora l'ordine di inserimento effettivo delle righe, il piano potrebbe quindi avere un altro ordinamento dopo il TOP N è stabilito per ottenere le righe nell'ordine dell'indice cluster, ad esempio.

Per l'esempio nella tua domanda, regolerei semplicemente il codice chiamante per specificare ORDER BY name se è quello che richiede.

Riguardo al tuo sort_id idea da Ordinazione delle garanzie in SQL Server è garantito quando si inserisce in una tabella con IDENTITY che l'ordine a cui vengono assegnati sarà come da ORDER BY quindi potresti fare anche

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 

ma dovresti comunque ordinare tramite sort_id nelle tue query di selezione in quanto non esiste un ordinamento garantito senza quello (forse questo sort_id potrebbe essere utile nel caso in cui le colonne originali utilizzate per l'ordinamento non vengano copiate nella variabile della tabella)