SQL Server:基于多个日期创建摘要
Posted
技术标签:
【中文标题】SQL Server:基于多个日期创建摘要【英文标题】:SQL Server : create summarization based on multiple dates 【发布时间】:2021-04-04 10:31:54 【问题描述】:我有下表,其中包含 10 年前的工人职位:
worker_id | position_code | date_from | date_to |
---|---|---|---|
1 | x1 | 2021-01-01 | 2100-12-31 |
1 | x2 | 2020-12-01 | 2021-01-01 |
2 | x3 | 2000-01-01 | 2100-12-31 |
我想创建一个视图,在这里我可以看到每个工人每个月的职位。
例如:
year | month | worker_id | position_code |
---|---|---|---|
2020 | 12 | 1 | x2 |
2020 | 12 | 2 | x3 |
2021 | 1 | 1 | x1 |
2021 | 1 | 2 | x3 |
2021 | 2 | 1 | x1 |
理想情况下,我只对过去 6 个月的表现感兴趣。 总体而言,大约有 10000 名工人,桌子本身大约有 100000 行。 有些工人只有 1 个职位,但可以是多个职位。
理论上位置只会在月初发生变化,但最好也注意这一点,在这种情况下,选择在月底处于活动状态。
(例如:从 1 月 1 日到 10 日位置是 x1,从 1 月 10 日到 31 日是 x2,在这种情况下 x2 是我要找的那个)
【问题讨论】:
如果工人在月中开始工作会怎样? 【参考方案1】:WITH WORKERS(worker_id, position_code, date_from, date_to) AS
(
SELECT 1 , 'x1', '2021-01-01', '2100-12-31' UNION ALL
SELECT 1 , 'x2' , '2020-12-01', '2021-01-01' UNION ALL
SELECT 2 , 'x3' , '2000-01-01' , '2100-12-31'
),
MINI_MAX AS
(
SELECT MIN(DATE_FROM)AS STARTT_DATE,MAX(DATE_TO)AS END_DATE
FROM WORKERS
),
CALENDAR AS
(
SELECT CAST(STARTT_DATE AS DATE)DATE_D FROM MINI_MAX AS W
UNION ALL
SELECT DATEADD(MONTH,1,Z.DATE_D)
FROM CALENDAR AS Z
WHERE Z.DATE_D<=(SELECT END_DATE FROM MINI_MAX)
),
RESULT AS
(
SELECT YEAR(C.DATE_D)AS YEARR,MONTH(C.DATE_D)MONTHH,W.worker_id,W.position_code
FROM CALENDAR AS C
JOIN WORKERS AS W ON C.DATE_D BETWEEN W.date_from AND W.date_to
)
SELECT R.YEARR,R.MONTHH,R.worker_id,R.position_code
FROM RESULT AS R
OPTION(MAXRECURSION 0)
我会说这种查询最适合的方式是使用永久日历表并直接对其执行JOIN
【讨论】:
thanks 看起来又好又快。我可以过滤最后一个选择的月份,我猜我需要的年份?如果一个工人在同一个月有 2 个值会发生什么? 我想,最好用加入日历表来替换所有这些计算。之后,所有对年、月等的过滤都将变得微不足道。如果一个工人在同一个月有 2 个值,您将获得 2 条记录【参考方案2】:最困难的部分是生成月份。一种方法是递归 CTE:
with cte as (
select worker_id, position_code, date_from as dte,
eomonth(case when date_to < eomonth(getdate()) then dateadd(day, -1, date_to) else getdate() end) as date_to
from t
union all
select worker_id, position_code,
dateadd(month, 1, datefromparts(year(dte), month(dte), 1)), date_to
from cte
where eomonth(dte) < eomonth(date_to)
)
select *
from cte
order by worker_id, dte desc
option (maxrecursion 0)
注意:如果工人在月中开始工作,您可能会得到重复。
Here 是一个 dbfiddle。
【讨论】:
感谢这看起来很清楚。我有 2 个问题:因为我不需要全系列,我可以过滤整个 cte 吗?例如今年?还是在性能方面更好地尝试在 uninon 之前做到这一点?如果像您说的那样一个月有多个值,那么过滤的最佳方法是什么?按 date_to 排序,只取第一行? @meri 。 . .如果你只想要一个范围,我可能会建议你问一个 new 问题。那会简单一些。但。是的,您可以生成所有数据,然后进行过滤。以上是关于SQL Server:基于多个日期创建摘要的主要内容,如果未能解决你的问题,请参考以下文章
在 SQL Server 中使用基于多个字段的自动序列创建触发器
基于 Distinct 结果集在 Microsoft SQL Server 中创建表