Er waren twee dingen mis met je oorspronkelijke aanpak.
- Bij het invoegen in de tabel werd nooit gegarandeerd dat de
ORDER BY
op deINSERT ... SELECT ... ORDER BY
zou de volgorde zijn waarin de rijen daadwerkelijk zijn ingevoegd. - Bij het selecteren ervan garandeert SQL Server niet dat
SELECT
zonder eenORDER BY
retourneert de rijen in een bepaalde volgorde, zoals de volgorde van invoegen, hoe dan ook.
In 2012 lijkt het alsof het gedrag is veranderd met betrekking tot item 1. Het negeert nu over het algemeen de ORDER BY
op de SELECT
statement dat de bron is voor een INSERT
DECLARE @T TABLE(number int)
INSERT INTO @T
SELECT number
FROM master..spt_values
ORDER BY name
2008-abonnement
Abonnement 2012
De reden voor de gedragsverandering is dat in eerdere versies SQL Server één plan produceerde dat werd gedeeld tussen uitvoeringen met SET ROWCOUNT 0
(uit) en SET ROWCOUNT N
. De sort-operator was er alleen om de juiste semantiek te garanderen in het geval dat het plan werd uitgevoerd door een sessie met een ROWCOUNT
niet nul set. De TOP
operator links ervan is een ROWCOUNT TOP
.
SQL Server 2012 produceert nu aparte plannen voor de twee gevallen, dus het is niet nodig om deze toe te voegen aan de ROWCOUNT 0
versie van het plan.
Een sortering kan in 2012 nog steeds in het plan verschijnen als de SELECT
heeft een expliciete TOP
gedefinieerd (anders dan TOP 100 PERCENT
) maar dit garandeert nog steeds niet de daadwerkelijke invoegvolgorde van rijen, het plan kan dan een andere sortering hebben na de TOP N
is ingesteld om de rijen bijvoorbeeld in geclusterde indexvolgorde te krijgen.
Voor het voorbeeld in uw vraag zou ik gewoon de aanroepcode aanpassen om ORDER BY name
op te geven als dat is wat het vereist.
Met betrekking tot uw sort_id
idee van Bestelgaranties in SQL Server
het is gegarandeerd bij het invoegen in een tabel met IDENTITY
dat de volgorde waarin deze worden toegewezen zal zijn volgens de ORDER BY
dus je zou ook kunnen doen
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
maar je zou nog steeds moeten bestellen met de sort_id
in uw selectiequery's, aangezien er geen gegarandeerde bestelling is zonder dat (misschien deze sort_id
aanpak kan handig zijn in het geval dat de originele kolommen die voor het ordenen worden gebruikt niet worden gekopieerd naar de tabelvariabele)