我如何在SQL中创建一个日期表,该表将自动填充自身

问题描述

我想用以下4个列在sql中创建一个表:id,年,月和日。但是,我想从2012年到2020年自动填写此栏。最佳方法是什么?我用谷歌搜索,但我真的找不到解决方案。例如,我希望表格显示以下信息。

overflow: hidden

解决方法

使用 VBoka 建议,请尝试以下操作:

create table calendar(
    id int identity(1,1) not null primary key,ano int not null,mes int not null,dia int not null
)

declare @startdate date,@enddate date,@num_days int
set @startdate = '2012-01-01'
set @num_days = 3287 --number of days bewtween jan 2012 and dez 2020 https://www.timeanddate.com/date/durationresult.html
set @enddate = dateadd(d,@num_days,@startdate)

while @startdate <= @enddate
    begin
        insert into calendar (ano,mes,dia)
            select year(@startdate),month(@startdate),day(@startdate)

        set @startdate = dateadd(dd,1,@startdate)
    end
,

使用CTE且没有日期时间功能:

if object_id('Calendar_tb','U') is null
    create table Calendar_tb (
        id int identity(1,1) not null,[year] smallint,[month] tinyint,[day] tinyint
    )

declare @tb table (yy smallint,mm tinyint,dd tinyint);
with
CTE_y as (
    select 2012 as nyear
    union all
    select nyear + 1 from CTE_y where nyear < 2020
),CTE_m as (
    select 1 as nmonth
    union all
    select nmonth + 1 from CTE_m where nmonth < 12
),CTE_d as (
    select 1 as nday
    union all
    select nday + 1 from cte_d where nday < 31
)
insert @tb
select nyear,nmonth,nday from CTE_d,CTE_m,CTE_y

delete from @tb
where   (dd>30 and mm in (4,6,9,11))
    or  (dd>29 and mm = 2)
    or  (dd>28 and mm = 2 and not
            -- leap year
            (yy%400=0 or (yy%4=0 and yy%100!=0)))

truncate table Calendar_tb

insert Calendar_tb
select * from @tb order by 1,2,3

select * from Calendar_tb
,

不需要循环,游标或递归CTE ...就像下面这样简单。

    WITH 
        cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1)) n (n)),-- 10
        cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b),-- 100
        cte_Calendar (dt) AS (
            SELECT TOP (DATEDIFF(DAY,'2012-01-01','2020-12-31') + 1)
                CONVERT(DATE,DATEADD(DAY,ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1,'2012-01-01'))
            FROM
                cte_n2 a CROSS JOIN cte_n2 b                                                    -- 10,000
            )
    SELECT
        ID = DATEDIFF(DAY,c.dt) + 1,[Year] = YEAR(c.dt),[Month] = MONTH(c.dt),[Day] = DAY(c.dt)
    FROM
        cte_Calendar c;
GO

或者您可以用它来填充一个永久表...

    IF OBJECT_ID('tempdb.dbo.YMD','U') IS NOT NULL 
    BEGIN DROP TABLE tempdb.dbo.YMD; END;
    GO
    
    CREATE TABLE tempdb.dbo.YMD (
            ID int NOT NULL IDENTITY(1,1)
                CONSTRAINT pk_YMD PRIMARY KEY CLUSTERED (ID),[Year] int NOT NULL,[Month] tinyint NOT NULL,[Day] tinyint NOT NULL 
        );
    GO
    
    --------------------------------------------------------------------------------------------------------
    WITH 
        cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),000
            )
    INSERT tempdb.dbo.YMD (Year,Month,Day)
    SELECT 
        [Year] = YEAR(c.dt),[Day] = DAY(c.dt)
    FROM
        cte_Calendar c;
GO
    
    ------------------------------------------------------------------------------------------------------
    SELECT
        YMD.ID,YMD.Year,YMD.Month,YMD.Day
    FROM
        tempdb.dbo.YMD;
GO