Ich habe gerade festgestellt, dass dieser Code nicht immer funktioniert! Ich habe es versucht: SET @StartDate = '28 -mar-2011 'SET @EndDate = '29 -mar-2011' Die Antwort zählte es als 2 Tage
greektreat
16
@greektreat Es funktioniert gut. Es ist nur so, dass sowohl @StartDate als auch @EndDate in der Zählung enthalten sind. Wenn Sie möchten, dass Montag bis Dienstag als 1 Tag zählt, entfernen Sie einfach die "+ 1" nach dem ersten DATEDIFF. Dann erhalten Sie auch Fri-> Sa = 0, Fri-> So = 0, Fri-> Mo = 1.
Joe Daley
6
Als Folge von @JoeDaley. Wenn Sie die + 1 nach dem DATEDIFF entfernen, um das Startdatum von der Zählung auszuschließen, müssen Sie auch den CASE-Teil davon anpassen. Am Ende habe ich Folgendes verwendet: + (FALL WENN DATENAME (dw, @StartDate) = 'Samstag' DANN 1 SONST 0 ENDE) - (FALL WENN DATENAME (dw, @EndDate) = 'Samstag' DANN 1 SONST 0 ENDE)
Sequenzia
7
Die Dateinamenfunktion ist vom Gebietsschema abhängig. Eine robustere, aber auch dunkelere Lösung besteht darin, die letzten beiden Zeilen durch folgende zu ersetzen:-(case datepart(dw, @StartDate)+@@datefirst when 8 then 1 else 0 end) -(case datepart(dw, @EndDate)+@@datefirst when 7 then 1 when 14 then 1 else 0 end)
Torben Klein
2
Um den Kommentar von @ Sequenzia zu verdeutlichen, würden Sie die Fallaussagen über den Sonntag vollständig ENTFERNEN und nur+(CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END) - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
Andy Raddatz
32
In Berechnung der Arbeitstage finden Sie einen guten Artikel zu diesem Thema, aber wie Sie sehen, ist er nicht so weit fortgeschritten.
--Changing current database to the Master database allows function to be shared by everyone.USE MASTER
GO--If the function already exists, drop it.IFEXISTS(SELECT*FROM dbo.SYSOBJECTSWHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')AND XType IN(N'FN', N'IF', N'TF'))DROPFUNCTION[dbo].[fn_WorkDays]
GOCREATEFUNCTION dbo.fn_WorkDays--Presets--Define the input parameters (OK if reversed by mistake).(@StartDate DATETIME,@EndDate DATETIME =NULL--@EndDate replaced by @StartDate when DEFAULTed)--Define the output data type.
RETURNS INTAS--Calculate the RETURN of the function.BEGIN--Declare local variables--Temporarily holds @EndDate during date reversal.DECLARE@Swap DATETIME--If the Start Date is null, return a NULL and exit.IF@StartDate ISNULLRETURNNULL--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).IF@EndDate ISNULLSELECT@EndDate =@StartDate--Strip the time element from both dates (just to be safe) by converting to whole days and back to a date.--Usually faster than CONVERT.--0 is a date (01/01/1900 00:00:00.000)SELECT@StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate),0),@EndDate = DATEADD(dd,DATEDIFF(dd,0,@EndDate),0)--If the inputs are in the wrong order, reverse them.IF@StartDate >@EndDateSELECT@Swap =@EndDate,@EndDate =@StartDate,@StartDate =@Swap--Calculate and return the number of workdays using the input parameters.--This is the meat of the function.--This is really just one formula with a couple of parts that are listed on separate lines for documentation purposes.RETURN(SELECT--Start with total number of days including weekends(DATEDIFF(dd,@StartDate,@EndDate)+1)--Subtact 2 days for each full weekend-(DATEDIFF(wk,@StartDate,@EndDate)*2)--If StartDate is a Sunday, Subtract 1-(CASEWHEN DATENAME(dw,@StartDate)='Sunday'THEN1ELSE0END)--If EndDate is a Saturday, Subtract 1-(CASEWHEN DATENAME(dw,@EndDate)='Saturday'THEN1ELSE0END))END
GO
Wenn Sie einen benutzerdefinierten Kalender verwenden müssen, müssen Sie möglicherweise einige Überprüfungen und einige Parameter hinzufügen. Hoffentlich bietet es einen guten Ausgangspunkt.
Vielen Dank, dass Sie den Link eingefügt haben, um zu verstehen, wie dies funktioniert. Das Schreiben auf sqlservercentral war großartig!
Chris Porter
20
Alle Ehre gebührt Bogdan Maxim & Peter Mortensen. Dies ist ihr Beitrag, ich habe gerade Feiertage zur Funktion hinzugefügt (Dies setzt voraus, dass Sie eine Tabelle "tblHolidays" mit einem Datum / Uhrzeit-Feld "HolDate" haben.
--Changing current database to the Master database allows function to be shared by everyone.USE MASTER
GO--If the function already exists, drop it.IFEXISTS(SELECT*FROM dbo.SYSOBJECTSWHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')AND XType IN(N'FN', N'IF', N'TF'))DROPFUNCTION[dbo].[fn_WorkDays]
GOCREATEFUNCTION dbo.fn_WorkDays--Presets--Define the input parameters (OK if reversed by mistake).(@StartDate DATETIME,@EndDate DATETIME =NULL--@EndDate replaced by @StartDate when DEFAULTed)--Define the output data type.
RETURNS INTAS--Calculate the RETURN of the function.BEGIN--Declare local variables--Temporarily holds @EndDate during date reversal.DECLARE@Swap DATETIME--If the Start Date is null, return a NULL and exit.IF@StartDate ISNULLRETURNNULL--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).IF@EndDate ISNULLSELECT@EndDate =@StartDate--Strip the time element from both dates (just to be safe) by converting to whole days and back to a date.--Usually faster than CONVERT.--0 is a date (01/01/1900 00:00:00.000)SELECT@StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate),0),@EndDate = DATEADD(dd,DATEDIFF(dd,0,@EndDate),0)--If the inputs are in the wrong order, reverse them.IF@StartDate >@EndDateSELECT@Swap =@EndDate,@EndDate =@StartDate,@StartDate =@Swap--Calculate and return the number of workdays using the input parameters.--This is the meat of the function.--This is really just one formula with a couple of parts that are listed on separate lines for documentation purposes.RETURN(SELECT--Start with total number of days including weekends(DATEDIFF(dd,@StartDate,@EndDate)+1)--Subtact 2 days for each full weekend-(DATEDIFF(wk,@StartDate,@EndDate)*2)--If StartDate is a Sunday, Subtract 1-(CASEWHEN DATENAME(dw,@StartDate)='Sunday'THEN1ELSE0END)--If EndDate is a Saturday, Subtract 1-(CASEWHEN DATENAME(dw,@EndDate)='Saturday'THEN1ELSE0END)--Subtract all holidays-(Select Count(*)from[DB04\DB04].[Gateway].[dbo].[tblHolidays]where[HolDate]between@StartDate and@EndDate ))END
GO-- Test Script/*
declare @EndDate datetime= dateadd(m,2,getdate())
print @EndDate
select [Master].[dbo].[fn_WorkDays] (getdate(), @EndDate)
*/
Hallo Dan B. Nur um Sie wissen zu lassen, dass Ihre Version davon ausgeht, dass die Tabelle tblHolidays keine Samstage und Montage enthält, was manchmal vorkommt. Wie auch immer, danke, dass du deine Version geteilt hast. Prost
Julio Nobre
3
Julio - Ja - Meine Version geht davon aus, dass Samstag und Sonntag (nicht Montag) Wochenenden sind und daher kein "nicht geschäftlicher" Tag. Aber wenn Sie am Wochenende arbeiten, dann ist jeder Tag ein "Arbeitstag", und Sie können den Samstag- und Sonntagsteil der Klausel auskommentieren und einfach alle Ihre Feiertage zur Tabelle tblHolidays hinzufügen.
Dan B
1
Danke Dan. Ich habe dies in meine Funktion aufgenommen und einen Scheck für Wochenenden hinzugefügt, da meine DateDimensions-Tabelle alle Daten, Feiertage usw. enthält. Bei Ihrer Funktion habe ich gerade Folgendes hinzugefügt: und IsWeekend = 0 nach wo [HolDate] zwischen StartDate und EndDate)
AlsoKnownAsJazz
Wenn die Feiertagstabelle Feiertage an Wochenenden enthält, können Sie die Kriterien wie folgt ändern: WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6Nur Feiertage von Montag bis Freitag zählen.
Andre
7
Ein anderer Ansatz zur Berechnung von Arbeitstagen besteht darin, eine WHILE-Schleife zu verwenden, die im Wesentlichen einen Datumsbereich durchläuft und ihn um 1 erhöht, wenn festgestellt wird, dass die Tage zwischen Montag und Freitag liegen. Das vollständige Skript zur Berechnung der Arbeitstage mithilfe der WHILE-Schleife ist unten dargestellt:
Obwohl die Option WHILE-Schleife sauberer ist und weniger Codezeilen verwendet, kann dies zu einem Leistungsengpass in Ihrer Umgebung führen, insbesondere wenn sich Ihr Datumsbereich über mehrere Jahre erstreckt.
Meine Version der akzeptierten Antwort wird als Funktion mit verwendet DATEPART, sodass ich keinen Zeichenfolgenvergleich in der Zeile mit durchführen muss
DATENAME(dw,@StartDate)='Sunday'
Wie auch immer, hier ist meine Business-Datediff-Funktion
SET ANSI_NULLS ON
GOSET QUOTED_IDENTIFIER ON
GOCREATEFUNCTION BDATEDIFF(@startdate as DATETIME,@enddate as DATETIME)
RETURNS INTASBEGINDECLARE@res intSET@res =(DATEDIFF(dd,@startdate,@enddate)+1)-(DATEDIFF(wk,@startdate,@enddate)*2)-(CASEWHEN DATEPART(dw,@startdate)=1THEN1ELSE0END)-(CASEWHEN DATEPART(dw,@enddate)=7THEN1ELSE0END)RETURN@resEND
GO
Wenn Sie eine Postleitzahl, XML oder Datenproben, bitte diese Zeilen im Texteditor und klicken Sie auf den „Code - Beispiele“ Taste ({}) auf der Editor - Symbolleiste zu schön Format und die Syntax markieren Sie markieren!
marc_s
Großartig, keine Peripheriefunktionen oder Aktualisierungen der Datenbank erforderlich. Vielen Dank. Ich liebe den Saltire übrigens :-)
Brian Scott
Super Lösung. Ich habe in Formeln für Variablen eingebettet, die in einem Webi-Universum verwendet werden sollen, um Wochentage (MF) zwischen den Daten in 2 Tabellenspalten wie folgt zu berechnen ... (((((DATEDIFF (Tag, table.col1, table.col2) +1)) - ((CASE DATENAME (Wochentag, table.col2) WENN 'Samstag' DANN 1 WENN 'Sonntag' DANN 2 SONST 0 ENDE)) / 7) * 5) + (((DATEDIFF (Tag, table.col1, table.col2)))) ) +1) - ((CASE DATENAME (Wochentag, table.col2) WENN 'Samstag' DANN 1 WENN 'Sonntag' DANN 2 SONST 0 ENDE))% 7)
Hilary
5
(Ich bin ein paar Punkte schüchtern, um Privilegien zu kommentieren)
Wenn Sie in der eleganten Lösung von CMS auf den Tag +1 verzichten möchten , beachten Sie, dass Sie eine negative Antwort erhalten, wenn Start- und Enddatum am selben Wochenende liegen. Das heißt, 2008/10/26 bis 2008/10/26 geben -1 zurück.
In Bezug auf Ihre Urlaubsabzüge. Was ist, wenn das Startdatum der 1. Januar und das Enddatum der 31. Dezember ist? Sie werden nur 2 subtrahieren - was falsch ist. Ich schlage vor, DATEDIFF (Tag, Start_Datum, Datum) und dasselbe für End_Date anstelle von 'SELECT COUNT (*) FROM Holiday ...' zu verwenden.
Illia Ratkevych
4
Hier ist eine Version, die gut funktioniert (glaube ich). Die Feiertagstabelle enthält Holiday_date-Spalten, die die von Ihrem Unternehmen beobachteten Feiertage enthalten.
Diese Feiertagstermine können auch auf Wochenenden fallen. Und für einige wird der Feiertag am Sonntag durch den nächsten Montag ersetzt.
Irawan Soetomo
3
Ich weiß, dass dies eine alte Frage ist, aber ich brauchte eine Formel für Arbeitstage ohne Startdatum, da ich mehrere Elemente habe und die Tage benötigt, um richtig zu akkumulieren.
Keine der nicht iterativen Antworten hat bei mir funktioniert.
Ich habe eine Definition wie verwendet
Häufigkeit, mit der Mitternacht bis Montag, Dienstag, Mittwoch, Donnerstag und Freitag vergangen sind
(andere zählen vielleicht Mitternacht bis Samstag statt Montag)
Dieser hat es für mich getan, aber ich musste eine kleine Änderung vornehmen. Es wurde nicht berücksichtigt, wann @StartDateein Samstag oder Freitag ist. Hier ist meine Version:DATEDIFF(day, @StartDate, @EndDate) - DATEDIFF(week, @StartDate, @EndDate) - DATEDIFF(week, DATEADD(day, 1, @StartDate), DATEADD(day, 1, @EndDate)) - (CASE WHEN DATEPART(WEEKDAY, @StartDate) IN (1, 7) THEN 1 ELSE 0 END) + 1
caiosm1005
@ caiosm1005, Samstag bis Sonntag gibt 0 zurück, Samstag bis Montag gibt 1 zurück, Freitag bis Samstag gibt 0 zurück. Alle stimmen mit meiner Definition überein. Ihr Code wird nicht korrekt akkumuliert (z. B. 6 für Freitag bis Freitag, aber 5 für Montag bis Montag)
Adrianm
3
Dies ist im Grunde die Antwort von CMS, ohne sich auf eine bestimmte Spracheinstellung verlassen zu müssen. Und da wir für Generika fotografieren, sollte dies auch für alle @@datefirstEinstellungen funktionieren .
datediff(day,<start>,<end>)+1- datediff(week,<start>,<end>)*2/* if start is a Sunday, adjust by -1 */+casewhen datepart(weekday,<start>)=8-@@datefirst then-1else0end/* if end is a Saturday, adjust by -1 */+casewhen datepart(weekday,<end>)=(13-@@datefirst)%7+1then-1else0end
datediff(week, ...)Verwendet wochenlang immer eine Grenze von Samstag zu Sonntag, sodass der Ausdruck deterministisch ist und nicht geändert werden muss (solange unsere Definition von Wochentagen von Montag bis Freitag konsistent ist). Die Nummerierung der Tage variiert je nach @@datefirstEinstellung und Einstellung modifizierte Berechnungen behandeln diese Korrektur mit der kleinen Komplikation einer modularen Arithmetik.
Eine sauberere Möglichkeit, mit der Sache am Samstag / Sonntag umzugehen, besteht darin, die Daten vor dem Extrahieren eines Wochentagswerts zu übersetzen. Nach dem Verschieben stimmen die Werte wieder mit einer festen (und wahrscheinlich bekannteren) Nummerierung überein, die am Sonntag mit 1 beginnt und am Samstag mit 7 endet.
Ich habe diese Form der Lösung mindestens bis 2002 und einen Artikel von Itzik Ben-Gan zurückverfolgt. ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) Obwohl eine kleine Änderung erforderlich war, da neuere dateTypen keine Datumsarithmetik zulassen, ist sie ansonsten identisch.
EDIT: Ich habe das hinzugefügt +1, was irgendwie weggelassen wurde. Es ist auch erwähnenswert, dass diese Methode immer die Start- und Endtage zählt. Es wird auch davon ausgegangen, dass das Enddatum am oder nach dem Startdatum liegt.
Beachten Sie, dass dies für viele Daten an Wochenenden zu falschen Ergebnissen führt, sodass sie nicht addiert werden (Fri-> Mo sollte mit Fri-> Sa + Sa-> So + So-> Mo identisch sein). Fri-> Sat sollte 0 sein (richtig), Sat-> Sun sollte 0 sein (falsch -1), Sun-> Mon sollte 1 sein (falsch 0). Andere Fehler, die sich daraus ergeben, sind Sat-> Sat = -1, Sun-> Sun = -1, Sun-> Sat = 4
Adrianm
@adrianm Ich glaube, ich hatte die Probleme behoben. Eigentlich war das Problem, dass es immer um eins war, weil ich diesen Teil versehentlich fallen gelassen hatte.
shawnt00
Danke für das Update. Ich dachte, Ihre Formel schließt das Startdatum aus, was ich brauchte. Ich habe es selbst gelöst und als weitere Antwort hinzugefügt.
Adrianm
2
Verwenden einer Datumstabelle:
DECLARE@StartDate date ='2014-01-01',@EndDate date ='2014-01-31';SELECT
COUNT(*)As NumberOfWeekDays
FROM dbo.Calendar
WHERE CalendarDate BETWEEN@StartDate AND@EndDate
AND IsWorkDay =1;
Wenn Sie das nicht haben, können Sie eine Zahlentabelle verwenden:
DECLARE@StartDate datetime ='2014-01-01',@EndDate datetime ='2014-01-31';SELECT
SUM(CASEWHEN DATEPART(dw, DATEADD(dd, Number-1,@StartDate))BETWEEN2AND6THEN1ELSE0END)As NumberOfWeekDays
FROM dbo.Numbers
WHERE Number <= DATEDIFF(dd,@StartDate,@EndDate)+1-- Number table starts at 1, we want a 0 base
Sie sollten beide schnell sein und die Mehrdeutigkeit / Komplexität beseitigen. Die erste Option ist die beste, aber wenn Sie keine Kalendertabelle haben, können Sie immer eine Zahlentabelle mit einem CTE erstellen.
DECLARE@StartDate datetime,@EndDate datetime
select@StartDate='3/2/2010',@EndDate='3/7/2010'DECLARE@TotalDays INT,@WorkDays INT
DECLARE@ReducedDayswithEndDate INT
DECLARE@WeekPart INT
DECLARE@DatePart INT
SET@TotalDays= DATEDIFF(day,@StartDate,@EndDate)+1SELECT@ReducedDayswithEndDate =CASE DATENAME(weekday,@EndDate)WHEN'Saturday'THEN1WHEN'Sunday'THEN2ELSE0ENDSET@TotalDays=@TotalDays-@ReducedDayswithEndDate
SET@WeekPart=@TotalDays/7;SET@DatePart=@TotalDays%7;SET@WorkDays=(@WeekPart*5)+@DatePart
SELECT@WorkDays
Ich habe die verschiedenen Beispiele hier genommen, aber in meiner speziellen Situation haben wir ein @PromisedDate für die Lieferung und ein @ReceivedDate für den tatsächlichen Empfang des Artikels. Wenn ein Artikel vor dem "PromisedDate" eingegangen ist, wurden die Berechnungen nicht korrekt summiert, es sei denn, ich habe die in die Funktion übergebenen Daten in Kalenderreihenfolge bestellt. Ich wollte die Daten nicht jedes Mal überprüfen und habe die Funktion geändert, um dies für mich zu erledigen.
CreateFUNCTION[dbo].[fnGetBusinessDays](@PromiseDate date,@ReceivedDate date
)
RETURNS integer
ASBEGINDECLARE@days integer
SELECT@days =Casewhen@PromiseDate >@ReceivedDate Then
DATEDIFF(d,@PromiseDate,@ReceivedDate)+
ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate))*2+CASEWHEN DATENAME(dw,@PromiseDate)<>'Saturday'AND DATENAME(dw,@ReceivedDate)='Saturday'THEN1WHEN DATENAME(dw,@PromiseDate)='Saturday'AND DATENAME(dw,@ReceivedDate)<>'Saturday'THEN-1ELSE0END+(Select COUNT(*)FROM CompanyHolidays
WHERE HolidayDate BETWEEN@ReceivedDate AND@PromiseDate
AND DATENAME(dw, HolidayDate)<>'Saturday'AND DATENAME(dw, HolidayDate)<>'Sunday')Else
DATEDIFF(d,@PromiseDate,@ReceivedDate)-
ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate))*2-CASEWHEN DATENAME(dw,@PromiseDate)<>'Saturday'AND DATENAME(dw,@ReceivedDate)='Saturday'THEN1WHEN DATENAME(dw,@PromiseDate)='Saturday'AND DATENAME(dw,@ReceivedDate)<>'Saturday'THEN-1ELSE0END-(Select COUNT(*)FROM CompanyHolidays
WHERE HolidayDate BETWEEN@PromiseDate and@ReceivedDate
AND DATENAME(dw, HolidayDate)<>'Saturday'AND DATENAME(dw, HolidayDate)<>'Sunday')EndRETURN(@days)END
Wenn Sie einem bestimmten Datum Arbeitstage hinzufügen müssen, können Sie eine Funktion erstellen, die von einer unten beschriebenen Kalendertabelle abhängt:
CREATETABLE Calendar
(
dt SMALLDATETIME PRIMARYKEY,
IsWorkDay BIT
);--fill the rows with normal days, weekends and holidays.createfunction AddWorkingDays (@initialDate smalldatetime,@numberOfDays int)
returns smalldatetime asbegindeclare@result smalldatetime
set@result =(select t.dt from(select dt, ROW_NUMBER()over(orderby dt)as daysAhead from calendar
where dt >@initialDate
and IsWorkDay =1) t
where t.daysAhead =@numberOfDays
)return@result
end
Wie bei DATEDIFF betrachte ich das Enddatum nicht als Teil des Intervalls. Die Anzahl der (zum Beispiel) Sonntage zwischen @StartDate und @EndDate ist die Anzahl der Sonntage zwischen einem "anfänglichen" Montag und dem @EndDate abzüglich der Anzahl der Sonntage zwischen diesem "anfänglichen" Montag und dem @StartDate. Wenn wir das wissen, können wir die Anzahl der Arbeitstage wie folgt berechnen:
CREATEFUNCTION dbo.fn_WorkDays(@StartDate DATETIME,@EndDate DATETIME=NULL)
RETURNS INT
ASBEGINDECLARE@Days int
SET@Days =0IF@EndDate =NULLSET@EndDate = EOMONTH(@StartDate)--last date of the monthWHILE DATEDIFF(dd,@StartDate,@EndDate)>=0BEGINIF DATENAME(dw,@StartDate)<>'Saturday'and DATENAME(dw,@StartDate)<>'Sunday'andNot((Day(@StartDate)=1And Month(@StartDate)=1))--New Year's Day.andNot((Day(@StartDate)=4And Month(@StartDate)=7))--Independence Day.BEGINSET@Days =@Days +1ENDSET@StartDate = DATEADD(dd,1,@StartDate)ENDRETURN@Days
END
Ich fand die folgende TSQL eine ziemlich elegante Lösung (ich habe keine Berechtigung zum Ausführen von Funktionen). Ich fand die DATEDIFFIgnoranten DATEFIRSTund wollte, dass mein erster Tag der Woche ein Montag ist. Ich wollte auch, dass der erste Arbeitstag auf Null gesetzt wird und wenn er auf ein Wochenende fällt, wird Montag eine Null sein. Dies kann jemandem helfen, der eine etwas andere Anforderung hat :)
Es werden keine Feiertage behandelt
SET DATEFIRST 1SELECT,(DATEDIFF(DD,[StartDate],[EndDate]))-(DATEDIFF(wk,[StartDate],[EndDate]))-(DATEDIFF(wk, DATEADD(dd,-@@DATEFIRST,[StartDate]), DATEADD(dd,-@@DATEFIRST,[EndDate])))AS[WorkingDays]FROM/*Your Table*/
Ein Ansatz besteht darin, die Daten von Anfang bis Ende in Verbindung mit einem Fallausdruck zu durchlaufen, der prüft, ob der Tag kein Samstag oder Sonntag ist, und ihn markiert (1 für Wochentag, 0 für Wochenende). Und am Ende summieren Sie einfach die Flags (dies entspricht der Anzahl der 1-Flags, da das andere Flag 0 ist), um die Anzahl der Wochentage anzugeben.
Sie können eine Dienstprogrammfunktion vom Typ GetNums (startNumber, endNumber) verwenden, die eine Reihe von Zahlen für die Schleife vom Startdatum bis zum Enddatum generiert. Eine Implementierung finden Sie unter http://tsql.solidq.com/SourceCodes/GetNums.txt . Die Logik kann auch erweitert werden, um Feiertage zu berücksichtigen (z. B. wenn Sie eine Feiertagstabelle haben).
declare@date1 as datetime ='19900101'declare@date2 as datetime ='19900120'select sum(casewhen DATENAME(DW,currentDate)notin('Saturday','Sunday')then1else0end)as noOfWorkDays
from dbo.GetNums(0,DATEDIFF(day,@date1,@date2)-1)as Num
crossapply(select DATEADD(day,n,@date1))as Dates(currentDate)
Ich habe einige Ideen von anderen ausgeliehen, um meine Lösung zu erstellen. Ich verwende Inline-Code, um Wochenenden und US-Bundesfeiertage zu ignorieren. In meiner Umgebung ist EndDate möglicherweise null, steht jedoch niemals vor StartDate.
CREATEFUNCTION dbo.ufn_CalculateBusinessDays(@StartDate DATE,@EndDate DATE =NULL)
RETURNS INT
ASBEGINDECLARE@TotalBusinessDays INT =0;DECLARE@TestDate DATE =@StartDate;IF@EndDate ISNULLRETURNNULL;WHILE@TestDate <@EndDate
BEGINDECLARE@Month INT = DATEPART(MM,@TestDate);DECLARE@Day INT = DATEPART(DD,@TestDate);DECLARE@DayOfWeek INT = DATEPART(WEEKDAY,@TestDate)-1;--Monday = 1, Tuesday = 2, etc.DECLARE@DayOccurrence INT =(@Day -1)/7+1;--Nth day of month (3rd Monday, for example)--Increment business day counter if not a weekend or holidaySELECT@TotalBusinessDays +=(SELECTCASE--Saturday OR SundayWHEN@DayOfWeek IN(6,7)THEN0--New Year's DayWHEN@Month =1AND@Day =1THEN0--MLK Jr. DayWHEN@Month =1AND@DayOfWeek =1AND@DayOccurrence =3THEN0--G. Washington's BirthdayWHEN@Month =2AND@DayOfWeek =1AND@DayOccurrence =3THEN0--Memorial DayWHEN@Month =5AND@DayOfWeek =1AND@Day BETWEEN25AND31THEN0--Independence DayWHEN@Month =7AND@Day =4THEN0--Labor DayWHEN@Month =9AND@DayOfWeek =1AND@DayOccurrence =1THEN0--Columbus DayWHEN@Month =10AND@DayOfWeek =1AND@DayOccurrence =2THEN0--Veterans DayWHEN@Month =11AND@Day =11THEN0--ThanksgivingWHEN@Month =11AND@DayOfWeek =4AND@DayOccurrence =4THEN0--ChristmasWHEN@Month =12AND@Day =25THEN0ELSE1ENDAS Result);SET@TestDate = DATEADD(dd,1,@TestDate);ENDRETURN@TotalBusinessDays;END
Antworten:
Für Arbeitstage von Montag bis Freitag können Sie dies mit einem einzigen SELECT wie folgt tun:
Wenn Sie Feiertage einbeziehen möchten, müssen Sie es ein wenig ausarbeiten ...
quelle
-(case datepart(dw, @StartDate)+@@datefirst when 8 then 1 else 0 end) -(case datepart(dw, @EndDate)+@@datefirst when 7 then 1 when 14 then 1 else 0 end)
+(CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END) - (CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
In Berechnung der Arbeitstage finden Sie einen guten Artikel zu diesem Thema, aber wie Sie sehen, ist er nicht so weit fortgeschritten.
Wenn Sie einen benutzerdefinierten Kalender verwenden müssen, müssen Sie möglicherweise einige Überprüfungen und einige Parameter hinzufügen. Hoffentlich bietet es einen guten Ausgangspunkt.
quelle
Alle Ehre gebührt Bogdan Maxim & Peter Mortensen. Dies ist ihr Beitrag, ich habe gerade Feiertage zur Funktion hinzugefügt (Dies setzt voraus, dass Sie eine Tabelle "tblHolidays" mit einem Datum / Uhrzeit-Feld "HolDate" haben.
quelle
WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6
Nur Feiertage von Montag bis Freitag zählen.Ein anderer Ansatz zur Berechnung von Arbeitstagen besteht darin, eine WHILE-Schleife zu verwenden, die im Wesentlichen einen Datumsbereich durchläuft und ihn um 1 erhöht, wenn festgestellt wird, dass die Tage zwischen Montag und Freitag liegen. Das vollständige Skript zur Berechnung der Arbeitstage mithilfe der WHILE-Schleife ist unten dargestellt:
Obwohl die Option WHILE-Schleife sauberer ist und weniger Codezeilen verwendet, kann dies zu einem Leistungsengpass in Ihrer Umgebung führen, insbesondere wenn sich Ihr Datumsbereich über mehrere Jahre erstreckt.
Weitere Methoden zur Berechnung von Arbeitstagen und -stunden finden Sie in diesem Artikel: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql-server/
quelle
Meine Version der akzeptierten Antwort wird als Funktion mit verwendet
DATEPART
, sodass ich keinen Zeichenfolgenvergleich in der Zeile mit durchführen mussWie auch immer, hier ist meine Business-Datediff-Funktion
quelle
quelle
(Ich bin ein paar Punkte schüchtern, um Privilegien zu kommentieren)
Wenn Sie in der eleganten Lösung von CMS auf den Tag +1 verzichten möchten , beachten Sie, dass Sie eine negative Antwort erhalten, wenn Start- und Enddatum am selben Wochenende liegen. Das heißt, 2008/10/26 bis 2008/10/26 geben -1 zurück.
meine eher vereinfachende Lösung:
.. wodurch auch alle fehlerhaften Beiträge mit Startdatum nach Enddatum auf Null gesetzt werden. Etwas, nach dem Sie vielleicht suchen oder nicht.
quelle
Für den Unterschied zwischen Daten einschließlich Feiertagen ging ich diesen Weg:
1) Tabelle mit Feiertagen:
2) Ich hatte meine Planungstabelle wie diese und wollte die Spalte Work_Days füllen, die leer war:
3) Um "Work_Days" später zum Ausfüllen meiner Spalte zu bekommen, musste ich nur:
Hoffe ich konnte helfen.
Prost
quelle
Hier ist eine Version, die gut funktioniert (glaube ich). Die Feiertagstabelle enthält Holiday_date-Spalten, die die von Ihrem Unternehmen beobachteten Feiertage enthalten.
quelle
Ich weiß, dass dies eine alte Frage ist, aber ich brauchte eine Formel für Arbeitstage ohne Startdatum, da ich mehrere Elemente habe und die Tage benötigt, um richtig zu akkumulieren.
Keine der nicht iterativen Antworten hat bei mir funktioniert.
Ich habe eine Definition wie verwendet
(andere zählen vielleicht Mitternacht bis Samstag statt Montag)
Am Ende hatte ich diese Formel
quelle
@StartDate
ein Samstag oder Freitag ist. Hier ist meine Version:DATEDIFF(day, @StartDate, @EndDate) - DATEDIFF(week, @StartDate, @EndDate) - DATEDIFF(week, DATEADD(day, 1, @StartDate), DATEADD(day, 1, @EndDate)) - (CASE WHEN DATEPART(WEEKDAY, @StartDate) IN (1, 7) THEN 1 ELSE 0 END) + 1
Dies ist im Grunde die Antwort von CMS, ohne sich auf eine bestimmte Spracheinstellung verlassen zu müssen. Und da wir für Generika fotografieren, sollte dies auch für alle
@@datefirst
Einstellungen funktionieren .datediff(week, ...)
Verwendet wochenlang immer eine Grenze von Samstag zu Sonntag, sodass der Ausdruck deterministisch ist und nicht geändert werden muss (solange unsere Definition von Wochentagen von Montag bis Freitag konsistent ist). Die Nummerierung der Tage variiert je nach@@datefirst
Einstellung und Einstellung modifizierte Berechnungen behandeln diese Korrektur mit der kleinen Komplikation einer modularen Arithmetik.Eine sauberere Möglichkeit, mit der Sache am Samstag / Sonntag umzugehen, besteht darin, die Daten vor dem Extrahieren eines Wochentagswerts zu übersetzen. Nach dem Verschieben stimmen die Werte wieder mit einer festen (und wahrscheinlich bekannteren) Nummerierung überein, die am Sonntag mit 1 beginnt und am Samstag mit 7 endet.
Ich habe diese Form der Lösung mindestens bis 2002 und einen Artikel von Itzik Ben-Gan zurückverfolgt. ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) Obwohl eine kleine Änderung erforderlich war, da neuere
date
Typen keine Datumsarithmetik zulassen, ist sie ansonsten identisch.EDIT: Ich habe das hinzugefügt
+1
, was irgendwie weggelassen wurde. Es ist auch erwähnenswert, dass diese Methode immer die Start- und Endtage zählt. Es wird auch davon ausgegangen, dass das Enddatum am oder nach dem Startdatum liegt.quelle
Verwenden einer Datumstabelle:
Wenn Sie das nicht haben, können Sie eine Zahlentabelle verwenden:
Sie sollten beide schnell sein und die Mehrdeutigkeit / Komplexität beseitigen. Die erste Option ist die beste, aber wenn Sie keine Kalendertabelle haben, können Sie immer eine Zahlentabelle mit einem CTE erstellen.
quelle
quelle
quelle
Ich habe die verschiedenen Beispiele hier genommen, aber in meiner speziellen Situation haben wir ein @PromisedDate für die Lieferung und ein @ReceivedDate für den tatsächlichen Empfang des Artikels. Wenn ein Artikel vor dem "PromisedDate" eingegangen ist, wurden die Berechnungen nicht korrekt summiert, es sei denn, ich habe die in die Funktion übergebenen Daten in Kalenderreihenfolge bestellt. Ich wollte die Daten nicht jedes Mal überprüfen und habe die Funktion geändert, um dies für mich zu erledigen.
quelle
Wenn Sie einem bestimmten Datum Arbeitstage hinzufügen müssen, können Sie eine Funktion erstellen, die von einer unten beschriebenen Kalendertabelle abhängt:
quelle
Wie bei DATEDIFF betrachte ich das Enddatum nicht als Teil des Intervalls. Die Anzahl der (zum Beispiel) Sonntage zwischen @StartDate und @EndDate ist die Anzahl der Sonntage zwischen einem "anfänglichen" Montag und dem @EndDate abzüglich der Anzahl der Sonntage zwischen diesem "anfänglichen" Montag und dem @StartDate. Wenn wir das wissen, können wir die Anzahl der Arbeitstage wie folgt berechnen:
Freundliche Grüße!
quelle
Das funktioniert für mich, in meinem Land sind Samstag und Sonntag arbeitsfreie Tage.
Für mich ist die Zeit von @StartDate und @EndDate wichtig.
quelle
Erstellen Sie eine Funktion wie:
Sie können die Funktion wie folgt aufrufen:
Oder wie:
quelle
Ende
quelle
Ich fand die folgende TSQL eine ziemlich elegante Lösung (ich habe keine Berechtigung zum Ausführen von Funktionen). Ich fand die
DATEDIFF
IgnorantenDATEFIRST
und wollte, dass mein erster Tag der Woche ein Montag ist. Ich wollte auch, dass der erste Arbeitstag auf Null gesetzt wird und wenn er auf ein Wochenende fällt, wird Montag eine Null sein. Dies kann jemandem helfen, der eine etwas andere Anforderung hat :)Es werden keine Feiertage behandelt
quelle
Ein Ansatz besteht darin, die Daten von Anfang bis Ende in Verbindung mit einem Fallausdruck zu durchlaufen, der prüft, ob der Tag kein Samstag oder Sonntag ist, und ihn markiert (1 für Wochentag, 0 für Wochenende). Und am Ende summieren Sie einfach die Flags (dies entspricht der Anzahl der 1-Flags, da das andere Flag 0 ist), um die Anzahl der Wochentage anzugeben.
Sie können eine Dienstprogrammfunktion vom Typ GetNums (startNumber, endNumber) verwenden, die eine Reihe von Zahlen für die Schleife vom Startdatum bis zum Enddatum generiert. Eine Implementierung finden Sie unter http://tsql.solidq.com/SourceCodes/GetNums.txt . Die Logik kann auch erweitert werden, um Feiertage zu berücksichtigen (z. B. wenn Sie eine Feiertagstabelle haben).
quelle
Ich habe einige Ideen von anderen ausgeliehen, um meine Lösung zu erstellen. Ich verwende Inline-Code, um Wochenenden und US-Bundesfeiertage zu ignorieren. In meiner Umgebung ist EndDate möglicherweise null, steht jedoch niemals vor StartDate.
quelle