2017-06-01 4 views
0

SQLの頻度列の各カウントごとに行を作成する効率的な方法について、いくつかのアイディアが必要です。 (SQL Serverの2016)T-SQLの頻度列から変更された行を作成

データ:
私が病気で呼び出さ日付の人々とテーブルを持っており、彼らがつもり欠けていたと述べた日数:

BEGIN_DATE    DAYS_SICK 
2011-01-01 00:00:00.000 3 
2011-01-01 00:00:00.000 3 
2011-01-01 00:00:00.000 1 
2011-01-02 00:00:00.000 2 
2011-01-02 00:00:00.000 3 
2011-01-04 00:00:00.000 4 
2011-01-04 00:00:00.000 4 
2011-01-04 00:00:00.000 3 

私はこれを翻訳したいです各行が1日の1日を表し、その日に病気になっている人の数を数えます。例えばので

DATE      PEOPLE_SICK 
2011-01-01 00:00:00.000 3 
2011-01-02 00:00:00.000 4 
2011-01-03 00:00:00.000 4 
2011-01-04 00:00:00.000 4 
2011-01-05 00:00:00.000 3 
2011-01-06 00:00:00.000 3 
2011-01-07 00:00:00.000 2 

  • は2011-01-01のために2、3日だけ、その日のいずれかの病気で呼び出さ病気に呼ばれる3人が、ありました。出力は3です。
  • 2011-01-02にもう1人(病人)が電話しましたが、その日から2人もいましたが、その日も逃したと言われたので、出力は4です。
  • 2011-01-03に病気になった人はいませんが、2日前から2人がいました。出力は4
  • 等...

である私は現在、必要に応じて新しいテーブルに行を追加または更新し、入力の行のそれぞれを反復処理して、周波数をループすることでこれをやっていますそれは猥褻な時間がかかります。

これをより効率的に行う方法はありますか?

答えて

1

これは週末にはまったく対応していませんが、始めることができます。また、頻繁に実行されるクエリがあった場合は、DATE DIMテーブルを作成してDates CTEの代わりに使用します。 Where I got the DATE DIM code from.

CREATE TABLE #test (ID int IDENTITY(1,1), BEGIN_DATE datetime, DAYS_SICK int); 

DECLARE @StartDate datetime = '2011-01-01' 
, @CutoffDate datetime = '2011-01-10'; 

INSERT INTO #test (BEGIN_DATE, DAYS_SICK) 
VALUES 
('2011-01-01 00:00:00.000', 3), 
('2011-01-01 00:00:00.000', 3), 
('2011-01-01 00:00:00.000', 1), 
('2011-01-02 00:00:00.000', 2), 
('2011-01-02 00:00:00.000', 3), 
('2011-01-04 00:00:00.000', 4), 
('2011-01-04 00:00:00.000', 4), 
('2011-01-04 00:00:00.000', 3); 

WITH Dates 
AS (SELECT d 
    FROM (
     SELECT d = DATEADD(DAY, rn - 1, @StartDate) 
     FROM (SELECT TOP (DATEDIFF(DAY, @StartDate, @CutoffDate)) rn = ROW_NUMBER() OVER (
        ORDER BY s1.[object_id]) 
      FROM sys.all_objects AS s1 
      CROSS JOIN sys.all_objects AS s2 
      ORDER BY s1.[object_id] 
      ) AS x 
     ) AS y 
    ) 
    ,SickRanges 
AS (
    SELECT BEGIN_DATE 
     ,DATEADD(DAY, DAYS_SICK - 1, BEGIN_DATE) END_DATE 
    FROM #test 
    ) 
SELECT d.d [DATE] 
    ,count(1) PEOPLE_SICK 
FROM SickRanges sr 
JOIN Dates d ON d.d BETWEEN sr.BEGIN_DATE AND sr.END_DATE 
GROUP BY d.d 
ORDER BY d.d 

DROP TABLE #test 
関連する問題