SQL: получить агрегат (SUM) вычисления двух полей (DATEDIFF) с условной логикой (CASE WHEN) - PullRequest
0 голосов
/ 04 июня 2019

У меня есть набор данных, который включает в себя набор данных о пребывании (в отеле).Каждая строка содержит дату начала и дату окончания, но не содержит поля продолжительности.Мне нужно получить сумму длительностей.

Образцы данных:

| 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. IЯ использую Crystal Reports, и это выражение SQL, которое подчиняется немного другим правилам.По сути, он возвращает единственное скалярное значение.Вот еще немного информации: http://www.cogniza.com/wordpress/2005/11/07/crystal-reports-using-sql-expression-fields/
  2. Иногда поле даты окончания является пустым (они еще не забронированы).Если пусто, я хотел бы заменить его на текущую временную метку.
  3. Я хочу считать только ночи, произошедшие в прошлом году.Если дата начала данного пребывания превышает год назад, мне нужно изменить его.
  4. Мне нужно получить сумму по идентификатору клиента

Я на самом деле не являюсьчто-то хорошо в SQL, так что все, что у меня есть, это догадки.

Правильный синтаксис для выражения SQL Crystal Reports выглядит примерно так:

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

Но я хочу получить СУММУ Длительности на клиента, поэтому я хочу это:

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

Я пытался простообернуть SUM () вокруг моего CASE, но это не работает:

(
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.Но я даже не знаю, что это значит, поэтому я не знаю, как устранить неполадки или куда идти дальше.И затем следующий шаг - получить СУММУ по идентификатору клиента.

Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

0 голосов
/ 04 июня 2019

Хотя объяснение и набор данных практически невозможно сопоставить, я думаю, что это приблизительное значение к тому, что вы хотите.

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

0 голосов
/ 04 июня 2019

Вам нужен подзапрос для суммы, основанной на группе по client_id и объединению между вами таблицы подзапроса, например:

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