Как и многие другие задачи в SQL, это может быть решена несколькими способами.
Вы можете использовать агрегированные операции COUNT в диапазоне дат с оператором BETWEEN, чтобы получить итоговые суммы дней выходных дней и праздничных дней с даты начала (OrderDate) до даты окончания (DeliveryDate).
Эта функциональность может быть объединена с CTE (Common Table Expressions), чтобы дать вам набор конечных результатов, который вы ищете.
Я собрал запрос, который иллюстрирует один способ, которым вы могли бы это сделать. Я также собрал некоторые тестовые данные и результаты, чтобы проиллюстрировать, как работает запрос.
DECLARE @DateRangeBegin DATETIME = '2016-01-01'
, @DateRangeEnd DATETIME = '2016-07-01'
DECLARE @OrderTable TABLE
(OrderNum INT, OrderDate DATETIME, DeliveryDate DATETIME)
INSERT INTO @OrderTable VALUES
(1, '2016-02-12 09:30', '2016-03-01 13:00')
, (2, '2016-03-15 13:00', '2016-03-30 13:00')
, (3, '2016-03-22 14:00', NULL)
, (4, '2016-05-06 10:00', '2016-05-19 13:00')
DECLARE @PublicHolidaysTable TABLE
(PublicHolidayDate DATETIME, Description NVARCHAR(255))
INSERT INTO @PublicHolidaysTable VALUES
('2016-02-15', 'President''s Day')
, ('2016-03-17', 'St. Patrick''s Day')
, ('2016-03-25', 'Good Friday')
, ('2016-03-27', 'Easter Sunday')
, ('2016-05-05', 'Cinco de Mayo')
Некоторые соображения вы можете уже думали о том, что вы не хотите, чтобы рассчитывать как в выходные дни и праздники, которые происходят в выходные дни, если ваша компания не соблюдает праздник на следующий понедельник. Для простоты я исключил любой праздник, который происходит в выходной день в запросе.
Вы также хотите ограничить этот тип запросов конкретным диапазоном дат.
Первый CTE (cteAllDates) получает все даты между диапазоном начала и окончания даты.
Второй CTE (cteWeekendDates) получает все выходные от первого CTE (cteAllDates).
Третий CTE (ctePublicHolidays) получает все праздники, которые происходят в будние дни с вашего сайта PublicHolidaysTable.
Последний CTE (cteOrders) выполняет требование о том, что общее количество дней и рабочих дней должно начинаться со следующего дня, если OrderDate находится после 12:00 PM, и требование, чтобы DeliveryDate использовала сегодняшнюю дату, если она равна нулю ,
Оператор select в конце заявлений CTE получает ваш общий счет дня, количество выходных дней, количество праздников и рабочие дни для каждого заказа.
;WITH cteAllDates AS (
SELECT 1 [DayID]
, @DateRangeBegin [CalendarDate]
, DATENAME(dw, @DateRangeBegin) [NameOfDay]
UNION ALL
SELECT cteAllDates.DayID + 1 [DayID]
, DATEADD(dd, 1 ,cteAllDates.CalendarDate) [CalenderDate]
, DATENAME(dw, DATEADD(d, 1 ,cteAllDates.CalendarDate)) [NameOfDay]
FROM cteAllDates
WHERE DATEADD(d,1,cteAllDates.CalendarDate) < @DateRangeEnd
)
, cteWeekendDates AS (
SELECT CalendarDate
FROM cteAllDates
WHERE NameOfDay IN ('Saturday','Sunday')
)
, ctePublicHolidays AS (
SELECT PublicHolidayDate
FROM @PublicHolidaysTable
WHERE DATENAME(dw, PublicHolidayDate) NOT IN ('Saturday', 'Sunday')
)
, cteOrders AS (
SELECT OrderNum
, OrderDate
, CASE WHEN DATEPART(hh, OrderDate) >= 12 THEN DATEADD(dd, 1, OrderDate)
ELSE OrderDate
END [AdjustedOrderDate]
, CASE WHEN DeliveryDate IS NOT NULL THEN DeliveryDate
ELSE GETDATE()
END [DeliveryDate]
FROM @OrderTable
)
SELECT o.OrderNum
, o.OrderDate
, o.DeliveryDate
, DATEDIFF(DAY, o.AdjustedOrderDate, o.DeliveryDate) [TotalDayCount]
, (SELECT COUNT(*) FROM cteWeekendDates w
WHERE w.CalendarDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [WeekendDayCount]
, (SELECT COUNT(*) FROM ctePublicHolidays h
WHERE h.PublicHolidayDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [HolidayCount]
, DATEDIFF(DAY, o.AdjustedOrderDate, o.DeliveryDate)
- (SELECT COUNT(*) FROM cteWeekendDays w
WHERE w.CalendarDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate)
- (SELECT COUNT(*) FROM ctePublicHolidays h
WHERE h.PublicHolidayDate BETWEEN o.AdjustedOrderDate AND o.DeliveryDate) [WorkingDays]
FROM cteOrders o
WHERE o.OrderDate BETWEEN @DateRangeBegin AND @DateRangeEnd
OPTION (MaxRecursion 500)
Результаты вышеупомянутого запроса с использованием тестовых данных ...
![Query Results](https://i.stack.imgur.com/ihWda.png)
То, что я бы, вероятно, сделать, это упростить выше, добавив таблицу календаря, населенную с достаточно широким диапазоном дат. Затем я бы взял некоторые из заявлений CTE и превратил их в представления.
Я думаю, что особенно ценным для вас было бы представление, которое даст вам рабочие дни без выходных или праздничных дней. Тогда вы можете просто получить разницу дат между двумя датами и подсчитать рабочие дни в том же диапазоне.
Показывать нам, что вы пробовали до сих пор, будет полезно. –