7

同じ SELECT ステートメントの前の n 行の列に基づいて、SELECT ステートメントに移動平均列を作成しようとしています。必要な平均は、結果セットの前の n 行に基づいています。

説明させてください

Id        Number       Average
 1             1          NULL
 2             3          NULL
 3             2          NULL
 4             4             2 <----- Average of (1, 3, 2),Numbers from previous 3 rows
 5             6             3 <----- Average of (3, 2, 4),Numbers from previous 3 rows
 .             .             .
 .             .             .

前の行がないため、Average 列の最初の 3 行は null です。Average 列の 4 行目は、前の 3 行の Number 列の平均を示しています。

これを実行する SQL Select ステートメントを作成しようとして、助けが必要です。

4

7 に答える 7

2

単純な自己結合は、サブクエリを参照する行よりもはるかに優れたパフォーマンスを発揮するようです

10,000 行のテスト データを生成します。

drop table test10k
create table test10k (Id int, Number int, constraint test10k_cpk primary key clustered (id))

;WITH digits AS (
    SELECT 0 as Number
    UNION SELECT 1
    UNION SELECT 2
    UNION SELECT 3
    UNION SELECT 4
    UNION SELECT 5
    UNION SELECT 6
    UNION SELECT 7
    UNION SELECT 8
    UNION SELECT 9
)
,numbers as (
    SELECT 
        (thousands.Number * 1000) 
        + (hundreds.Number * 100) 
        + (tens.Number * 10) 
        + ones.Number AS Number
    FROM digits AS ones 
    CROSS JOIN digits AS tens
    CROSS JOIN digits AS hundreds
    CROSS JOIN digits AS thousands
)
insert test10k (Id, Number)
select Number, Number
from numbers 

最初の 3 行の特殊なケースをメイン クエリから引き出します。行セットに本当に必要な場合は、それらを UNION ALL に戻すことができます。自己結合クエリ:

;WITH   NumberedRows
AS
(
    SELECT  rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
    FROM    test10k rta
)

SELECT  nr.ID, nr.Number,
    avg(trailing.Number) as MovingAverage
FROM    NumberedRows nr
    join NumberedRows as trailing on trailing.RowNumber between nr.RowNumber-3 and nr.RowNumber-1
where nr.Number > 3
group by nr.id, nr.Number

私のマシンでは、これには約 10 秒かかります。Aaron Alton が示したサブクエリ アプローチは、約 45 秒かかります (テスト ソース テーブルを反映するように変更した後)。

;WITH   NumberedRows
AS
(
    SELECT  rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
    FROM    test10k rta
)
SELECT  nr.ID, nr.Number,
    CASE
            WHEN nr.RowNumber <=3 THEN NULL
            ELSE (  SELECT  avg(Number) 
                            FROM    NumberedRows 
                            WHERE   RowNumber < nr.RowNumber
                            AND             RowNumber >= nr.RowNumber - 3
                    )
    END AS MovingAverage
FROM    NumberedRows nr

SET STATISTICS PROFILE ON を実行すると、自己結合がテーブル スプールで 10k 実行されていることがわかります。サブクエリには、フィルター、集計、およびその他のステップで 10,000 回の実行があります。

于 2009-05-26T20:04:50.133 に答える
0

または、事前に計算された実行中の値を非正規化して保存することもできます。ここで説明します:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/23/denormalizing-to-enforce-business-rules-running-totals.aspx

選択のパフォーマンスは、それが進むのと同じくらい高速です。もちろん、変更は遅くなります。

于 2009-05-26T18:43:47.007 に答える