做测试或者生成数据仓库中的日期维度时,我们需要生成某一时间段的连续日期。大部分时候我们会用循环插入的方式来实现,但看了《High Performance T-SQL Using Window Functions》的朋友可能会有另一种方式。
先是建立表结构,简单的两个字段,一是日期,二是周几
CREATE TABLE dbo.DimTime(CurrentDay DateTime, CurrentDayOfWeek INT)
首先来看循环的方式:
DECLARE @INC INT = 0
DECLARE @DateBegin DateTime = '1980-01-01'
WHILE @DateBegin <='2080-01-01'
BEGIN
INSERT INTO dbo.DimTime(CurrentDay , CurrentDayOfWeek )
VALUES(@DateBegin,DATEPART(dw,@DateBegin))
SET @DateBegin = DATEADD(Day,1,@DateBegin)
END
(耗时 10s, 本机配了 2G内存,i3 CPU, SSD 硬盘,windows server 2012)
接下来是《High Performance T-SQL Using Window Functions》中提到的 Tally Table 方式:
DECLARE @BEGIN DATETIME = '2010-01-01'
,@END DATETIME = '2017-10-30'
DECLARE @INC INT;
SELECT @INC = DATEDIFF(DAY, @BEGIN, @END);
WITH L0
AS (
SELECT *
FROM (
VALUES (1)
,(2)
,(3)
) AS T(C)
)
,L1
AS (
SELECT a.C
,b.C AS BC
FROM L0 AS a
CROSS JOIN L0 AS b
)
,L2
AS (
SELECT a.C
,b.C AS BC
FROM L1 AS a
CROSS JOIN L1 AS b
)
,L3
AS (
SELECT a.C
,b.C AS BC
FROM L2 AS a
CROSS JOIN L2 AS b
)
,L4
AS (
SELECT a.C
,b.C AS BC
FROM L3 AS a
CROSS JOIN L3 AS b
)
,L5
AS (
SELECT a.C
,b.C AS BC
FROM L4 AS a
CROSS JOIN L4 AS b
)
INSERT INTO dbo.DimTime(CurrentDay , CurrentDayOfWeek )
SELECT TOP (@INC) DATEADD(DAY, RNK - 1, @BEGIN) AS CURR_DATE, DATEPART(dw, DATEADD(DAY, RNK - 1, @BEGIN)) AS CURR_DW
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY (
SELECT NULL
)
) AS RNK
FROM L5
) M
ORDER BY RNK
(同样硬件配置下, 0s 插入100年数据)
比较两种方法,时间上 Tally Table 占了优势,将原理部分单独出来做个函数,还可以自动生成一段连续的数字或者测试数据集,用来解决自增列序号间断的排查。
下面是对 Tally Table 原理的详细描述,请移步
Tally Table 数字辅助表
所以不妨记录下来,以后碰到有机会或者场景的时候,能随手用上。不止一次呼吁广大朋友们,读书再多,也需要动动笔头(现在动动手指记录电子档即可),记录才是可靠的。