基于集合的解决方案,用于处理SQL表中的行

时间:2013-11-01 16:00:03

标签: sql-server

有人可以指导我使用基于集合的解决方案与基于光标的解决方案来解决此问题吗?

给定一个包含以下行的表:

Date        Value  
2013-11-01  12  
2013-11-12  15  
2013-11-21  13  
2013-12-01   0

我需要一个查询,为2013-11-1和2013-12-1之间的每个日期提供一行,如下所示:

2013-11-01   12  
2013-11-02   12  
2013-11-03   12  
...
2013-11-12   15  
2013-11-13   15  
2013-11-14   15  
...
2013-11-21   13  
2013-11-21   13  
...
2013-11-30   13  
2013-11-31   13

任何建议和/或指示都将受到赞赏。

3 个答案:

答案 0 :(得分:1)

我想到的第一件事就是通过查看一年中的某一天来填写缺失的日期。您可以通过加入主数据库中的spt_values表并将数字添加到一年的第一天来完成此操作。

DECLARE @Table AS TABLE(ADate Date, ANumber Int);
INSERT INTO @Table
VALUES
    ('2013-11-01',12),
    ('2013-11-12',15),
    ('2013-11-21',13),
    ('2013-12-01',0);

SELECT
    DateAdd(D, v.number, MinDate) Date
FROM (SELECT number FROM master.dbo.spt_values WHERE name IS NULL) v
    INNER JOIN (
        SELECT
            Min(ADate) MinDate
            ,DateDiff(D, Min(ADate), Max(ADate)) DaysInSpan
            ,Year(Min(ADate)) StartYear
        FROM @Table
    ) dates ON v.number BETWEEN 0 AND DaysInSpan - 1

接下来,我将它包装成一个派生表,并添加一个子查询来获取最新的数字。您的最终结果可能类似于:

DECLARE @Table AS TABLE(ADate Date, ANumber Int);
INSERT INTO @Table
VALUES
    ('2013-11-01',12),
    ('2013-11-12',15),
    ('2013-11-21',13),
    ('2013-12-01',0);

-- Uncomment the following line to see how it behaves when the date range spans a year end
--UPDATE @Table SET ADate = DateAdd(d, 45, ADate)

SELECT
    AllDates.Date
    ,(SELECT TOP 1 ANumber FROM @Table t WHERE t.ADate <= AllDates.Date ORDER BY ADate DESC)
FROM (
    SELECT
        DateAdd(D, v.number, MinDate) Date
    FROM
        (SELECT number FROM master.dbo.spt_values WHERE name IS NULL) v
        INNER JOIN (
            SELECT
                Min(ADate) MinDate
                ,DateDiff(D, Min(ADate), Max(ADate)) DaysInSpan
                ,Year(Min(ADate)) StartYear
            FROM @Table
        ) dates ON v.number BETWEEN 0 AND DaysInSpan - 1
) AllDates

答案 1 :(得分:1)

另一个解决方案,不确定它与两个已经发布的性能明显相比,但它更简洁:

使用数字表:

Linky

<强>查询:

DECLARE @SDATE DATETIME
DECLARE @EDATE DATETIME
DECLARE @DAYS INT

SET @SDATE = '2013-11-01'
SET @EDATE = '2013-11-29'

SET @DAYS = DATEDIFF(DAY,@SDATE, @EDATE)

SELECT Num, DATEADD(DAY,N.Num,@SDATE), SUB.[Value]

FROM Numbers N
LEFT JOIN MyTable M ON DATEADD(DAY,N.Num,@SDATE) = M.[Date]
CROSS APPLY (SELECT TOP 1 [Value] 
             FROM MyTable M2 
             WHERE [Date] <= DATEADD(DAY,N.Num,@SDATE)
             ORDER BY [Date] DESC) SUB
WHERE N.Num <= @DAYS

-

<强> SQL Fiddle

答案 2 :(得分:0)

这是可能的,但既不漂亮也不高效:

除了your_table之外,您还需要创建第二个表/视图dates,其中包含您希望在此查询的输出中显示的每个日期。对于您的示例,它至少需要包含2013-11-01到2013-12-01。

SELECT m.date, y.value
FROM your_table y
INNER JOIN ( 
        SELECT md.date, MAX(my.date) AS max_date
        FROM dates md 
        INNER JOIN your_table my ON md.date >= my.date
        GROUP BY md.date
    ) m
    ON y.date = m.max_date