2015-11-02 31 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> 

这种方法允许包括日历表的附加信息(节假日等) - 有时是非常有帮助的。

相关问题