Как вернуть одну и ту же строку несколько раз с несколькими условиями - PullRequest
0 голосов
/ 26 сентября 2019

Мои знания довольно просты, поэтому ваша помощь будет высоко оценена.

Я пытаюсь возвращать одну и ту же строку несколько раз, когда она удовлетворяет условию (у меня есть только доступ к запросу на выборку).

У меня есть таблица из более чем 500000 записей с Customer ID, Start Date and End Date, где end date может быть null.

Я пытаюсь добавить новый столбец с именем Week_No и перечислить все строки соответственно.Например, если диапазон дат превышает одну неделю, строка должна возвращаться несколько раз с соответствующим номером недели.Также я хотел бы подсчитать перекрывающиеся дни, которые никогда не будут превышать 7 (неделя) на строку, а затем подсчитать недоступные дни, используя вторую таблицу.

Пример данных ниже

t1

ID     | Start_Date | End_Date
000001 | 12/12/2017 | 03/01/2018
000002 | 13/01/2018 |
000003 | 02/01/2018 | 11/01/2018
...

t2

ID     | Unavailable
000002 | 14/01/2018
000003 | 03/01/2018
000003 | 04/01/2018
000003 | 08/01/2018
...

Я не могу пройти этап добавления недели №.Я пытался использовать CASE и UNION ALL, но продолжаю получать ошибки.

declare @week01start datetime = '2018-01-01 00:00:00'   
declare @week01end datetime = '2018-01-07 00:00:00' 
declare @week02start datetime = '2018-01-08 00:00:00'   
declare @week02end datetime = '2018-01-14 00:00:00' 
...
SELECT  
  ID,
  '01' as Week_No,
  '2018' as YEAR,
  Start_Date, 
  End_Date 

FROM t1 
WHERE (Start_Date <= @week01end and End_Date >= @week01start)
 or (Start_Date <= @week01end and End_Date is null)
UNION ALL   
SELECT
  ID,
  '02' as Week_No,
  '2018' as YEAR,
  Start_Date, 
  End_Date  
FROM t1 
WHERE (Start_Date <= @week02end and End_Date >= @week02start) 
 or (Start_Date <= @week02end and End_Date is null)
...

Новая таблица должна выглядеть следующим образом

ID     | Week_No | Year | Start_Date | End_Date   | Overlap | Unavail_Days
000001 | 01      | 2018 | 12/12/2017 | 03/01/2018 | 3       | 
000002 | 02      | 2018 | 13/01/2018 |            | 2       | 1
000003 | 01      | 2018 | 02/01/2018 | 11/01/2018 | 6       | 2
000003 | 02      | 2018 | 02/01/2018 | 11/01/2018 | 4       | 1
...

1 Ответ

0 голосов
/ 26 сентября 2019

бизнес мудрый я не могу понять, что вы пытаетесь достичь.Вы можете использовать следующий код, чтобы вычислить ваши перекрывающиеся дни и т. Д. Я сделал это так, как вы просили, но я бы порекомендовал отдельную таблицу, такую ​​как измерение времени, чтобы получить «более чистое» решение

/*sample data set in temp table*/
select '000001' as id, '2017-12-12'as start_dt, ' 2018-01-03' as end_dt into #tmp union
select '000002' as id, '2018-01-13 'as start_dt, null as end_dt union
select '000003' as id, '2018-01-02' as start_dt, '2018-01-11' as end_dt 

/*calculate week numbers and week diff according to dates*/
select *,
DATEPART(WK,start_dt) as start_weekNumber,
DATEPART(WK,end_dt) as end_weekNumber,
case 
    when DATEPART(WK,end_dt) - DATEPART(WK,start_dt) > 0 then  (DATEPART(WK,end_dt) - DATEPART(WK,start_dt)) +1
    else (52 - DATEPART(WK,start_dt)) + DATEPART(WK,end_dt)
end as WeekDiff 
into #tmp1
 from 
        (
        SELECT *,DATEADD(DAY, 2 - DATEPART(WEEKDAY, start_dt), CAST(start_dt AS DATE)) [start_dt_Week_Start_Date],
        DATEADD(DAY, 8 - DATEPART(WEEKDAY, start_dt), CAST(start_dt AS DATE)) [startdt_Week_End_Date],
        DATEADD(DAY, 2 - DATEPART(WEEKDAY, end_dt), CAST(end_dt AS DATE)) [end_dt_Week_Start_Date],
        DATEADD(DAY, 8 - DATEPART(WEEKDAY, end_dt), CAST(end_dt AS DATE)) [end_dt_Week_End_Date]
         from #tmp
        ) s

/*cte used to create duplicates when week diff is over 1*/
;with x as
(
 SELECT TOP (10) rn = ROW_NUMBER() --modify the max you want
  OVER (ORDER BY [object_id]) 
  FROM sys.all_columns 
  ORDER BY [object_id]
)  
/*final query*/
select  --*
            ID,
            start_weekNumber+ (r-1) as Week,
            DATEPART(YY,start_dt) as [YEAR],
            start_dt,
            end_dt,
            null as Overlap,
            null as unavailable_days
             from

(
        select *,
        ROW_NUMBER() over (partition by id order by id) r
         from
        (
            select d.* from x
            CROSS JOIN #tmp1 AS d
            WHERE x.rn <= d.WeekDiff
            union all
            select * from #tmp1
            where WeekDiff is null

        ) a
)a_ext
order by id,start_weekNumber

--drop table #tmp1,#tmp

Выше приведен результат, который вы хотите получить, кроме перекрывающихся и недоступных столбцов.Вместо того, чтобы просто считать недели, я добавил номер недели в году, используя start_dt, но вы можете изменить его, если он вам не нравится:

  ID    Week    YEAR    start_dt    end_dt  Overlap unavailable_days
000001  50  2017    2017-12-12   2018-01-03 NULL    NULL
000001  51  2017    2017-12-12   2018-01-03 NULL    NULL
000001  52  2017    2017-12-12   2018-01-03 NULL    NULL
000002  2   2018    2018-01-13        NULL  NULL    NULL
000003  1   2018    2018-01-02   2018-01-11 NULL    NULL
000003  2   2018    2018-01-02   2018-01-11 NULL    NULL
...