web-dev-qa-db-ja.com

派生テーブルのSQL Server ROW_NUMBER()OVER()の計算

他の一部のデータベース(DB2、またはROWNUMを使用したOracleなど)では、ランキング関数のOVER()句でORDER BY句を省略できます。例えば:

ROW_NUMBER() OVER()

これは、次のような順序付けられた派生テーブルで使用する場合に特に便利です。

SELECT t.*, ROW_NUMBER() OVER()
FROM (
    SELECT ...
    ORDER BY
) t

SQL Serverでこれをどのようにエミュレートできますか?私は thistrick を使用している人々を見つけましたが、それは派生テーブルからの順序に関して非決定的に動作するため、それは誤りです:

-- This order here ---------------------vvvvvvvv
SELECT t.*, ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (
    SELECT TOP 100 PERCENT ...
    -- vvvvv ----redefines this order here
    ORDER BY
) t

具体的な例( SQLFiddle で確認できます):

SELECT v, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM (
  SELECT TOP 100 PERCENT 1 UNION ALL
  SELECT TOP 100 PERCENT 2 UNION ALL
  SELECT TOP 100 PERCENT 3 UNION ALL
  SELECT TOP 100 PERCENT 4
  -- This descending order is not maintained in the outer query
  ORDER BY 1 DESC
) t(v)

また、私の場合、派生テーブルの式を再利用してORDER BY句を再現することはできません。派生テーブルは、外部ロジックによって提供される可能性があるため、利用できない場合があるためです。

それでは、どうすればよいですか?できますか?

12
Lukas Eder

Row_Number() OVER (ORDER BY (SELECT 1))トリックは[〜#〜]しない[〜#〜]を、順序の変更を回避する方法と見なす必要があります基礎となるデータ。これは、サーバーに不要な並べ替えを実行させないようにするための手段にすぎません(並べ替えを実行することはできますが、列による並べ替えと比較すると、可能な限り最小限のコストがかかります)。

SQLサーバーのすべてのクエリ絶対に必須最外部のクエリにORDER BY句があり、結果が保証された方法で確実に順序付けされます。

「元の順序を保持する」という概念は、リレーショナルデータベースには存在しません。テーブルとクエリは、最も外側のクエリでORDER BY句が指定されない限り、常に順序付けなしと見なす必要があります。

同じ順序付けされていないクエリを100,000回試行し、常に同じ順序で受け取ることができるため、その順序に依存できると信じることができます。しかし、それは間違いです。ある日、何かが変化し、期待した順序にならないからです。 1つの例は、データベースが新しいバージョンのSQL Serverにアップグレードされた場合です。これにより、多くのクエリでその順序が変更されました。しかし、それほど大きな変化である必要はありません。インデックスを追加または削除するだけでも違いが生じる可能性があります。その他:サービスパックのインストール。テーブルの分割。問題のテーブルを含むインデックス付きビューを作成します。シークではなくスキャンが選択される転換点に到達する。等々。

「サーバー、ORDER BY」と言っていない限り、注文の結果に依存しないでください。

10
ErikE