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 中使用基于多个字段的自动序列创建触发器

在 SQL Server 中基于临时表创建永久表

在 SQL Server 2008 中从月份和年份创建日期

基于 Distinct 结果集在 Microsoft SQL Server 中创建表

如何:使用 SQL Server 2008 为自动更新修改日期创建触发器

SQL Server BI:单个多维数据集,多个事实表