次のようなテーブルがあるとします。
declare @periods table (
s date,
e date,
t tinyint
);
開始日順に並べられたギャップのない日付間隔
insert into @periods values
('2013-01-01' , '2013-01-02', 3),
('2013-01-02' , '2013-01-04', 1),
('2013-01-04' , '2013-01-05', 1),
('2013-01-05' , '2013-01-06', 2),
('2013-01-06' , '2013-01-07', 2),
('2013-01-07' , '2013-01-08', 2),
('2013-01-08' , '2013-01-09', 1);
すべての日付間隔には異なるタイプ (t) があります。
他のタイプの間隔によって分割されていない同じタイプの日付間隔を組み合わせる必要があります (すべての間隔を開始日順に並べます)。
したがって、結果テーブルは次のようになります。
s | e | t
------------|------------|-----
2013-01-01 | 2013-01-02 | 3
2013-01-02 | 2013-01-05 | 1
2013-01-05 | 2013-01-08 | 2
2013-01-08 | 2013-01-09 | 1
カーソルなしでこれを行う方法はありますか?
私は1つの実用的な解決策を持っています:
declare @periods table (
s datetime primary key clustered,
e datetime,
t tinyint,
period_number int
);
insert into @periods (s, e, t) values
('2013-01-01' , '2013-01-02', 3),
('2013-01-02' , '2013-01-04', 1),
('2013-01-04' , '2013-01-05', 1),
('2013-01-05' , '2013-01-06', 2),
('2013-01-06' , '2013-01-07', 2),
('2013-01-07' , '2013-01-08', 2),
('2013-01-08' , '2013-01-09', 1);
declare @t tinyint = null;
declare @PeriodNumber int = 0;
declare @anchor date;
update @periods
set period_number = @PeriodNumber,
@PeriodNumber = case
when @t <> t
then @PeriodNumber + 1
else
@PeriodNumber
end,
@t = t,
@anchor = s
option (maxdop 1);
select
s = min(s),
e = max(e),
t = min(t)
from
@periods
group by
period_number
order by
s;
しかし、UPDATEステートメントのそのような動作に頼ることができるかどうか疑問に思いますか?
SQL Server 2008 R2 を使用しています。
編集:
ダニエルとこの記事に感謝します: http://www.sqlservercentral.com/articles/T-SQL/68467/
上記のソリューションで見落とされていた 3 つの重要な点が見つかりました。
- テーブルにクラスター化インデックスが必要です
- クラスター化された列のアンカー変数と呼び出しが必要です
- 更新ステートメントは 1 つのプロセッサで実行する必要があります。つまり、並列処理は使用しません。
これらのルールに従って、上記のソリューションを変更しました。