Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Tabellenwertfunktion – Sortieren nach wird in der Ausgabe ignoriert

An Ihrem ursprünglichen Ansatz waren zwei Dinge falsch.

  1. Beim Einfügen in die Tabelle war nie garantiert, dass der ORDER BY auf INSERT ... SELECT ... ORDER BY wäre die Reihenfolge, in der die Zeilen tatsächlich eingefügt wurden.
  2. Bei der Auswahl daraus garantiert SQL Server nicht, dass SELECT ohne ORDER BY gibt die Zeilen ohnehin in einer bestimmten Reihenfolge zurück, z. B. in der Reihenfolge der Einfügungen.

Im Jahr 2012 sieht es so aus, als ob sich das Verhalten bezüglich Punkt 1 geändert hat. Es ignoriert nun generell den ORDER BY auf SELECT -Anweisung, die die Quelle für ein INSERT ist

DECLARE @T TABLE(number int)

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

2008-Plan

2012-Plan

Der Grund für die Verhaltensänderung liegt darin, dass SQL Server in früheren Versionen einen Plan erstellt hat, der zwischen Ausführungen mit SET ROWCOUNT 0 geteilt wurde (aus) und SET ROWCOUNT N . Der Sortieroperator war nur dazu da, die korrekte Semantik sicherzustellen, falls der Plan von einer Sitzung mit einem ROWCOUNT ungleich Null ausgeführt wurde einstellen. Die TOP links davon ist ein ROWCOUNT TOP .

SQL Server 2012 erstellt jetzt separate Pläne für die beiden Fälle, sodass diese nicht zu ROWCOUNT 0 hinzugefügt werden müssen Version des Plans.

Eine Sortierung kann 2012 noch im Plan erscheinen, wenn der SELECT hat ein explizites TOP definiert (anders als TOP 100 PERCENT ), aber dies garantiert immer noch nicht die tatsächliche Einfügungsreihenfolge der Zeilen, der Plan könnte dann eine andere Sortierung nach TOP N haben wird eingerichtet, um die Zeilen zum Beispiel in die Clustered-Index-Reihenfolge zu bringen.

Für das Beispiel in Ihrer Frage würde ich einfach den Aufrufcode anpassen, um ORDER BY name anzugeben wenn es das erfordert.

Zu Ihrer sort_id Idee von Ordnen von Garantien in SQL Server es ist beim Einfügen in eine Tabelle mit IDENTITY gewährleistet dass die Reihenfolge, in der diese zugewiesen werden, der ORDER BY entspricht Sie könnten also auch

tun
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 

aber Sie müssten trotzdem nach der sort_id sortieren in Ihren Auswahlabfragen, da es ohne diese keine garantierte Sortierung gibt (vielleicht diese sort_id Dieser Ansatz kann nützlich sein, wenn die ursprünglichen Spalten, die zum Sortieren verwendet wurden, nicht in die Tabellenvariable kopiert werden)