简体   繁体   English

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

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

I have a dataset that includes a bunch of stay data (at a hotel). 我有一个包含大量住宿数据的数据集(在酒店)。 Each row contains a start date and an end date, but no duration field. 每行包含开始日期和结束日期,但没有持续时间字段。 I need to get a sum of the durations. 我需要得到持续时间的总和。

Sample Data: 样本数据:

| 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       |

There are some added complications: 还有一些复杂的问题:

  1. I am using Crystal Reports and this is a SQL Expression, which obeys slightly different rules. 我正在使用Crystal Reports,这是一个SQL表达式,它遵循略有不同的规则。 Basically, it returns a single scalar value. 基本上,它返回单个标量值。 Here is some more info: http://www.cogniza.com/wordpress/2005/11/07/crystal-reports-using-sql-expression-fields/ 以下是一些更多信息: http//www.cogniza.com/wordpress/2005/11/07/crystal-reports-using-sql-expression-fields/
  2. Sometimes, the end date field is blank (they haven't booked out yet). 有时,结束日期字段为空(他们尚未预订)。 If blank, I would like to replace it with the current timestamp. 如果为空,我想用当前时间戳替换它。
  3. I only want to count nights that have occurred in the past year. 我只想算一下去年发生的夜晚。 If the start date of a given stay is more than a year ago, I need to adjust it. 如果给定停留的开始日期超过一年,我需要调整它。
  4. I need to get a sum by Client ID 我需要通过客户ID获得一笔款项

I'm not actually any good at SQL so all I have is guesswork. 我实际上并不擅长SQL,所以我只是猜测。

The proper syntax for a Crystal Reports SQL Expression is something like this: 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)
)

And that's giving me the correct value for a single row, if I wanted to do this: 如果我想这样做,这给了我一行的正确价值:

| 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       |

But I want to get the SUM of Duration per client, so I want this: 但我希望得到每个客户端的持续时间的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      |

I've tried to just wrap a SUM() around my CASE but that doesn't work: 我试图在我的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)
)

It gives me an error that the StayDateEnd is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause. 它给出了一个错误,即StayDateEnd在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。 But I don't even know what that means, so I'm not sure how to troubleshoot, or where to go from here. 但我甚至不知道这意味着什么,所以我不确定如何排除故障,或者从哪里开始。 And then the next step is to get the SUM by Client ID. 然后下一步是通过客户端ID获取SUM。

Any help would be greatly appreciated! 任何帮助将不胜感激!

You need a subquery for sum based on group by client_id and a join between you table the subquery eg: 您需要一个基于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

Although the explanation and data set are almost impossible to match, I think this is an approximation to what you want. 虽然解释和数据集几乎不可能匹配,但我认为这是你想要的近似值。

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 https://rextester.com/HCKOR53440

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

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