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

Tan*_*ven 24 sql sql-server sql-order-by sql-server-2012

我们正在从SQL Server 2008迁移到SQL Server 2012,并立即注意到我们所有的表值函数都不再以正确排序的顺序提供临时表内容.

码:

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**
Run Code Online (Sandbox Code Playgroud)

在SQL Server 2008中,此函数返回按名称排序的客户.在SQL Server 2012中,它返回未排序的表.在"排序依据" 2012年SQL被忽略.

我们是否必须重新编写所有函数以包含a sort_id,然后在主应用程序中调用它们时对它们进行排序或是否有一个简单的修复?

Mar*_*ith 34

你的原始方法有两个问题.

  1. 在插入表中它从未被保证了ORDER BYINSERT ... SELECT ... ORDER BY将是该行实际上是插入的顺序.
  2. 在从中进行选择时,SQL Server并不保证SELECT不会ORDER BY以任何特定顺序返回行,例如插入顺序.

在2012年,看起来好像行为已经改变了第1项.它现在通常忽略了作为一个来源ORDER BYSELECT声明INSERT

DECLARE @T TABLE(number int)

INSERT INTO @T 
SELECT number
FROM master..spt_values
ORDER BY name
Run Code Online (Sandbox Code Playgroud)

2008年计划

2008年计划

2012年计划

2012年计划

更改行为的原因是,在以前的版本中,SQL Server生成了一个在执行与SET ROWCOUNT 0(off)和之间共享的计划SET ROWCOUNT N.排序运算符仅用于确保计划由具有非零ROWCOUNT集的会话运行时的正确语义.TOP左边的操作员是a ROWCOUNT TOP.

SQL Server 2012现在为这两种情况生成单独的计划,因此无需将这些ROWCOUNT 0计划添加到计划的版本中.

如果SELECT具有明确TOP定义的(TOP 100 PERCENT但不是)但是仍然不能保证行的实际插入顺序,则计划中的排序可能仍会出现在2012年的计划中,然后计划可能在TOP N建立之后具有另一种排序以将行转换为集群索引顺序例如.

对于您问题中的示例,我只需调整调用代码以指定ORDER BY name它是否符合要求.

关于您在SQL Server中的订购保证sort_id想法,当插入到表中时,保证这些订单的顺序是按照这样的顺序,所以你也可以这样做IDENTITYORDER 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 
Run Code Online (Sandbox Code Playgroud)

但是你仍然需要sort_id在你选择的查询中进行排序,因为没有这个没有保证的顺序(也许这种sort_id方法在用于排序的原始列没有被复制到表变量的情况下可能是有用的)

  • +1我总是认为在`INSERT`期间忽略了`ORDER BY`.知道这不是具有"IDENTITY"列的情况是有用的. (3认同)