2015-11-02 29 views

回答

2

假設日期的範圍是相當窄的,一個替代方案是使用一個遞歸CTE來創建一個li在範圍內的所有日期的ST然後再加入插值到它:

WITH LastDay AS 
(
    SELECT MAX(Date_To) AS MaxDate 
    FROM MyTable 
), 
Days AS 
(
    SELECT MIN(Date_From) AS TheDate 
    FROM MyTable 

    UNION ALL 

    SELECT DATEADD(d, 1, TheDate) AS TheDate 
    FROM Days CROSS JOIN LastDay 
    WHERE TheDate <= LastDay.MaxDate 
) 
SELECT mt.Item_ID, mt.Cost_Of_Item, d.TheDate 
FROM MyTable mt 
INNER JOIN Days d 
ON d.TheDate BETWEEN mt.Date_From AND mt.Date_To; 

我還假設的那個日期從和日期來表示一個包含的範圍(即包括兩個邊緣) - 在日期上使用包容性BETWEEN是不常見的。

SqlFiddle here

編輯

在遞歸CTE SQL Server中的默認MAXRECURSION是100,這將限制在查詢日期範圍內100天的跨度。您可以將其調整爲maximum of 32767

此外,如果你要過濾只是一個小範圍的大表的日期,你可以調整CTE限制範圍內的天數:

WITH DateRange AS 
(
    SELECT CAST('2014-01-01' AS DATE) AS MinDate, 
     CAST('2014-02-16' AS DATE) AS MaxDate 
), 
Days AS 
(
    SELECT MinDate AS TheDate 
    FROM DateRange 

    UNION ALL 

    SELECT DATEADD(d, 1, TheDate) AS TheDate 
    FROM Days CROSS APPLY DateRange 
    WHERE TheDate <= DateRange.MaxDate 
) 
SELECT mt.Item_ID, mt.Cost_Of_Item, d.TheDate 
FROM MyTable mt 
INNER JOIN Days d 
ON d.TheDate BETWEEN mt.Date_From AND mt.Date_To 
OPTION (MAXRECURSION 0); 

Update Fiddle

+0

謝謝你的回答,嘗試了小提琴,工作得很好,在我的服務器上試過......沒有那麼多...忘了說這個表是2mill記錄長,當執行代碼時我得到了一個530錯誤。努力更好地瞭解您的查詢,看看我能否修復它。 – dhuesca

+0

看起來數據中的日期範圍大於100天 - 我已經更新了一些更多的想法。 – StuartLC

+0

感謝您的更新,它可以根據需要運行。 – dhuesca

0

您可以生成一個增量表,並將其加入到你的日期從:

查詢:

With inc(n) as (
    Select ROW_NUMBER() over (order by (select 1)) -1 From (
     Select 1 From (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as x1(n) 
     Cross Join (values(1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) as x2(n) 
    ) as x(n) 
) 
Select item_id, cost, DATEADD(day, n, dateFrom), n From @dates d 
Inner Join inc i on n <= DATEDIFF(day, dateFrom, dateTo) 
Order by item_id 

輸出:

item_id cost Date      n 
1  100  2014-01-01 00:00:00.000  0 
1  100  2014-01-02 00:00:00.000  1 
1  100  2014-01-03 00:00:00.000  2 
2  105  2014-01-08 00:00:00.000  2 
2  105  2014-01-07 00:00:00.000  1 
2  105  2014-01-06 00:00:00.000  0 
2  105  2014-01-09 00:00:00.000  3 
3  102  2014-02-14 00:00:00.000  3 
3  102  2014-02-15 00:00:00.000  4 
3  102  2014-02-16 00:00:00.000  5 
3  102  2014-02-11 00:00:00.000  0 
3  102  2014-02-12 00:00:00.000  1 
3  102  2014-02-13 00:00:00.000  2 

示例數據:

declare @dates table(item_id int, cost int, dateFrom datetime, dateTo datetime); 
insert into @dates(item_id, cost, dateFrom, dateTo) values 
(1, 100, '20140101', '20140103') 
, (2, 105, '20140106', '20140109') 
, (3, 102, '20140211', '20140216'); 
1

這可以使用Cursors來實現。

我模擬提供的測試數據,並創建另一個表名爲「DesiredTable」來存儲裏面的數據,並創建了以下cusror這就實現正是你在找什麼:

SET NOCOUNT ON; 

DECLARE @ITEM_ID int, @COST_OF_ITEM Money, 
     @DATE_FROM date, @DATE_TO date; 

DECLARE @DateDiff INT; -- holds number of days between from & to columns 
DECLARE @counter INT = 0; -- for loop counter 

PRINT '-------- Begin the Date Expanding Cursor --------'; 

-- defining the cursor target statement 
DECLARE Date_Expanding_Cursor CURSOR FOR 
SELECT [ITEM_ID] 
     ,[COST_OF_ITEM] 
     ,[DATE_FROM] 
     ,[DATE_TO] 
    FROM [dbo].[OriginalTable] 

-- openning the cursor 
OPEN Date_Expanding_Cursor 

-- fetching next row data into the declared variables 
FETCH NEXT FROM Date_Expanding_Cursor 
INTO @ITEM_ID, @COST_OF_ITEM, @DATE_FROM, @DATE_TO 

-- if next row is found 
WHILE @@FETCH_STATUS = 0 
BEGIN 

-- calculate the number of days in between the date columns 
SELECT @DateDiff = DATEDIFF(day,@DATE_FROM,@DATE_TO) 

-- reset the counter to 0 for the next loop 
set @counter = 0; 

WHILE @counter <= @DateDiff 
BEGIN 

-- inserting rows inside the new table 
insert into DesiredTable 
Values (@COST_OF_ITEM, DATEADD(day,@counter,@DATE_FROM)) 

set @counter = @counter +1 
END 

-- fetching next row 
FETCH NEXT FROM Date_Expanding_Cursor 
INTO @ITEM_ID, @COST_OF_ITEM, @DATE_FROM, @DATE_TO 
END 

-- cleanup code 
CLOSE Date_Expanding_Cursor; 
DEALLOCATE Date_Expanding_Cursor; 

的代碼從原始表中提取每一行,然後計算DATE_FROMDATE_TO列之間的天數,然後使用此數字腳本將創建要插入新表DesiredTable內的相同行。

試試看,讓我知道結果。

+0

它作爲一種魅力,謝謝你。只有一個問題:所討論的表大約需要2-3百萬條記錄(並且正在增長),所以使用遊標真的非常耗費資源,而且需要很長時間才能完成。 – dhuesca

+0

哦,對不起。我在創建此解決方案時不知道這些信息。原諒我 :) –

0

另一種方法是創建和維護日曆表,其中包含所有日期多年(在我們的應用程序中,我們有30年左右的表,每年延長)。然後,你可以鏈接到日曆:

select <whatever you need>, calendar.day 
from <your tables> inner join calendar on calendar.day between <min date> and <max date> 

這種方法允許包括日曆表的附加信息(節假日等) - 有時是非常有幫助的。

相關問題