2011-07-13 9 views
4

簡略化のため、ItemIDStartDate、およびEndDateの項目の一覧を含む項目テーブルがあります。日付範囲の未処理アイテムのSQLグループ化と実行中の合計

ItemID  StartDate  EndDate 
1   1/1/2011  1/15/2011 
2   1/2/2011  1/14/2011 
3   1/5/2011  1/17/2011 
... 

私の目標は、日付の順次リストでテーブルにこのテーブルに参加 し、累積的に開かれているどのように多くの項目も特定の日に開いており、両方の項目数を言うことができるようにすることです。

Date  ItemsOpened  CumulativeItemsOpen 
1/1/2011 1    1 
1/2/2011 1    2 
... 

私は、これはWHILEループ、 で行われるだろうが、それがパフォーマンスに影響を持っているかを見ることができます。私はどのように これは、セットベースのアプローチで行うことができますか?

+1

をすることができますItemsOpenedとItemsOpenedCumulativeの意味を再定義してください。 ItemsOpened = "この日付に開かれたアイテムの数"とItemsOPenedCumulative = "現在開いているアイテムの数"という回答を受け入れました。私はそれが間違っている場合私の答えを削除したいと思います –

+0

良い点;私の列の名前は混乱の余地を残しました。 "現在開いているアイテムの数"は私が探していたものです。 – mg1075

+0

累積列またはItemsOpened列を参照していますか?おかげで –

答えて

2
SELECT COUNT(CASE WHEN d.CheckDate = i.StartDate THEN 1 ELSE NULL END) 
     AS ItemsOpened 
    , COUNT(i.StartDate) 
     AS ItemsOpenedCumulative 
FROM Dates AS d 
    LEFT JOIN Items AS i 
    ON d.CheckDate BETWEEN i.StartDate AND i.EndDate 
GROUP BY d.CheckDate 
2

これはあなたが望むものを

SELECT DATE, 
    SUM(ItemOpened) AS ItemsOpened, 
    COUNT(StartDate) AS ItemsOpenedCumulative 
FROM 
    (
    SELECT d.Date, i.startdate, i.enddate, 
     CASE WHEN i.StartDate = d.Date THEN 1 ELSE 0 END AS ItemOpened 
    FROM Dates d 
    LEFT OUTER JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate 
    ) AS x 
GROUP BY DATE 
ORDER BY DATE 

を与えることがありますが、これはあなたの日付の値は、DATEデータ型であることを前提としています。または、日付はDATETIMEであり、時間値はありません。

2

これは便利です。再使用部分はテーブルで置き換えることができます。それを実証するために、私はある種の日付表を埋めなければなりませんでした。ご覧のとおり、実際のSQLは短くてシンプルです。

DECLARE @i table (itemid INT, startdate DATE, enddate DATE) 

INSERT @i VALUES (1,'1/1/2011', '1/15/2011') 
INSERT @i VALUES (2,'1/2/2011', '1/14/2011') 
INSERT @i VALUES (3,'1/5/2011', '1/17/2011') 

DECLARE @from DATE 
DECLARE @to DATE 
SET @from = '1/1/2011' 
SET @to = '1/18/2011' 

-- the recusive sql is strictly to make a datelist between @from and @to 
;WITH cte(Date) 
AS ( 
SELECT @from DATE 
UNION ALL 
SELECT DATEADD(day, 1, DATE) 
FROM cte ch  
WHERE DATE < @to 
) 
SELECT cte.Date, sum(case when cte.Date=i.startdate then 1 else 0 end) ItemsOpened, count(i.itemid) ItemsOpenedCumulative 
FROM cte 
left join @i i on cte.Date between i.startdate and i.enddate 
GROUP BY cte.Date 
OPTION(MAXRECURSION 0) 
0

は、SQL Server 2005+上にある場合、あなたはこのように、ranking機能ROW_NUMBER()の追加の助けを借りて、recursiveCTEは、合計を実行している取得するために使用することができます

WITH grouped AS (
    SELECT 
    d.Date, 
    ItemsOpened = COUNT(i.ItemID), 
    rn = ROW_NUMBER() OVER (ORDER BY d.Date) 
    FROM Dates d 
    LEFT JOIN Items i ON d.Date BETWEEN i.StartDate AND i.EndDate 
    GROUP BY d.Date 
    WHERE d.Date BETWEEN @FilterStartDate AND @FilterEndDate 
), 
cumulative AS (
    SELECT 
    Date, 
    ItemsOpened, 
    ItemsOpenedCumulative = ItemsOpened 
    FROM grouped 
    WHERE rn = 1 
    UNION ALL 
    SELECT 
    g.Date, 
    g.ItemsOpened, 
    ItemsOpenedCumulative = g.ItemsOpenedCumulative + c.ItemsOpened 
    FROM grouped g 
    INNER JOIN cumulative c ON g.Date = DATEADD(day, 1, c.Date) 
) 
SELECT * 
FROM cumulative 
+0

上記の構文エラーがあると思います。 「累積AS」は単純に「累積AS」となるはずです – Karl

+0

@Karl:ありがとうございます! –

関連する問題