0

有人可以引导我使用基于集合的解决方案而不是基于光标的解决方案来解决这个问题吗?

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

日期值  
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

任何建议和/或方向将不胜感激。

4

3 回答 3

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
于 2013-11-01T16:30:49.373 回答
1

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

使用数字表:

链接

询问:

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小提琴

于 2013-11-01T16:58:02.780 回答
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
于 2013-11-01T16:28:15.773 回答