我已經有過類似的問題,並發現,如果範圍需要是連續的,最好的辦法是廢除範圍的結束日期,並計算這爲下一步的開始日期。然後,如果需要的話創建一個視圖如下:
SELECT FromDate,
( SELECT DATEADD(DAY, -1, MIN(DateFrom))
FROM YourTable b
WHERE b.FromDate > a.FromDate
) [ToDate],
Value
FROM YourTable a
這確保了2個範圍,不能交叉,但並不一定保證沒有工作插入時需要得到想要的結果,但它應該是更容易維護和與存儲開始日期和結束日期相比,錯誤的範圍更小。
附錄
有一次,我寫出來的是,我意識到它不會提高可維護性很多工作要做,廢除了DateTo
領域的下方,但仍需要驗證了相當數量的代碼,但無論如何,我會這麼做。
DECLARE @T table (DateFrom DATE, Value INT)
INSERT INTO @T VALUES ('20120101', 10), ('20120202', 15), ('20120207', 12), ('20120211', 15)
DECLARE @NewFrom DATE = '20120209',
@NewTo DATE = '20120210',
@NewValue INT = 8
-- SHOW INITIAL VALUES FOR DEMONSTATIVE PURPOSES --
SELECT DateFrom,
ISNULL(( SELECT DATEADD(DAY, -1, MIN(DateFrom))
FROM @t b
WHERE b.DateFrom > a.DateFrom
), CAST(GETDATE() AS DATE)) [DateTo],
Value
FROM @t a
ORDER BY DateFrom
;WITH CTE AS
( SELECT DateFrom,
( SELECT DATEADD(DAY, -1, MIN(DateFrom))
FROM @t b
WHERE b.DateFrom > a.DateFrom
) [DateTo],
Value
FROM @t a
),
MergeCTE AS
( SELECT @NewFrom [DateFrom], @NewValue [Value], 'INSERT' [RowAction]
WHERE @NewFrom < @NewTo -- ENSURE A VALID RANGE IS ENTERED
UNION ALL
-- INSERT A ROW WHERE THE NEW DATE TO SLICES AN EXISTING PERIOD
SELECT DATEADD(DAY, 1, @NewTo), Value, 'INSERT'
FROM CTE
WHERE @NewTo BETWEEN DateFrom AND DateTo
UNION ALL
-- DELETE ALL ENTRIES STARTING WITHIN THE DEFINED PERIOD
SELECT DateFrom, Value, 'DELETE'
FROM CTE
WHERE DateFrom BETWEEN @NewFrom AND @NewTo
)
MERGE INTO @t t USING MergeCTE c ON t.DateFrom = c.DateFrom AND t.Value = c.Value
WHEN MATCHED AND RowAction = 'DELETE' THEN DELETE
WHEN NOT MATCHED THEN INSERT VALUES (c.DateFrom, c.Value);
SELECT DateFrom,
ISNULL(( SELECT DATEADD(DAY, -1, MIN(DateFrom))
FROM @t b
WHERE b.DateFrom > a.DateFrom
), CAST(GETDATE() AS DATE)) [DateTo],
Value
FROM @t a
ORDER BY DateFrom
我不明白這個邏輯。你能更具體嗎? – Diego 2012-02-27 10:57:07
我懷疑在這裏有很多邊界情況需要考慮 - 一個新行可以有一個完全相同的From/To作爲現有行,並將其全部替換?如果它完全覆蓋多行呢?我認爲它可以跨越兩個現有的範圍? – 2012-02-27 11:24:15
日期範圍必須表示一個時間序列,兩個範圍不能相互跨越。 – AngeloBad 2012-02-27 11:27:13