24

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**

SQL Server 2008 では、この関数は名前で並べ替えられた顧客を返します。SQL Server 2012 では、並べ替えられていないテーブルが返されます。SQL 2012 では、"order by"は無視されます。

すべての関数を a を含むように書き直してsort_id、メイン アプリケーションで呼び出されたときに並べ替える必要がありますか、それとも簡単な修正方法はありますか??

4

2 に答える 2

37

元のアプローチには 2 つの問題がありました。

  1. テーブルへの挿入時に、行が実際に挿入された順序になることORDER BYは保証されませんでした。INSERT ... 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

2008年計画

2008年計画

2012年計画

2012年計画

動作が変更された理由は、以前のバージョンの SQL Server では、SET ROWCOUNT 0(off) とSET ROWCOUNT N. ソート演算子は、プランがゼロ以外のROWCOUNTセットでセッションによって実行された場合に正しいセマンティクスを保証するためだけにありました。そのTOP左側の演算子はROWCOUNT TOP.

ROWCOUNT 0SQL Server 2012 では、2 つのケースに対して個別の計画が作成されるようになったため、これらを計画のバージョンに追加する必要はありません。

SELECTが明示的にTOP定義されている場合 ( 以外) 、2012 年の計画にも並べ替えが表示されることがありますが、それでも行TOP 100 PERCENTの実際の挿入順序は保証されません。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 

ただし、それsort_idなしでは順序付けが保証されないため、選択クエリで順序付けする必要があります (おそらくsort_id、順序付けに使用される元の列がテーブル変数にコピーされていない場合に、このアプローチが役立つ場合があります)。

于 2012-06-27T17:34:45.697 に答える
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 
于 2012-06-27T08:29:18.363 に答える