Получить все даты для всех диапазонов дат в таблице, используя SQL Server - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть таблица dbo.WorkSchedules(Id, From, To), где я храню диапазоны дат для графиков работы.Я хочу создать представление, которое будет иметь все даты для всех строк WorkSchedules.Благодаря этому у меня есть 1 просмотр со всеми датами для всех расписаний.

В Интернете я нашел решения только для 1 строки, например, 2 параметра начала и конца.Моя проблема заключается в том, что у меня несколько строк с начальным и конечным диапазоном.

Пример:

WorkSchedules

Id | From       | To
---+------------+-----------
1  | 2018-01-01 | 2018-01-05 
2  | 2018-01-08 | 2018-01-12

Желаемый результат

1 | 2018-01-01
2 | 2018-01-02
3 | 2018-01-03
4 | 2018-01-04
5 | 2018-01-05
6 | 2018-01-08
7 | 2018-01-09
8 | 2018-01-10
9 | 2018-01-11
10| 2018-01-12

Ответы [ 3 ]

0 голосов
/ 22 сентября 2018

Вы бы использовали рекурсивный CTE:

with dates as (
      select from, to, from as date
      from WorkSchedules
      union all
      select from, to, dateadd(day, 1, date)
      from dates
      where date < to
     )
select row_number() over (order by date), date
from dates;

Обратите внимание, что from и to являются зарезервированными словами в SQL.Это паршивые имена для идентификаторов.Я не избежал их, потому что я предполагаю, что они не являются реальными именами столбцов.

0 голосов
/ 22 сентября 2018

Если вы регулярно имеете дело с «заданиями» и «расписаниями», тогда я предлагаю, чтобы вам потребовалось постоянная календарная таблица (таблица, в которой каждая строка представляет собой уникальную дату).Вы можете динамически создавать строки для дат, но зачем делать это много раз, когда вы можете сделать это один раз и просто использовать повторно?

Календарная таблица, даже несколько десятилетий, - нет "большой "и при индексации они могут быть очень быстрыми.Вы также можете хранить информацию о праздничных и / или финансовых периодах и т. Д.

Существует множество сценариев для создания этих таблиц, вот ответ с двумя сценариями на этом сайте: https://stackoverflow.com/a/5635628/2067753

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

Если у вас есть постоянная таблица Calendar, можно использовать этот стиль запроса.:

CREATE TABLE WorkSchedules(
   Id   INTEGER  NOT NULL PRIMARY KEY 
  ,[From] DATE  NOT NULL
  ,[To]   DATE  NOT NULL
);
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (1,'2018-01-01','2018-01-05');
INSERT INTO WorkSchedules(Id,[From],[To]) VALUES (2,'2018-01-12','2018-01-12');

with range as (
    select min(ws.[From]) as dt_from, max(ws.[To]) dt_to
    from WorkSchedules as ws
    )
select c.*
from calendar as c
inner join range on c.date between range.dt_from and range.dt_to
where c.KindOfDay = 'BANKDAY'
order by c.date

и результат выглядит следующим образом (примечание: «День новостных лет» был исключен)

              Date           Year   Quarter   Month   Week   Day   DayOfYear   Weekday   Fiscal_Year   Fiscal_Quarter   Fiscal_Month   KindOfDay   Description  
 ---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- ------------- 
   1   02.01.2018 00:00:00   2018         1       1      1     2           2         2          2018                1              1   BANKDAY     NULL         
   2   03.01.2018 00:00:00   2018         1       1      1     3           3         3          2018                1              1   BANKDAY     NULL         
   3   04.01.2018 00:00:00   2018         1       1      1     4           4         4          2018                1              1   BANKDAY     NULL         
   4   05.01.2018 00:00:00   2018         1       1      1     5           5         5          2018                1              1   BANKDAY     NULL         
   5   08.01.2018 00:00:00   2018         1       1      2     8           8         1          2018                1              1   BANKDAY     NULL         
   6   09.01.2018 00:00:00   2018         1       1      2     9           9         2          2018                1              1   BANKDAY     NULL         
   7   10.01.2018 00:00:00   2018         1       1      2    10          10         3          2018                1              1   BANKDAY     NULL         
   8   11.01.2018 00:00:00   2018         1       1      2    11          11         4          2018                1              1   BANKDAY     NULL         
   9   12.01.2018 00:00:00   2018         1       1      2    12          12         5          2018                1              1   BANKDAY     NULL         

