表值函数 - 输出中忽略排序依据

时间:2012-06-27 08:18:11

标签: sql sql-server sql-server-2012 sql-order-by

我们正在从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,然后在主应用程序中调用它们时对它们进行排序还是有一个简单的修复方法?

2 个答案:

答案 0 :(得分:27)

您的原始方法存在两个问题。

  1. 在插入表格时,我们无法保证ORDER BY上的INSERT ... SELECT ... ORDER BY将是实际插入行的顺序。
  2. 从中选择时,SQL Server不保证没有SELECT的{​​{1}}将以任何特定顺序返回行,例如插入顺序。
  3. 在2012年,看起来行为已经相对于第1项发生了变化。它现在通常忽略了作为ORDER BY来源的ORDER BY语句中的SELECT

    INSERT

    2008年计划

    2008 plan

    2012年计划

    2012 plan

    行为更改的原因是,在以前的版本中,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定义了明确SELECTTOP除外),则排序可能仍会出现在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