ウィンドウ集計関数で RANGE オプションを使用すると、SQL Server 2012 で興味深い動作が発生します。これがバグなのか、SQL Server 2012 の「機能」なのかわかりません。次のように定義されたテーブルがあります。
CREATE TABLE [Test].[Trades](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Member] [varchar](20) NOT NULL,
[TradeDate] [date] NOT NULL,
[Fund] [varchar](4) NOT NULL,
[Units] [decimal](28, 8) NOT NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)
);
このテーブルには、メンバーが特定の取引日にファンドで行った取引が格納されます。メンバーは、特定の日に特定のファンドで 1 回以上の取引を行うことができます。クラスター化インデックスに加えて、次のように定義された非クラスター化インデックスがあります。
CREATE NONCLUSTERED INDEX [Ix_TradesIndex] ON [Test].[Trades]
(
[Member] ASC,
[Fund] ASC,
[TradeDate] ASC
)
INCLUDE ([Units]);
データ セットをクエリして、各メンバーが各ファンドで保有しているユニットの現在の合計を取得したい場合は、SQL Server 2012 のウィンドウ集計の拡張機能を使用して、次のように質問に答えることができます。
SELECT T.Member, T.Fund, T.TradeDate,
SUM(T.Units) OVER(PARTITION BY T.Member, T.Fund
ORDER BY T.TradeDate
RANGE BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) AS TotalShares
FROM Test.Trades AS T;
これにより、以下のようなデータ セットが得られます (例は、2005 年 2 月 3 日に Fund2 で 1 回以上の取引を行ったメンバーを示しています)。
....
メンバー 1、ファンド 1、2005 年 3 月 31 日、0.00
メンバー1、ファンド2、2005-02-03、3256.50
メンバー1、ファンド2、2005-02-03、3256.50
....
RANGE オプションは、注文句が一意でない場合 (つまり、特定のメンバーが特定の取引日に特定のファンドで複数の取引を行った場合)、ウィンドウが範囲の上部にあるすべての重複行を含むことを保証します。これは期待どおりに正しく機能しています。ただし、「このセットから個別の行のみを提供してください」(つまり、重複するエントリを削除する) と言いたい場合、この質問をする 1 つの方法は次のとおりです。
SELECT DISTINCT T.Member, T.Fund, T.TradeDate, T.TotalShares
FROM
(
SELECT T.Member, T.Fund, T.TradeDate,
SUM(T.Units) OVER(PARTITION BY T.Member, T.Fund
ORDER BY T.TradeDate
RANGE BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) AS TotalShares
FROM Test.Trades AS T
) AS T;
ここで興味深いことに、私が見ているのは、大規模なデータセットで計画が並行して行われた場合、結果のセットが非決定論的であるということです (つまり、クエリが間違った答えを返し、クエリが返す行数が後続の実行で変わる可能性があります)。クエリの)。 計画が並行に進まない場合(OPTION(MAXDOP 1) を指定することで明らかに強制できます)、クエリは常に同じ数の行を返し、結果セットが「正しい」場合は結果セットを返します。私には、これは SQL Server 2012 のバグのように感じます。
私の質問は、「<strong>誰かがこの動作について別の説明を持っていますか?それともこれはバグですか?」</p>