使用当天的值或最近一天的值生成每天的结果集

时间:2014-03-18 13:32:54

标签: sql tsql

使用开始日期和结束日期,我们需要选择每天的列值,或使用最近日期存在数据的值。

例如,使用此示例数据

create table #t1
(location char(2),
item varchar(6),
postdate date,
posttime time,
qoh int)

insert #t1 select 'FL', 'itemA', '1/1/2014', '0900', 10
insert #t1 select 'FL', 'itemA', '1/1/2014', '0100', 11
insert #t1 select 'NY', 'itemA', '1/1/2014', '1100', 50
insert #t1 select 'NY', 'itemA', '1/1/2014', '0900', 51;

insert #t1 select 'FL', 'itemB', '1/1/2014', '0900', 100
insert #t1 select 'FL', 'itemB', '1/1/2014', '0100', 101
insert #t1 select 'NY', 'itemB', '1/1/2014', '1100', 150
insert #t1 select 'NY', 'itemB', '1/1/2014', '0900', 151;

insert #t1 select 'FL', 'itemA', '1/5/2014', '0900', 510
insert #t1 select 'FL', 'itemA', '1/5/2014', '0100', 511
insert #t1 select 'NY', 'itemA', '1/5/2014', '1100', 550
insert #t1 select 'NY', 'itemA', '1/5/2014', '0900', 551;

insert #t1 select 'FL', 'itemB', '1/5/2014', '0900', 5100
insert #t1 select 'FL', 'itemB', '1/5/2014', '0100', 5101
insert #t1 select 'NY', 'itemB', '1/5/2014', '1100', 5150
insert #t1 select 'NY', 'itemB', '1/5/2014', '0900', 5151;

我想为1/1和1/6之间的所有日期选择每个位置,项目和最后余额。对于没有条目的日期,例如1/2,没有任何记录,所以我想使用上一个已知日期1/1的值,并对所有其他日期使用这个类似的逻辑。

我想要的结果是

date    Location    Item    OHB2
2014-01-01  FL  itemA   11
2014-01-01  FL  itemB   101
2014-01-01  NY  itemA   51
2014-01-01  NY  itemB   151
2014-01-02  FL  itemA   11
2014-01-02  FL  itemB   101
2014-01-02  NY  itemA   51
2014-01-02  NY  itemB   151
2014-01-03  FL  itemA   11
2014-01-03  FL  itemB   101
2014-01-03  NY  itemA   51
2014-01-03  NY  itemB   151
2014-01-04  FL  itemA   11
2014-01-04  FL  itemB   101
2014-01-04  NY  itemA   51
2014-01-04  NY  itemB   151
2014-01-05  FL  itemA   510
2014-01-05  FL  itemB   5100
2014-01-05  NY  itemA   550
2014-01-05  NY  itemB   5150
2014-01-06  FL  itemA   510
2014-01-06  FL  itemB   5100
2014-01-06  NY  itemA   550
2014-01-06  NY  itemB   5150

到目前为止,这是我尝试过的,直到我开始使用更大的日期范围。然后它开始在我的实际数据库中非常缓慢地运行,其中涉及100万行。当SELECT TOP部分被注释掉时,它运行得非常快。

WITH dates AS
(
    SELECT CAST('1/1/2014' AS DATE) 'date', 
           1 AS RN
    UNION ALL
    SELECT DATEADD(day, 1, D.date), 
           1 AS RN
    FROM dates D
    WHERE DATEADD(dd, 1, D.date) <= '1/6/2014'
)
SELECT dates.[date], 
       I.Location,
       I.Item,
(SELECT TOP 1 #t1.qoh FROM #t1
    WHERE #t1.location = I.Location
    AND #t1.item = I.Item
    AND #t1.postdate <= dates.[date]
    ORDER BY #t1.postdate DESC, #t1.posttime DESC) AS OHB2
FROM dates
INNER JOIN 
(
SELECT 1 AS RN2,
#t1.location AS Location, 
#t1.item AS Item
FROM #t1
GROUP BY #t1.location, 
          #t1.item) I
ON dates.RN = I.RN2
ORDER BY dates.[date] ASC, I.Location ASC, I.Item ASC
OPTION (MAXRECURSION 32767)

1 个答案:

答案 0 :(得分:0)

使用您的日期CTE。

;WITH dates AS
(
    SELECT CAST('1/1/2014' AS DATE) 'date', 
           1 AS RN
    UNION ALL
    SELECT DATEADD(day, 1, D.date), 
           1 AS RN
    FROM dates D
    WHERE DATEADD(dd, 1, D.date) <= '1/6/2014'
)
SELECT d.[date], I.location, I.item, i.qoh
FROM dates d
    CROSS JOIN (SELECT DISTINCT location, item 
                FROM #t1) a
    CROSS APPLY (SELECT TOP 1 * 
                FROM #t1 t 
                WHERE t.postdate <= d.date 
                    AND a.location = t.location 
                    AND a.item = t.item 
                ORDER BY t.postdate 
                DESC) i
ORDER BY i.postdate