Wie bei vielen Aufgaben in SQL, das in vielfältiger Weise gelöst werden könnte.
Sie können COUNT-Aggregatoperationen im Datumsbereich mit dem BETWEEN-Operator verwenden, um aggregierte Summen der Wochenendtage und Feiertage von einem Startdatum (OrderDate) bis zu einem Enddatum (DeliveryDate) zu erhalten.
Diese Funktionalität kann mit CTEs (Common Table Expressions) kombiniert werden, um Ihnen das Endergebnisset zu liefern, das Sie suchen.
Ich habe eine Abfrage zusammengestellt, die eine Möglichkeit darstellt, wie man es machen könnte. Ich habe auch einige Testdaten und Ergebnisse zusammengestellt, um zu veranschaulichen, wie die Abfrage funktioniert.
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')
Einige Überlegungen, die Sie gedacht bereits können, sind, dass Sie nicht beide Wochenende und Feiertage zählen wollen, die an einem Wochenende stattfinden, es sei denn, Ihr Unternehmen den Urlaub am kommenden Montag beobachtet. Der Einfachheit halber habe ich alle Feiertage ausgeschlossen, die an einem Wochenende in der Abfrage auftreten.
Sie möchten diese Art von Abfrage auch auf einen bestimmten Datumsbereich beschränken.
Das erste CTE (cteAllDates) ruft alle Daten zwischen dem Anfangs- und dem Enddatumsbereich ab.
Das zweite CTE (cteWeekendDates) bekommt alle Wochenenddaten vom ersten CTE (cteAllDates).
Der dritte CTE (ctePublicHolidays) erhält alle Feiertage, die an Wochentagen von Ihrer PublicHolidaysTable auftreten.
Die letzte CTE (cteOrders) erfüllt die Anforderung, dass die Anzahl der gesamten Tage und Arbeitstage am nächsten Tag beginnen muss, wenn das Bestelldatum nach 12:00 Uhr liegt, und die Anforderung, dass das DeliveryDate das heutige Datum verwenden sollte, wenn es null ist .
Die Select-Anweisung am Ende der CTE-Anweisungen enthält die Gesamtzahl der Tage, die Anzahl der Wochenenden, die Anzahl der Feiertage und die Arbeitstage für jede Bestellung.
;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)
Ergebnisse aus der obigen Abfrage, um die Testdaten mit ...
Was würde ich wahrscheinlich tun ist, um die oben zu vereinfachen, indem eine Kalender Tabelle um mit ausreichend großen Datumsbereichen besiedelt. Dann würde ich einige der CTE-Anweisungen nehmen und sie in Ansichten verwandeln.
Ich denke speziell wertvoll für Sie wäre eine Aussicht, die Sie die Arbeitstage ohne Wochenenden oder Feiertage bekommt. Dann könnten Sie einfach den Datumsunterschied zwischen den beiden Daten ermitteln und die Arbeitstage im selben Bereich zählen.
Zeigen Sie uns, was Sie bisher versucht haben, wird nützlich sein. –