加入生成的日期序列

时间:2020-02-06 23:26:01

标签: sql sql-server

当前,我正在尝试将日期表联接到分类帐表,以便在某些情况下(例如3月1日和3月3日有交易,但没有交易记录)填补空白表的空白3月2日进行交易。通过将两个表连接起来,3月2日将出现在分类帐表中,但我们要分析的变量为0。)

挑战在于我无法创建Date对象/表/维度,因为我没有在数据库中创建表的权限。因此,我一直在使用以下代码生成日期序列:

DECLARE @startDate date = CAST('2016-01-01' AS date),
        @endDate date = CAST(GETDATE() AS date);

SELECT DATEADD(day, number - 1, @startDate) AS [Date]
FROM (
    SELECT ROW_NUMBER() OVER (
        ORDER BY n.object_id
        )
    FROM sys.all_objects n
    ) S(number)
WHERE number <= DATEDIFF(day, @startDate, @endDate) + 1;

那么,是否有可能将两个表连接到同一条语句中?假设分类帐表如下所示:

SELECT
 date,cost
FROM ledger

我认为可以通过使用子查询来完成,但是我不知道怎么做。

谢谢。

2 个答案:

答案 0 :(得分:2)

Aaron Bertrand的一篇很好的文章介绍了几种在SQL Server中生成数字序列(或日期)的方法:Generate a set or sequence without loops – part 1

尝试一下,看看自己更快或更方便。 (破坏者-递归CTE相当慢)

选择了首选方法后,可以将其包装在CTE(common-table expression)中。

在这里,我将使用问题中的方法

WITH
CTE_Dates
AS
(
    SELECT 
        DATEADD(day, number - 1, @startDate) AS dt
    FROM (
        SELECT ROW_NUMBER() OVER (
            ORDER BY n.object_id
            )
        FROM sys.all_objects n
        ) S(number)
    WHERE number <= DATEDIFF(day, @startDate, @endDate) + 1
)
SELECT
   ...
FROM
    CTE_Dates
    LEFT JOIN Ledger ON Ledger.dt = CTE_Dates.dt
;

答案 1 :(得分:1)

您可以将生成的日期序列用作CTE,并将LEFT JOIN用于ledger表。例如:

DECLARE @startDate date = CAST('2020-02-01' AS date);
DECLARE @endDate date = CAST(GETDATE() AS date);

WITH dates AS (
SELECT DATEADD(day, number - 1, @startDate) AS [Date]
FROM (
    SELECT ROW_NUMBER() OVER (
        ORDER BY n.object_id
        )
    FROM sys.all_objects n
    ) S(number)
  WHERE number <= DATEDIFF(day, @startDate, @endDate) + 1
)
SELECT dates.Date, COALESCE(ledger.cost, 0)
FROM dates
LEFT JOIN (VALUES ('2020-02-02', 14), ('2020-02-05', 10)) AS ledger([Date], [cost]) ON dates.Date = ledger.Date

输出:

Date        cost
2020-02-01  0
2020-02-02  14
2020-02-03  0
2020-02-04  0
2020-02-05  10
2020-02-06  0

Demo on dbfiddle

相关问题