@Alex Wのクエリが機能しませんでした。それは標準のSQLではないので、SQL Serverと互換性を持たせるためには多くの書き換えが必要でした(これは私がテストすることができます)。しかし、それは私にいくつかのインスピレーションを与えてくれました。
途切れない待機のすべての期間のすべての開始点を探す:
SELECT DISTINCT
t1.ID,
t1.d1 AS date,
-DATEDIFF(DAY, (SELECT MIN(d1) FROM Orders), t1.d1) AS n
FROM Orders t1
LEFT JOIN Orders t2 -- Join for any events occurring while this
ON t2.ID = t1.ID -- is starting. If this is a start point,
AND t2.d1 <> t1.d1 -- it won't match anything, which is what
AND t1.d1 BETWEEN t2.d1 AND t2.d2 -- we want.
GROUP BY t1.ID, t1.d1, t1.d2
HAVING COUNT(t2.ID) = 0
とエンドポイントの等価:
SELECT DISTINCT
t1.ID,
t1.d2 AS date,
DATEDIFF(DAY, (SELECT MIN(d1) FROM Orders), t1.d2) AS n
FROM Orders t1
LEFT JOIN Orders t2
ON t2.ID = t1.ID
AND t2.d2 <> t1.d2
AND t1.d2 BETWEEN t2.d1 AND t2.d2
GROUP BY t1.ID, t1.d1, t1.d2
HAVING COUNT(t2.ID) = 0
n
は、いくつかの共通からの日数ですある時点。開始点は負の値を持ち、終点は正の値を持ちます。これは、それらを追加して、その間の日数を取得できるようにするためです。
span = end - start
span = end + (-start)
span1 + span2 = end1 + (-start1) + end2 + (-start2)
最後に、私たちは物事を追加する必要があります。
SELECT ID, SUM(n) AS hold_days
FROM (
SELECT DISTINCT
t1.id,
t1.d1 AS date,
-DATEDIFF(DAY, (SELECT MIN(d1) FROM Orders), t1.d1) AS n
FROM Orders t1
LEFT JOIN Orders t2
ON t2.ID = t1.ID
AND t2.d1 <> t1.d1
AND t1.d1 BETWEEN t2.d1 AND t2.d2
GROUP BY t1.ID, t1.d1, t1.d2
HAVING COUNT(t2.ID) = 0
UNION ALL
SELECT DISTINCT
t1.id,
t1.d2 AS date,
DATEDIFF(DAY, (SELECT MIN(d1) FROM Orders), t1.d2) AS n
FROM Orders t1
LEFT JOIN Orders t2
ON t2.ID = t1.ID
AND t2.d2 <> t1.d2
AND t1.d2 BETWEEN t2.d1 AND t2.d2
GROUP BY t1.ID, t1.d1, t1.d2
HAVING COUNT(t2.ID) = 0
ORDER BY ID, date
) s
GROUP BY ID;
入力テーブル(受注):
ID d1 d2
1 2011-08-01 2011-08-08
1 2011-08-02 2011-08-06
1 2011-08-03 2011-08-10
1 2011-08-12 2011-08-14
2 2011-08-01 2011-08-03
2 2011-08-02 2011-08-06
2 2011-08-05 2011-08-09
が出力:
ID hold_days
1 11
2 8
または、ストアドプロシージャでこれを行うこともできます。
CREATE PROCEDURE CalculateHoldTimes
@ID int = 0
AS
BEGIN
DECLARE Events CURSOR FOR
SELECT *
FROM (
SELECT d1 AS date, 1 AS diff
FROM Orders
WHERE ID = @ID
UNION ALL
SELECT d2 AS date, -1 AS diff
FROM Orders
WHERE ID = @ID
) s
ORDER BY date;
DECLARE @Events_date date,
@Events_diff int,
@Period_start date,
@Period_accum int,
@Total_start date,
@Total_count int;
OPEN Events;
FETCH NEXT FROM Events
INTO @Events_date, @Events_diff;
SET @Period_start = @Events_date;
SET @Period_accum = 0;
SET @Total_start = @Events_date;
SET @Total_count = 0;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Period_accum = @Period_accum + @Events_diff;
IF @Period_accum = 1 AND @Events_diff = 1
-- Start of period
SET @Period_start = @Events_date;
ELSE IF @Period_accum = 0 AND @Events_diff = -1
-- End of period
SET @Total_count = @Total_count +
DATEDIFF(day, @Period_start, @Events_date);
FETCH NEXT FROM Events
INTO @Events_date, @Events_diff;
END;
SELECT
@Total_start AS d1,
@Events_date AS d2,
@Total_count AS hold_time;
END;
でそれを呼び出します
EXEC CalculateHoldTimes 1;
私は持っていますが、補助的なカレンダーテーブルの左の結合が役立つかもしれません。 –
[可能性のある日付のセットのギャップを見つけるための良い方法は何ですか?](http://stackoverflow.com/questions/4765495/what-is-a-good-way-to-find-gaps-in) -a-set-of-datespans) –
@Brian、この質問は大きく異なります。 OP、クエリを支援するビューを追加できますか? –