繁体   English   中英

SQL:获取具有条件逻辑的两个字段(DATEDIFF)的计算的聚合(SUM)(CASE WHEN)

[英]SQL: Get an aggregate (SUM) of a calculation of two fields (DATEDIFF) that has conditional logic (CASE WHEN)

我有一个包含大量住宿数据的数据集(在酒店)。 每行包含开始日期和结束日期,但没有持续时间字段。 我需要得到持续时间的总和。

样本数据:

| Stay ID | Client ID | Start Date | End Date   |
| 1       | 38        | 01/01/2018 | 01/31/2019 |
| 2       | 16        | 01/03/2019 | 01/07/2019 |
| 3       | 27        | 01/10/2019 | 01/12/2019 |
| 4       | 27        | 05/15/2019 | NULL       |
| 5       | 38        | 05/17/2019 | NULL       |

还有一些复杂的问题:

  1. 我正在使用Crystal Reports,这是一个SQL表达式,它遵循略有不同的规则。 基本上,它返回单个标量值。 以下是一些更多信息: http//www.cogniza.com/wordpress/2005/11/07/crystal-reports-using-sql-expression-fields/
  2. 有时,结束日期字段为空(他们尚未预订)。 如果为空,我想用当前时间戳替换它。
  3. 我只想算一下去年发生的夜晚。 如果给定停留的开始日期超过一年,我需要调整它。
  4. 我需要通过客户ID获得一笔款项

我实际上并不擅长SQL,所以我只是猜测。

Crystal Reports SQL Expression的正确语法如下所示:

(
SELECT (CASE
WHEN StayDateStart < DATEADD(year,-1,CURRENT_TIMESTAMP) THEN DATEDIFF(day,DATEADD(year,-1,CURRENT_TIMESTAMP),ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
ELSE DATEDIFF(day,StayDateStart,ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
END)
)

如果我想这样做,这给了我一行的正确价值:

| Stay ID | Client ID | Start Date | End Date   | Duration |
| 1       | 38        | 01/01/2018 | 01/31/2019 | 210      | // only days since June 4 2018 are counted
| 2       | 16        | 01/03/2019 | 01/07/2019 | 4        |
| 3       | 27        | 01/10/2019 | 01/12/2019 | 2        |
| 4       | 27        | 05/15/2019 | NULL       | 21       |
| 5       | 38        | 05/17/2019 | NULL       | 19       |

但我希望得到每个客户端的持续时间的SUM,所以我想要这个:

| Stay ID | Client ID | Start Date | End Date   | Duration |
| 1       | 38        | 01/01/2018 | 01/31/2019 | 229      | // 210+19
| 2       | 16        | 01/03/2019 | 01/07/2019 | 4        |
| 3       | 27        | 01/10/2019 | 01/12/2019 | 23       | // 2+21
| 4       | 27        | 05/15/2019 | NULL       | 23       |
| 5       | 38        | 05/17/2019 | NULL       | 229      |

我试图在我的CASE周围包装一个SUM(),但这不起作用:

(
SELECT SUM(CASE
WHEN StayDateStart < DATEADD(year,-1,CURRENT_TIMESTAMP) THEN DATEDIFF(day,DATEADD(year,-1,CURRENT_TIMESTAMP),ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
ELSE DATEDIFF(day,StayDateStart,ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
END)
)

它给出了一个错误,即StayDateEnd在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。 但我甚至不知道这意味着什么,所以我不确定如何排除故障,或者从哪里开始。 然后下一步是通过客户端ID获取SUM。

任何帮助将不胜感激!

您需要一个基于group by client_id的sum的子查询以及表示子查询之间的连接,例如:

select  Stay_id, client_id, Start_date, End_date,  t.sum_duration 
from your_table
inner join ( 
    select Client_id, 

    SUM(CASE
    WHEN StayDateStart < DATEADD(year,-1,CURRENT_TIMESTAMP) THEN DATEDIFF(day,DATEADD(year,-1,CURRENT_TIMESTAMP),ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
    ELSE DATEDIFF(day,StayDateStart,ISNULL(StayDateEnd,CURRENT_TIMESTAMP))
    END) sum_duration 

    from your_table  
    group by Client_id 
    ) t on t.Client_id = your_table.client_id

虽然解释和数据集几乎不可能匹配,但我认为这是你想要的近似值。

declare @your_data table (StayId int, ClientId int, StartDate date, EndDate date)
insert into @your_data values
(1,38,'2018-01-01','2019-01-31'),
(2,16,'2019-01-03','2019-01-07'),
(3,27,'2019-01-10','2019-01-12'),
(4,27,'2019-05-15',NULL),
(5,38,'2019-05-17',NULL)

;with data as (
  select *,
    datediff(day,
      case 
        when datediff(day,StartDate,getdate())>365 then dateadd(year,-1,getdate())
        else StartDate
      end,
      isnull(EndDate,getdate())
    ) days
  from @your_data
)
select *,
  sum(days) over (partition by ClientId)
from data

https://rextester.com/HCKOR53440

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM