【问题标题】:Dynamic 12 month rolling total for each previous month, going back 12 months前一个月的动态 12 个月滚动总计,可追溯至 12 个月
【发布时间】:2019-01-04 10:01:21
【问题描述】:

我有以下 sql 代码(where 子句只是为了限制当前的行数)

select 
    month,
    monthname,
    year,
    count(distinct case when a.dim_service_type_id_desc like '%Direct Payment%' then a.DIM_PERSON_ID else null end) as No_dp,
    count(distinct a.DIM_PERSON_ID) as no_ppl
from   
    SERVICE_PROVISIONS a
    inner join date_tbl d on CONVERT(VARCHAR(35),a.start_dttm,112) = d.dim_date_id
where 
    a.dim_person_id >0
    and year = 2018
group by 
    month,
    monthname,
    year

我的输出是这样的

month monthname     year    No_dp   no_ppl
1       January     2018    142     1604
2       February    2018    111     1526
3       March       2018    133     1636
4       April       2018    1107    3829
5       May         2018    140     1575
6       June        2018    131     1389
7       July        2018    200     893
8       August      2018    2       73
9       September   2018    1       32
10      October     2018    2       21
11      November    2018    2       21
12      December    2018    2       19

所以我的问题是 - 客户想查看在过去 12 个月内有多少服务处于打开状态(使用开始日期和结束日期)(不是已启动的服务数量,而是当前未结束的服务数量)。这在使用当前月份时很好,但是他们也希望将前 12 个月的数据显示为滚动动态数据。

因此,例如本月 7 月,他们想查看过去 12 个月内有多少服务处于开放状态。上个月 6 月,他们想查看在 6 月之前的 12 个月中有多少服务是开放的,以此类推之前的 12 个月。

表格需要包含过去 12 个月的月份名称,并在列中显示该月旁边的过去 12 个月中打开的服务数量。

我希望这是有道理的,如果没有,对不起,请随时提出问题,我会尽力澄清。

输出需要看起来像当前的输出表,但它目前只显示该月内启动了多少服务,这不是我们想要的。

日期表是一个参考表,具有不同的日期格式等。如果需要,可以使用或添加。

【问题讨论】:

  • 请务必在问题中包含预期的输出

标签: sql sql-server sql-server-2016


【解决方案1】:

我不得不对您的数据做出几个假设。希望我将在一分钟内显示的查询将便于您调整,如果其中有任何错误:

  1. 我猜start_dttmdatetimedatetime2 列。
  2. 我假设有一个名为 end_dttm 的对应列给出了服务的结束日期/时间,并且此列中的 null 表示服务尚未结束。
  3. 对于服务在给定月份“开放”意味着什么,我的最佳猜测是它在该月内或之前的某个时间开始,并且在该月结束时尚未结束。李>
  4. 我从您的原始查询中假设具有相同dim_person_id 的多个服务不代表不同的服务。

由于我不知道您的date_tbl 中有什么,我将展示一个不需要它的示例。考虑以下查询:

select
    BeginDate = dateadd(month, -1, dateadd(day, 1, eomonth(getdate(), -Offset.X))),
    EndDate = dateadd(day, 1, eomonth(getdate(), -Offset.X))
from
    (values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) Offset(X)

这将为您提供 12 条记录,分别代表当前月份和前 11 个月中的每一个月。请注意,我这里的EndDate 实际上不是该月的最后一天,而是下个月 的第一天。我这样做是因为上面的假设 1;由于您的服务日期可能包含时间部分,我将通过检查它们的日期是否严格早于下个月的开始来确定它们是否属于给定月份。以下是该查询给我的信息:

BeginDate   EndDate
2018-07-01  2018-08-01
2018-06-01  2018-07-01
2018-05-01  2018-06-01
2018-04-01  2018-05-01
2018-03-01  2018-04-01
2018-02-01  2018-03-01
2018-01-01  2018-02-01
2017-12-01  2018-01-01
2017-11-01  2017-12-01
2017-10-01  2017-11-01
2017-09-01  2017-10-01
2017-08-01  2017-09-01

现在我将把上述结果集加入到您的 SERVICE_PROVISIONS 数据中,查找每个月中具有 dim_person_id > 0(来自您的原始查询)并且满足上述假设 3 的记录。

-- Some sample data (assumptions 1 & 2)
declare @SERVICE_PROVISIONS table (dim_person_id bigint, start_dttm datetime, end_dttm datetime);
insert @SERVICE_PROVISIONS values
    (1, '20180101', '20180315'),
    (1, '20180101', '20180315'),
    (2, '20171215', '20180520');

