Масштабируемый СЛУЧАЙ, КОГДА для извлечения непраздничных дат

#sql #sql-server #case #exists

#sql #sql-сервер #кейс #существует

Вопрос:

У меня есть таблица, содержащая записи с датами начала и окончания, поэтому я должен захватить каждую запись, которая началась в пятницу, и если какая-либо пятница является праздничной, получить четверг, и если пятница и четверг являются праздничными днями, получить среду и так далее…

В настоящее время у меня есть две таблицы TableA для записей и Calendar для получения праздников.

Мой TableA выглядит следующим образом:

 id beg         end
--------------------------
1  11/01/2019  14/01/2019
2  10/01/2019  14/01/2019
3  09/01/2019  15/01/2019
...
  

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

 iddate    date        weekday isholiday
---------------------------------------
20190109  09/01/2019  3       0 --0=False / 1=True
20190110  10/01/2019  4       0
20190111  11/01/2019  5       1
...
  

Для обеих таблиц я использую WHERE EXISTS для получения пятниц и условия праздника, которое фактически отображает результаты:

 SELECT *
FROM TableA t
WHERE EXISTS (SELECT 1
              FROM dbo.Calendar AS c
              WHERE c.date = CAST(t.BEG AS DATETIME)
                AND c.weekday = CASE
                                    WHEN (C.weekday = 5 AND C.isholiday = 0)  
                                       THEN 5 --keep friday
                                    --WHEN ((C.weekday= 4 AND C.isholiday= 1) OR (C.weekday= 5 AND C.isholiday= 1)) THEN 3 --keep wednesday / not working
                                       ELSE 4 --keep thursday
                                    END
                AND DATEPART(yyyy, T.beg) = 2019)
ORDER BY 
    CAST(INI AS [datetime])
  

Если пятница — выходной день, на нем будет отображаться это:

 id beg         end
--------------------------
2  10/01/2019  14/01/2019
3  09/01/2019  15/01/2019
  

Если пятница и четверг являются праздничными днями, в нем должно отображаться:

 id beg         end
--------------------------
3  09/01/2019  15/01/2019
  

Масштабирование с помощью этого WHEN ((C.weekday= 4 AND C.isholiday= 1) OR (C.weekday= 5 AND C.isholiday= 1)) просто прерывает весь запрос, и я получаю -почти- случайные даты. Есть какой-нибудь способ увеличить его, не слишком расширяя запрос?

Комментарии:

1. Заполнена ли ваша таблица календаря в том смысле, что в ней 365 строк за 2019 год? Кроме того, ваши ожидаемые результаты не соответствуют вашему первоначальному описанию — раздел с надписью «Если пятница была праздничной» включает событие из среды, хотя четверг не является праздничным днем, не могли бы вы, пожалуйста, уточнить? Наконец, на какой версии SQL Server вы работаете?

2. @Brian Да, в нем хранятся данные за 30 лет. Я имею в виду, что мне нужна каждая строка с последнего рабочего дня для каждой недели, поэтому, если в таблице календаря пятница, это праздник, последний рабочий день будет в четверг, и я на SQL Server 2008. Спасибо!

Ответ №1:

Основываясь на вашем комментарии, я бы использовал общее табличное выражение:

 ;With cte_Last_Day_Of_Week
As
(
    Select 
        c.iddate
        , c.date
        , Row_Number() Over (Partition By DatePart(Week, c.date) Order By c.date Desc) As RN
    From dbo.Calendar As c
    Where c.isholiday = 0
)
  

Row_Number() Будет отмечаться дата последнего непраздничного дня каждой недели со значением 1 . Затем вы можете объединить их с этим, как с таблицей.

Дайте мне знать, имеет ли это смысл.