手動で構築したデータ セットで FIRST_VALUE を使用すると、1 つの結果が得られます。左結合の結果であるデータ セットで使用すると、データ セットに含まれているように見えても、別の結果が得られます。まったく同じデータ値。以下の単純なデータセットで問題を再現しました。
私が何かを誤解している場合、誰かが教えてもらえますか?
この SQL は、FIRST_VALUE が NULL で LAST_VALUE が 30 であるという予期された結果を生成します。
SELECT
agroup,
aval,
FIRST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) fv,
LAST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) lv
FROM
(
SELECT 1 agroup, 10 aval
UNION ALL SELECT 1, NULL
UNION ALL SELECT 1, 30
) T
この SQL は、上記と同じデータ セットになる LEFT JOIN を使用しますが、FIRST_VALUE は NULL を無視しているように見えます。
SELECT
agroup,
aval,
FIRST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) fv,
LAST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) lv
FROM
(
SELECT
T1.agroup,
T1.akey,
T2.aval
FROM
(
SELECT 1 agroup, 1 akey
UNION ALL SELECT 1, 2
UNION ALL SELECT 1, 3
) T1
LEFT JOIN
(
SELECT 1 akey, 10 aval
UNION ALL SELECT 3,30
) T2 ON T1.akey = T2.akey
) T
また、テーブル変数と CTE を使用すると、左結合の動作が異なることも示せます。CTE を使用してデータを生成する場合、FIRST_VALUE は NULL を無視します。まったく同じ SQL を使用しますが、結果をテーブル変数または一時テーブルに入れると、NULL が考慮されます。
CTE を使用すると、SQL Server の結果には FIRST_VALUE の決定に NULL が含まれません。
WITH T AS
(
SELECT
T1.agroup,
T1.akey,
T2.aval
FROM
(
SELECT 1 agroup, 1 akey
UNION ALL SELECT 1, 2
UNION ALL SELECT 1, 3
) T1
LEFT JOIN
(
SELECT 1 akey, 10 aval
UNION ALL SELECT 3,30
) T2 ON T1.akey = T2.akey
)
SELECT
agroup,
aval,
FIRST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) fv,
LAST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) lv
FROM
T
ただし、テーブル変数を使用すると、次のようになります。
DECLARE @T TABLE (agroup INT,akey INT,aval INT)
INSERT INTO
@T
SELECT
T1.agroup,
T1.akey,
T2.aval
FROM
(
SELECT 1 agroup, 1 akey
UNION ALL SELECT 1, 2
UNION ALL SELECT 1, 3
) T1
LEFT JOIN
(
SELECT 1 akey, 10 aval
UNION ALL SELECT 3,30
) T2 ON T1.akey = T2.akey
SELECT
agroup,
aval,
FIRST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) fv,
LAST_VALUE(aval) OVER (PARTITION BY agroup ORDER BY aval ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) lv
FROM
@T