如何在 SQL 服务器的查询中创建日期-table?
How can I create a dates-table inside a query in SQL Server?
假设我想将 table_a
中具有 startdate
和 enddate
的记录与个别日期进行匹配,并查看是否在(例如 3 月 13 日) table_a
匹配。我想通过每天生成一行来解决这个问题,日期作为前导列,来自 table_a
的任何匹配数据作为 left join
.
我曾使用过具有 date
维度的数据仓库,使这项工作变得容易。但不幸的是,我需要 运行 在没有 table.
的 OLTP 数据库上执行此特定查询
如何在 SQL 服务器中每天生成一行 table?在没有临时 tables、functions/procedures 等的情况下,如何在我的查询中执行此操作?
我找到了一些破解方法来执行此操作。我假设两年的约会对你来说已经足够 dates
table.
现在,在您的数据库中找到一个至少有 800 条记录的 table(365 x 2 + 闰年 - 令人头疼的乘法 365 = ~~ 800)。该问题讨论的是从 table_a
中选择数据,因此我们假设这是 table_b
。然后,在查询的顶部创建这个通用 Table 表达式:
with dates_table as (
select top 800 -- or more/less if your timespan isn't ~2years
[date] = date_add(day, ROW_NUMBER() over (order by <random column>) -1, <your-start-date>)
from table_b
)
select d.[date]
, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc, etc, etc
一些注意事项:
- 这只需获取数字 0 - 799 并将它们添加到任意日期即可。
- 如果您需要多于或少于两年的日期,请增加或减少输入
top
语句的数字。确保 table_b
有足够的行:select count(*) from table_b
.
<random column
可以是 table_b
上的任何列,顺序无关紧要。我们只对数字 1-800 感兴趣(-1 表示 0-799 的范围),但是 ROW_NUMBER
需要一个 order by
参数。
<your-start-date>
在日期 table 中有您想要的第一个日期,并包含在输出中。
- 在连接查询的
where
中,您可以通过添加 year(d.[date]) IN (2020, 2021)
.[= 之类的内容来过滤掉我们超过的任何多余天数,方法是使用 800 行而不是 730 行(+leap) 39=]
- 如果
table_a
本身有超过 800 条记录,这可以用作 dates_table
的基础,而不是其他一些 table。
另一种方法是使用递归查询来生成日期系列。根据您的 pseudo-code:
with dates_table as (
select <your-start-date> dt
union all
select dateadd(day, 1, dt) from dates_table where dt < <your-end-date>
)
select d.dt, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc etc
option (maxrecursion 0)
假设我想将 table_a
中具有 startdate
和 enddate
的记录与个别日期进行匹配,并查看是否在(例如 3 月 13 日) table_a
匹配。我想通过每天生成一行来解决这个问题,日期作为前导列,来自 table_a
的任何匹配数据作为 left join
.
我曾使用过具有 date
维度的数据仓库,使这项工作变得容易。但不幸的是,我需要 运行 在没有 table.
如何在 SQL 服务器中每天生成一行 table?在没有临时 tables、functions/procedures 等的情况下,如何在我的查询中执行此操作?
我找到了一些破解方法来执行此操作。我假设两年的约会对你来说已经足够 dates
table.
现在,在您的数据库中找到一个至少有 800 条记录的 table(365 x 2 + 闰年 - 令人头疼的乘法 365 = ~~ 800)。该问题讨论的是从 table_a
中选择数据,因此我们假设这是 table_b
。然后,在查询的顶部创建这个通用 Table 表达式:
with dates_table as (
select top 800 -- or more/less if your timespan isn't ~2years
[date] = date_add(day, ROW_NUMBER() over (order by <random column>) -1, <your-start-date>)
from table_b
)
select d.[date]
, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc, etc, etc
一些注意事项:
- 这只需获取数字 0 - 799 并将它们添加到任意日期即可。
- 如果您需要多于或少于两年的日期,请增加或减少输入
top
语句的数字。确保table_b
有足够的行:select count(*) from table_b
. <random column
可以是table_b
上的任何列,顺序无关紧要。我们只对数字 1-800 感兴趣(-1 表示 0-799 的范围),但是ROW_NUMBER
需要一个order by
参数。<your-start-date>
在日期 table 中有您想要的第一个日期,并包含在输出中。- 在连接查询的
where
中,您可以通过添加year(d.[date]) IN (2020, 2021)
.[= 之类的内容来过滤掉我们超过的任何多余天数,方法是使用 800 行而不是 730 行(+leap) 39=] - 如果
table_a
本身有超过 800 条记录,这可以用作dates_table
的基础,而不是其他一些 table。
另一种方法是使用递归查询来生成日期系列。根据您的 pseudo-code:
with dates_table as (
select <your-start-date> dt
union all
select dateadd(day, 1, dt) from dates_table where dt < <your-end-date>
)
select d.dt, a.<whatever>
from dates_table d
left outer join table_a a on <join / date matching here>
-- where etc etc
option (maxrecursion 0)