各文字のascii
値を評価する目的で、文字列を1行に1つずつ構成文字に効果的に分割する 簡潔なTSQLステートメント を見ました。
クエリを正しく、効果的に読み取っている場合、3つのCTEを使用して、それぞれ値が「0」の10,000行を含む1列のテーブルを準備しています。
4番目のCTEは次のように定義されます。
cteTally(n) AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) n
FROM E4
)
続いて、このCTEは、次のselect
を使用して、目的の文字列を含む列を含むテーブルに結合されます。
SELECT n, SUBSTRING(LastName, n, 1), ASCII( SUBSTRING(LastName, n, 1))
つまり、行番号n、LastNameのn番目の文字、その文字のASCII値です。
私の質問は、上記のCTEのover
句に関連しています。
基本的に、それは正確に何をしていますか?
10,000の同一行からrow_numberをクエリする場合、なぜorder by
句が必要なのですか? order by
がover
ステートメントのorder by
句としてではなくselect
句に入れられるのはなぜですか-特にover
句はtパーティションを指定しているだけですか? (これは、row_number
が動作するウィンドウが完全な10,000行であることを意味すると思いますか?)そして、select null
で並べ替えるとはどういう意味ですか?
ROW_NUMBER()はランキングウィンドウ関数であり、ランキングウィンドウ関数には必須のORDER BY句が必要です。 ORDER BYなしで記述しようとすると、構文エラーが発生します。
SELECT ROW_NUMBER() OVER()
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 4112, Level 15, State 1, Line 1
-- The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.
サブクエリのトリックは、それをブログに書いた誰かによって、パフォーマンスの最適化として発見されました。定数はORDER BY句では使用できないため、SQL Serverは常にソート操作を実行します。
SELECT ROW_NUMBER() OVER(ORDER BY NULL)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5309, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions
-- do not support constants as ORDER BY clause expressions.
また、どちらもインデックスとして扱われる整数ではありません。
SELECT ROW_NUMBER() OVER(ORDER BY 1)
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
-- Msg 5308, Level 16, State 1, Line 1
-- Windowed functions, aggregates and NEXT VALUE FOR functions
-- do not support integer indices as ORDER BY clause expressions.
コードの不具合により、なんらかの理由で許可されているサブクエリを使用してこの制限を回避し、並べ替え演算子を排除できることがわかります。
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (VALUES ('A'), ('B'), ('C')) AS X(Y);
サブクエリでは任意の定数を使用できますが、NULLはおそらくEXISTS述語内でSELECT NULLを使用する習慣を連想させます。SQLServerの初期の履歴では、*または他の列式とは対照的に、パフォーマンスに影響がありました。オプティマイザはそれを無視するほど賢くありませんでした。
HTH
[〜#〜] update [〜#〜]@ Erik-Darlingは、計算式を使用して回避することもできるとコメントしています:
You can do SELECT ROW_NUMBER() OVER (ORDER BY 1/0);
OVER句は、選択されたウィンドウ関数を適用する前に、行セットの順序(およびPARTITION BYが含まれている場合はパーティション化)を設定します。 1つのクエリで複数のウィンドウ関数を使用できるため、必要に応じてデータが返されるようにするには、それぞれに独自のパーティション化と順序付けが必要です。
この例では、ROW_NUMBER()を使用して、CTEの各行の連続する行番号を生成しています。特定の順序は必要ありませんが、ウィンドウ関数にはORDER BY句が必要なため、SELECT NULLを使用しています。
同じことを実現する別の方法は、IDENTITY列を使用することですが、これには他の影響があり、既存のテーブルまたは一時テーブルを作成する必要があります。 CTEのROW_NUMBERウィンドウ関数を使用すると、このIDをオンザフライで生成できます。
特定の質問に答えるには:
基本的に、それは正確に何をしていますか?
これは、ROW_NUMBER()ウィンドウ関数をその結果セットに適用してE4の行数と等しい行番号のリストを生成する前に、E4の行を「ランダムに」順序付けしています。 OVERは、「この順序付けとパーティション化を使用して結果セットを取得し、メインのSELECTステートメントの順序付けとは無関係に、このウィンドウ関数をその結果セットに適用(OVER)する」と解釈できます。
詳細: OVER句