理解含派生表的INSERT语句:修改Calendar列名后仍生效的原因
关于Calendar表填充SQL语句的核心疑问解答
一、为什么修改Calendar表的[Date]列为[TheDate]后,原INSERT语句仍能正常执行?
这是因为你用的是无列名指定的INSERT模式:
INSERT INTO Calendar SELECT ...
这种模式下,SQL会按照SELECT子句中列的顺序、数量、数据类型,与目标表Calendar中列的定义顺序、数量、数据类型一一匹配插入,完全不依赖列名。只要你修改列名后,Calendar表的列顺序还是:TheDate(原Date列)→ IsWeekend → IsHoliday → IsWorkday → ...,且对应位置列的数据类型和SELECT返回列一致,语句就能正常运行,两边列名是否匹配不影响执行。
二、语句中派生表(D.Date、DT.IsWeekend等)的含义解析
整个语句通过「生成连续日期→计算日期属性→判断工作日」的逻辑生成Calendar表数据,各派生表和字段的作用如下:
1. 日期偏移序列:S
GENERATE_SERIES(0, DATEDIFF(day, @CalendarFrom, @CalendarThru)) S
S.Value是从0开始的整数序列,最大值为@CalendarFrom到@CalendarThru的天数差。比如两个日期间隔100天,就生成0到100的101个数字,用来覆盖这段时间内的每一天。
2. 具体日期生成:D
(SELECT DATEADD(day, S.value, @CalendarFrom) AS Date) D
- 通过
DATEADD给起始日期@CalendarFrom加上S.Value的天数,生成序列中的每一个具体日期,用Date作为别名,D.Date就是当前循环到的那个日期。
3. 周末/节假日标记:DT
(SELECT CASE WHEN DATEPART(dw, D.Date) IN (@Sat, @Sun) THEN 1 ELSE 0 END AS IsWeekend, CASE WHEN EXISTS (SELECT * FROM Holiday H WHERE H.Date = D.Date) THEN 1 ELSE 0 END AS IsHoliday) DT
这是基于D.Date计算两个状态字段的派生表:
DT.IsWeekend:判断当前日期是否为周末,匹配@Sat(周六对应的数字)和@Sun(周日对应的数字),是则返回1,否则返回0。DT.IsHoliday:检查当前日期是否存在于Holiday表(节假日表)中,存在返回1,否则返回0。
4. 工作日标记:WD
(SELECT CASE WHEN DT.IsWeekend = 0 AND IsHoliday = 0 THEN 1 ELSE 0 END AS IsWorkday) WD
WD.IsWorkday:基于DT的两个字段判断是否为工作日,当既不是周末(IsWeekend=0)也不是节假日(IsHoliday=0)时返回1,否则返回0。
5. SELECT子句其他字段说明
DaySequence:S.Value + 1,把从0开始的偏移序列改成从1开始的日期序号。WorkdaySequence:用窗口函数SUM(WD.IsWorkday) OVER(ORDER BY D.Date)累计工作日数量,仅当当天是工作日时显示该累计值。ThisOrNextWorkdaySequence:累计到当前日期的工作日总数,用于快速定位当前或下一个工作日的序号。ThisOrPriorWorkdaySequence:调整后的累计工作日序号,用于快速定位当前或上一个工作日的序号。DayOfWeek:用DATENAME(dw, D.Date)返回当前日期的星期名称(如“星期一”)。DayType:拼接当前日期的类型标签(如“Weekend”“Holiday”“Workday”),并用TRIM去除多余空格。
内容的提问来源于stack exchange,提问作者J. Smoots
相关产品推荐
相关产品推荐