-- The CTE defines the months we'll report on, as described earlier.
with MonthsCTE as
(
    select
        BeginDate = dateadd(month, -1, dateadd(day, 1, eomonth(getdate(), -Offset.X))),
        EndDate = dateadd(day, 1, eomonth(getdate(), -Offset.X))
    from
        (values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) Offset(X)
)

-- This query matches the months from the CTE against the applicable services.
select
    [Month] = datepart(month, M.BeginDate),
    [MonthName] = datename(month, M.BeginDate),
    [Year] = datepart(year, M.BeginDate),
    ServicesOpen = count(distinct S.dim_person_id)   -- Assumption 4
from
    MonthsCTE M
    left join @SERVICE_PROVISIONS S on
        S.dim_person_id > 0 and
        S.start_dttm < M.EndDate and   -- Assumption 3
        (
            S.end_dttm >= M.EndDate or
            S.end_dttm is null   -- Assumption 2
        )
group by
    M.BeginDate,
    M.EndDate
order by
    M.BeginDate;

请注意,我将dim_person_id &gt; 0WHERE 子句移至JOIN,这样即使在此期间没有服务打开,12 个月中的每一个月仍将出现在结果集中。结果:

Month   MonthName   Year   ServicesOpen
8       August      2017   0
9       September   2017   0
10      October     2017   0
11      November    2017   0
12      December    2017   1
1       January     2018   2
2       February    2018   2
3       March       2018   1
4       April       2018   1
5       May         2018   0
6       June        2018   0
7       July        2018   0

【讨论】:

  • 我正在考虑尝试将此部分转换为表格函数,以便用户可以决定他们想要查看多少个月,之前的 12、6、24 等。任何帮助都会也非常感谢 - 选择 BeginDate = dateadd(month, -1, dateadd(day, 1, eomonth(getdate(), -Offset.X))), EndDate = dateadd(day, 1, eomonth(getdate(), - Offset.X)) 从(值 (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10) ),(11)) 偏移量(X)
  • 我很高兴它对你有用!查看this article 描述数字表的好处,因为我认为这可能是您更改查询中的月数的最简单方法,并且通常是一种有用的东西。然后,您将调整我的原始查询,而不是使用派生表(values 表达式),而是从您的数字表中选择数字 0 到 n - 1
  • 如果由于某种原因您无法在数据库中添加表,或者不想这样做,您可以将通常用于生成表的任何表达式放入 CTE 的您的查询顶部。 This question 展示了许多生成值的方法。
  • 您也可以使用现有的date_tbl 来实现此目的。我没有这样做的唯一原因是因为我真的不知道它长什么样。
【解决方案2】:

有点像这样 - 如果您可以编写一个查询来获取您想要的 ootput 中某行的值,然后使用交叉应用链接到该查询。统计月前有打开记录但月前没有关闭记录的记录似乎可行

SELECT IQ. *, OA.SERVICE_PROVISIONS FROM (select 
month,
monthname,
year,
a.dim_person_id dim_person_id,
count(distinct case when a.dim_service_type_id_desc like '%Direct Payment%' then a.DIM_PERSON_ID else null end) as No_dp,
count(distinct a.DIM_PERSON_ID) as no_ppl

from   
SERVICE_PROVISIONS a
inner join date_tbl d on CONVERT(VARCHAR(35),a.start_dttm,112) = d.dim_date_id

where 
a.dim_person_id >0
and year = 2018

group by 
month,
monthname,
year) IQ
CROSS APPLY 
(SELECT count(0) OpenThings FROM SERVICE_PROVISIONS SP1 WHERE 
                 (sp1.startdate < DATEFROMPARTS(IQ.year,iq.month,1) 
                AND 
                sp1.enddate is null or sp1.enddate > DATEFROMPARTS(IQ.year,iq.month,1)) and sp1.dim_person_id = iq.dim_person_id
) AS OA

【讨论】:

  • 更改了表别名的几个错误
  • 恐怕这行不通。我已经尝试修复一些明显的问题,但我遇到了错误,因为它不会在最后的子查询中获取 iq.year 等
  • 我没有表架构来测试它 - 你在 IQ 子查询中还有年份吗?
  • 原则上应该捡起来——例如——SELECT *, DQ.YEAR2 FROM (SELECT 1999 YEAR) IQ CROSS APPLY (SELECT IQ.year + 1 year2) DQ
猜你喜欢
  • 2022-08-02
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
  • 2013-10-06
  • 2018-03-01
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
相关资源
最近更新 更多