我们正在从SQL Server 2008迁移到SQL Server 2012,并立即注意到我们所有的表值函数都不再以正确排序的顺序提供临时表内容。
CODE:
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**
在SQL Server 2008中,此函数返回按名称排序的客户。在SQL Server 2012中,它返回未排序的表。 SQL 2012中将忽略“order by”。
我们是否必须重新编写所有函数以包含sort_id
,然后在主应用程序中调用它们时对它们进行排序还是有一个简单的修复方法?
答案 0 :(得分:27)
您的原始方法存在两个问题。
ORDER BY
上的INSERT ... SELECT ... ORDER BY
将是实际插入行的顺序。SELECT
的{{1}}将以任何特定顺序返回行,例如插入顺序。在2012年,看起来行为已经相对于第1项发生了变化。它现在通常忽略了作为ORDER BY
来源的ORDER BY
语句中的SELECT
INSERT
行为更改的原因是,在以前的版本中,SQL Server生成了一个在DECLARE @T TABLE(number int)
INSERT INTO @T
SELECT number
FROM master..spt_values
ORDER BY name
(关闭)和SET ROWCOUNT 0
的执行之间共享的计划。排序运算符仅用于确保计划由具有非零SET ROWCOUNT N
集的会话运行时的正确语义。左侧的ROWCOUNT
运算符为ROWCOUNT TOP
。
SQL Server 2012现在为这两种情况生成单独的计划,因此无需将这些计划添加到计划的TOP
版本中。
如果ROWCOUNT 0
定义了明确SELECT
(TOP
除外),则排序可能仍会出现在2012年的计划中,但这仍不能保证行的实际插入顺序然后,在建立TOP 100 PERCENT
之后,计划可能会有另一种排序,例如将行转换为聚簇索引顺序。
对于您问题中的示例,我只是调整调用代码以指定TOP N
,如果这是它所需要的。
关于Ordering guarantees in SQL Server来自{{3}}的ORDER BY name
想法,在插入sort_id
的表时,保证按照IDENTITY
分配这些订单,这样您就可以也做
ORDER BY
但是您仍然需要在选择查询中按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
订购,因为没有保证排序(可能这种sort_id
方法在原始列用于的情况下可能很有用排序没有被复制到表变量中)
答案 1 :(得分:3)
将名为rowno的列添加到@Customer表
INSERT INTO @Customer
SELECT ROW_NUMBER()over(order by Name)rowno,Customer_ID, Name,
CASE
WHEN Expiry_Date < GETDATE() then 1
WHEN Expired = 1 then 1
ELSE 0
END
from Customer