13

スナップショットが示すように、SQL Server 2012 にテーブルがあります。

ここに画像の説明を入力

次に、Last_Value() と First Value を使用して、異なる YearMonth の各 EmpID の AverageAmount を取得しています。スクリプトは次のとおりです。

SELECT A.EmpID,  
       First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS  '200901AvgAmount', 
       Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS '201112AvgAmount'

FROM  Emp_Amt  AS A

ただし、このクエリの結果は次のとおりです。

結果

「201112AvgAmount」の列には、EmpID ごとに異なる値が表示されますが、「200901AvgAmount」には正しい値が表示されます。

SQL スクリプトに何か問題がありますか? 私はオンラインで多くの調査を行いましたが、まだ答えを見つけることができません....

4

3 に答える 3

21

動作を説明する簡単なクエリを次に示します。

select 
  v,

  -- FIRST_VALUE() and LAST_VALUE()
  first_value(v) over(order by v) f1,
  first_value(v) over(order by v rows between unbounded preceding and current row) f2,
  first_value(v) over(order by v rows between unbounded preceding and unbounded following) f3,
  last_value (v) over(order by v) l1,
  last_value (v) over(order by v rows between unbounded preceding and current row) l2,
  last_value (v) over(order by v rows between unbounded preceding and unbounded following) l3,

  -- For completeness' sake, let's also compare the above with MAX()
  max        (v) over() m1,
  max        (v) over(order by v) m2,
  max        (v) over(order by v rows between unbounded preceding and current row) m3,
  max        (v) over(order by v rows between unbounded preceding and unbounded following) m4
from (values(1),(2),(3),(4)) t(v)

上記のクエリの出力は、ここで確認できます ( SQLFiddle here )。

| V | F1 | F2 | F3 | L1 | L2 | L3 | M1 | M2 | M3 | M4 |
|---|----|----|----|----|----|----|----|----|----|----|
| 1 |  1 |  1 |  1 |  1 |  1 |  4 |  4 |  1 |  1 |  4 |
| 2 |  1 |  1 |  1 |  2 |  2 |  4 |  4 |  2 |  2 |  4 |
| 3 |  1 |  1 |  1 |  3 |  3 |  4 |  4 |  3 |  3 |  4 |
| 4 |  1 |  1 |  1 |  4 |  4 |  4 |  4 |  4 |  4 |  4 |

ORDER BY節を取るウィンドウ関数に適用される暗黙的なフレームについて考える人はほとんどいません。この場合、ウィンドウはデフォルトで frame になりRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWます。(RANGE は ROWS とまったく同じではありませんが、それは別の話です)。次のように考えてください。

  • v = 1順序付けられたウィンドウのフレーム スパンを持つ行v IN (1)
  • v = 2順序付けられたウィンドウのフレーム スパンを持つ行v IN (1, 2)
  • v = 3順序付けられたウィンドウのフレーム スパンを持つ行v IN (1, 2, 3)
  • v = 4順序付けられたウィンドウのフレーム スパンを持つ行v IN (1, 2, 3, 4)

その動作を防ぎたい場合は、次の 2 つのオプションがあります。

  • 順序付きウィンドウ関数に明示的なROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING句を使用する
  • ORDER BYそれらを省略することができるウィンドウ関数では句を使用しないでください ( as MAX(v) OVER())

およびについての詳細は、この記事で説明されています。LEAD()LAG()FIRST_VALUE()LAST_VALUE()

于 2014-11-07T17:09:05.983 に答える
15

スクリプトに問題はありません。これは、SQL サーバーでパーティショニングがどのように機能するかです:/. LAST_VALUE を MAX に変更すると、結果は同じになります。解決策は次のとおりです。

SELECT A.EmpID,  
       First_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey asc) AS  '200901AvgAmount', 
       Last_Value(A.AverageAmount) OVER (PARTITION BY A.EmpID Order by A.DimYearMonthKey ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS '201112AvgAmount'  
FROM  Emp_Amt  AS A

それについてのすばらしい投稿があります。GL!

于 2013-03-13T15:53:01.897 に答える