Без условия where полный диапазон:

              Date           Year   Quarter   Month   Week   Day   DayOfYear   Weekday   Fiscal_Year   Fiscal_Quarter   Fiscal_Month   KindOfDay    Description    
 ---- --------------------- ------ --------- ------- ------ ----- ----------- --------- ------------- ---------------- -------------- ----------- ---------------- 
   1   01.01.2018 00:00:00   2018         1       1      1     1           1         1          2018                1              1   HOLIDAY     New Year's Day  
   2   02.01.2018 00:00:00   2018         1       1      1     2           2         2          2018                1              1   BANKDAY     NULL            
   3   03.01.2018 00:00:00   2018         1       1      1     3           3         3          2018                1              1   BANKDAY     NULL            
   4   04.01.2018 00:00:00   2018         1       1      1     4           4         4          2018                1              1   BANKDAY     NULL            
   5   05.01.2018 00:00:00   2018         1       1      1     5           5         5          2018                1              1   BANKDAY     NULL            
   6   06.01.2018 00:00:00   2018         1       1      1     6           6         6          2018                1              1   SATURDAY    NULL            
   7   07.01.2018 00:00:00   2018         1       1      1     7           7         7          2018                1              1   SUNDAY      NULL            
   8   08.01.2018 00:00:00   2018         1       1      2     8           8         1          2018                1              1   BANKDAY     NULL            
   9   09.01.2018 00:00:00   2018         1       1      2     9           9         2          2018                1              1   BANKDAY     NULL            
  10   10.01.2018 00:00:00   2018         1       1      2    10          10         3          2018                1              1   BANKDAY     NULL            
  11   11.01.2018 00:00:00   2018         1       1      2    11          11         4          2018                1              1   BANKDAY     NULL            
  12   12.01.2018 00:00:00   2018         1       1      2    12          12         5          2018                1              1   BANKDAY     NULL            

, а выходные и праздничные дни могут быть исключены с помощью столбца KindOfDay

Здесь вы можете увидеть демонстрацию (со сборкой календарной таблицы): http://rextester.com/CTSW63441

0 голосов
/ 22 сентября 2018

Хорошо, я разработал это для вас, думая, что вы имеете в виду, что вы имели в виду 01/08/2018 как дату начала во втором ряду.

/*WorkSchedules
Id|    From    |     To
1 | 2018-01-01 | 2018-01-05 
2 | 2018-01-08 | 2018-01-12
*/

--DROP TABLE #WorkSchedules;

CREATE TABLE #WorkSchedules (
    ID int,
    [DateFrom] DATE,
    [DateTo] DATE
    )

INSERT INTO #WorkSchedules
SELECT 1, '2018-01-01', '2018-01-05'
UNION
SELECT 2, '2018-01-08', '2018-01-12'

;WITH CTEDATELIMITS AS (
    SELECT [DateFrom], [DateTo]
    FROM #WorkSchedules
    )
,CTEDATES AS
(
SELECT [DateFrom] as [DateResult] FROM CTEDATELIMITS
UNION ALL
SELECT DATEADD(Day, 1, [DateResult]) FROM CTEDATES
JOIN CTEDATELIMITS ON CTEDATES.[DateResult] >= CTEDATELIMITS.[DateFrom]
AND CTEDATES.dateResult < CTEDATELIMITS.[DateTo]
)
SELECT [DateResult] FROM CTEDATES
ORDER BY [DateResult]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...