मैं SQL सर्वर में दो तिथियों के बीच कार्य दिवसों की संख्या की गणना कैसे कर सकता हूं?
सोमवार से शुक्रवार और यह टी-एसक्यूएल होना चाहिए।
मैं SQL सर्वर में दो तिथियों के बीच कार्य दिवसों की संख्या की गणना कैसे कर सकता हूं?
सोमवार से शुक्रवार और यह टी-एसक्यूएल होना चाहिए।
जवाबों:
कार्यदिवस के लिए, सोमवार से शुक्रवार, आप इसे एक ही चयन के साथ कर सकते हैं, जैसे:
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2008/10/01'
SET @EndDate = '2008/10/31'
SELECT
(DATEDIFF(dd, @StartDate, @EndDate) + 1)
-(DATEDIFF(wk, @StartDate, @EndDate) * 2)
-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END)
यदि आप छुट्टियों को शामिल करना चाहते हैं, तो आपको इसे थोड़ा काम करना होगा ...
-(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)
में गिना जा रहा है कार्य दिन आप इस विषय के बारे में एक अच्छा लेख पा सकते हैं, लेकिन जैसा कि आप देख सकते हैं यह है कि उन्नत नहीं है।
--Changing current database to the Master database allows function to be shared by everyone.
USE MASTER
GO
--If the function already exists, drop it.
IF EXISTS
(
SELECT *
FROM dbo.SYSOBJECTS
WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')
AND XType IN (N'FN', N'IF', N'TF')
)
DROP FUNCTION [dbo].[fn_WorkDays]
GO
CREATE FUNCTION 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 INT
AS
--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 IS NULL
RETURN NULL
--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).
IF @EndDate IS NULL
SELECT @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 > @EndDate
SELECT @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
-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday'
THEN 1
ELSE 0
END)
--If EndDate is a Saturday, Subtract 1
-(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday'
THEN 1
ELSE 0
END)
)
END
GO
यदि आपको एक कस्टम कैलेंडर का उपयोग करने की आवश्यकता है, तो आपको कुछ चेक और कुछ मापदंडों को जोड़ने की आवश्यकता हो सकती है। उम्मीद है कि यह एक अच्छी शुरुआत प्रदान करेगा।
बोगदान मैक्सिम और पीटर मोर्टेंसन को सभी क्रेडिट। यह उनका पद है, मैंने सिर्फ छुट्टियों को फ़ंक्शन में जोड़ा है (यह मानता है कि आपके पास एक टेबल "tblHolidays" है जिसमें एक डेटाइम फ़ील्ड "HolDate" है।
--Changing current database to the Master database allows function to be shared by everyone.
USE MASTER
GO
--If the function already exists, drop it.
IF EXISTS
(
SELECT *
FROM dbo.SYSOBJECTS
WHERE ID = OBJECT_ID(N'[dbo].[fn_WorkDays]')
AND XType IN (N'FN', N'IF', N'TF')
)
DROP FUNCTION [dbo].[fn_WorkDays]
GO
CREATE FUNCTION 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 INT
AS
--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 IS NULL
RETURN NULL
--If the End Date is null, populate with Start Date value so will have two dates (required by DATEDIFF below).
IF @EndDate IS NULL
SELECT @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 > @EndDate
SELECT @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
-(CASE WHEN DATENAME(dw, @StartDate) = 'Sunday'
THEN 1
ELSE 0
END)
--If EndDate is a Saturday, Subtract 1
-(CASE WHEN DATENAME(dw, @EndDate) = 'Saturday'
THEN 1
ELSE 0
END)
--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)
*/
WHERE HolDate BETWEEN @StartDate AND @EndDate AND DATEPART(dw, HolDate) BETWEEN 2 AND 6केवल सोमवार से शुक्रवार तक छुट्टियों की गणना करें।
कार्य दिवसों की गणना करने के लिए एक और तरीका है एक WHILE लूप का उपयोग करना जो मूल रूप से एक तिथि सीमा के माध्यम से पुनरावृत्त करता है और इसे 1 से बढ़ाता है जब भी दिन सोमवार - शुक्रवार के भीतर पाए जाते हैं। WHILE लूप का उपयोग करके कार्य दिवसों की गणना के लिए पूरी स्क्रिप्ट नीचे दी गई है:
CREATE FUNCTION [dbo].[fn_GetTotalWorkingDaysUsingLoop]
(@DateFrom DATE,
@DateTo DATE
)
RETURNS INT
AS
BEGIN
DECLARE @TotWorkingDays INT= 0;
WHILE @DateFrom <= @DateTo
BEGIN
IF DATENAME(WEEKDAY, @DateFrom) IN('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday')
BEGIN
SET @TotWorkingDays = @TotWorkingDays + 1;
END;
SET @DateFrom = DATEADD(DAY, 1, @DateFrom);
END;
RETURN @TotWorkingDays;
END;
GO
हालाँकि WHILE लूप विकल्प क्लीनर है और कोड की कम लाइनों का उपयोग करता है, लेकिन यह आपके वातावरण में एक प्रदर्शन अड़चन होने की संभावना है, खासकर जब आपकी तारीख कई वर्षों तक फैली हो।
आप इस लेख में काम के दिनों और घंटों की गणना करने के बारे में अधिक तरीके देख सकते हैं: https://www.sqlshack.com/how-to-calculate-work-days-and-hours-in-sql-server/
एक फ़ंक्शन के उपयोग के रूप में स्वीकृत उत्तर का मेरा संस्करण DATEPART, इसलिए मुझे लाइन पर एक स्ट्रिंग तुलना करने की आवश्यकता नहीं है
DATENAME(dw, @StartDate) = 'Sunday'
वैसे भी, यहाँ मेरा व्यवसाय दिनांकित कार्य है
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION BDATEDIFF
(
@startdate as DATETIME,
@enddate as DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @res int
SET @res = (DATEDIFF(dd, @startdate, @enddate) + 1)
-(DATEDIFF(wk, @startdate, @enddate) * 2)
-(CASE WHEN DATEPART(dw, @startdate) = 1 THEN 1 ELSE 0 END)
-(CASE WHEN DATEPART(dw, @enddate) = 7 THEN 1 ELSE 0 END)
RETURN @res
END
GO
DECLARE @TotalDays INT,@WorkDays INT
DECLARE @ReducedDayswithEndDate INT
DECLARE @WeekPart INT
DECLARE @DatePart INT
SET @TotalDays= DATEDIFF(day, @StartDate, @EndDate) +1
SELECT @ReducedDayswithEndDate = CASE DATENAME(weekday, @EndDate)
WHEN 'Saturday' THEN 1
WHEN 'Sunday' THEN 2
ELSE 0 END
SET @TotalDays=@TotalDays-@ReducedDayswithEndDate
SET @WeekPart=@TotalDays/7;
SET @DatePart=@TotalDays%7;
SET @WorkDays=(@WeekPart*5)+@DatePart
RETURN @WorkDays
(मैं विशेषाधिकारों पर टिप्पणी करने से कतराता हूं)
यदि आप CMS के सुरुचिपूर्ण समाधान में +1 दिन को त्यागने का निर्णय लेते हैं , तो ध्यान दें कि यदि आपकी आरंभ तिथि और अंतिम तिथि एक ही सप्ताहांत में है, तो आपको नकारात्मक उत्तर मिलता है। यानी, 2008/10/26 से 2008/10/26 रिटर्न -1।
मेरा बल्कि सरलीकृत समाधान:
select @Result = (..CMS's answer..)
if (@Result < 0)
select @Result = 0
RETURN @Result
.. जो कि अंतिम तिथि के बाद शुरू होने की तारीख के साथ सभी गलत पदों को भी शून्य पर सेट करता है। कुछ आप के लिए देख रहे हैं या नहीं हो सकता है।
छुट्टियों सहित तारीखों के अंतर के लिए मैं इस तरह गया:
1) छुट्टियों की तालिका:
CREATE TABLE [dbo].[Holiday](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[Date] [datetime] NOT NULL)
2) मेरे पास इस तरह मेरी योजना तालिका थी और कॉलम भरना चाहते थे Work_Days जो खाली था:
CREATE TABLE [dbo].[Plan_Phase](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Id_Plan] [int] NOT NULL,
[Id_Phase] [int] NOT NULL,
[Start_Date] [datetime] NULL,
[End_Date] [datetime] NULL,
[Work_Days] [int] NULL)
3) तो "Work_Days" प्राप्त करने के लिए बाद में मेरे कॉलम को बस भरना होगा:
SELECT Start_Date, End_Date,
(DATEDIFF(dd, Start_Date, End_Date) + 1)
-(DATEDIFF(wk, Start_Date, End_Date) * 2)
-(SELECT COUNT(*) From Holiday Where Date >= Start_Date AND Date <= End_Date)
-(CASE WHEN DATENAME(dw, Start_Date) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, End_Date) = 'Saturday' THEN 1 ELSE 0 END)
-(CASE WHEN (SELECT COUNT(*) From Holiday Where Start_Date = Date) > 0 THEN 1 ELSE 0 END)
-(CASE WHEN (SELECT COUNT(*) From Holiday Where End_Date = Date) > 0 THEN 1 ELSE 0 END) AS Work_Days
from Plan_Phase
उम्मीद है कि मैं मदद कर सकता हूं।
चियर्स
यहां एक संस्करण है जो अच्छी तरह से काम करता है (मुझे लगता है)। हॉलिडे टेबल में Holiday_date कॉलम होते हैं जिसमें आपकी कंपनी की छुट्टियां होती हैं।
DECLARE @RAWDAYS INT
SELECT @RAWDAYS = DATEDIFF(day, @StartDate, @EndDate )--+1
-( 2 * DATEDIFF( week, @StartDate, @EndDate ) )
+ CASE WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN 1 ELSE 0 END
- CASE WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN 1 ELSE 0 END
SELECT @RAWDAYS - COUNT(*)
FROM HOLIDAY NumberOfBusinessDays
WHERE [Holiday_Date] BETWEEN @StartDate+1 AND @EndDate
मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन मेरे पास कार्यदिवस के लिए एक सूत्र की आवश्यकता है जो कि प्रारंभ की तारीख को छोड़कर मेरे पास कई आइटम हैं और दिनों को सही तरीके से संचित करने की आवश्यकता है।
किसी भी गैर-पुनरावृत्त उत्तर ने मेरे लिए काम नहीं किया।
मैंने जैसे डिफ्रेंटेशन का इस्तेमाल किया
सोमवार, मंगलवार, बुधवार, बुधवार और शुक्रवार को मध्यरात्रि की संख्या बीत जाती है
(अन्य सोमवार की बजाय शनिवार की आधी रात को गिन सकते हैं)
मैं इस सूत्र के साथ समाप्त हुआ
SELECT DATEDIFF(day, @StartDate, @EndDate) /* all midnights passed */
- DATEDIFF(week, @StartDate, @EndDate) /* remove sunday midnights */
- DATEDIFF(week, DATEADD(day, 1, @StartDate), DATEADD(day, 1, @EndDate)) /* remove saturday midnights */
@StartDateशनिवार या शुक्रवार का हिसाब नहीं है। यहाँ मेरा संस्करण है: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
यह मूल रूप से एक विशेष भाषा सेटिंग पर निर्भरता के बिना सीएमएस का जवाब है। और जब से हम जेनेरिक के लिए शूटिंग कर रहे हैं, इसका मतलब है कि इसे सभी @@datefirstसेटिंग्स के लिए भी काम करना चाहिए ।
datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
/* if start is a Sunday, adjust by -1 */
+ case when datepart(weekday, <start>) = 8 - @@datefirst then -1 else 0 end
/* if end is a Saturday, adjust by -1 */
+ case when datepart(weekday, <end>) = (13 - @@datefirst) % 7 + 1 then -1 else 0 end
datediff(week, ...)हमेशा सप्ताह के लिए शनिवार-से-रविवार की सीमा का उपयोग करता है, ताकि अभिव्यक्ति नियतात्मक हो और इसे संशोधित करने की आवश्यकता न हो (जब तक कि कार्यदिवस की हमारी परिभाषा शुक्रवार के माध्यम से लगातार सोमवार हो।) दिन की संख्या @@datefirstसेटिंग के अनुसार भिन्न होती है । संशोधित गणना कुछ मॉड्यूलर अंकगणित की छोटी जटिलता के साथ इस सुधार को संभालती है।
शनिवार / रविवार की बात से निपटने के लिए एक क्लीनर तरीका सप्ताह के मूल्य का एक दिन निकालने से पहले की तारीखों का अनुवाद करना है। शिफ्टिंग के बाद, मान एक निश्चित (और शायद अधिक परिचित) क्रमांक के अनुसार वापस आ जाएंगे जो रविवार को 1 से शुरू होता है और शनिवार को 7 के साथ समाप्त होता है।
datediff(day, <start>, <end>) + 1 - datediff(week, <start>, <end>) * 2
+ case when datepart(weekday, dateadd(day, @@datefirst, <start>)) = 1 then -1 else 0 end
+ case when datepart(weekday, dateadd(day, @@datefirst, <end>)) = 7 then -1 else 0 end
मैंने समाधान के इस रूप को कम से कम 2002 और इत्ज़िक बेन-गण लेख के रूप में ट्रैक किया है। ( https://technet.microsoft.com/en-us/library/aa175781(v=sql.80).aspx ) हालांकि इसे नए dateप्रकार की छोटी सी तारीख की आवश्यकता है क्योंकि नए प्रकार तारीख अंकगणित की अनुमति नहीं देते हैं, यह अन्यथा समान है।
संपादित करें: मैंने वापस जोड़ा है +1कि किसी भी तरह छोड़ दिया गया था। यह भी ध्यान देने योग्य है कि यह विधि हमेशा शुरुआत और अंत के दिनों को गिनती है। यह यह भी मानता है कि अंतिम तिथि प्रारंभ तिथि के बाद या उसके बाद है।
दिनांक तालिका का उपयोग करना:
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;
यदि आपके पास ऐसा नहीं है, तो आप एक संख्या तालिका का उपयोग कर सकते हैं:
DECLARE
@StartDate datetime = '2014-01-01',
@EndDate datetime = '2014-01-31';
SELECT
SUM(CASE WHEN DATEPART(dw, DATEADD(dd, Number-1, @StartDate)) BETWEEN 2 AND 6 THEN 1 ELSE 0 END) As NumberOfWeekDays
FROM dbo.Numbers
WHERE Number <= DATEDIFF(dd, @StartDate, @EndDate) + 1 -- Number table starts at 1, we want a 0 base
वे दोनों तेज होना चाहिए और यह अस्पष्टता / जटिलता को बाहर निकालता है। पहला विकल्प सबसे अच्छा है लेकिन अगर आपके पास कैलेंडर टेबल नहीं है तो आप CTE के साथ नंबर टेबल बना सकते हैं।
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) +1
SELECT @ReducedDayswithEndDate = CASE DATENAME(weekday, @EndDate)
WHEN 'Saturday' THEN 1
WHEN 'Sunday' THEN 2
ELSE 0 END
SET @TotalDays=@TotalDays-@ReducedDayswithEndDate
SET @WeekPart=@TotalDays/7;
SET @DatePart=@TotalDays%7;
SET @WorkDays=(@WeekPart*5)+@DatePart
SELECT @WorkDays
CREATE FUNCTION x
(
@StartDate DATETIME,
@EndDate DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @Teller INT
SET @StartDate = DATEADD(dd,1,@StartDate)
SET @Teller = 0
IF DATEDIFF(dd,@StartDate,@EndDate) <= 0
BEGIN
SET @Teller = 0
END
ELSE
BEGIN
WHILE
DATEDIFF(dd,@StartDate,@EndDate) >= 0
BEGIN
IF DATEPART(dw,@StartDate) < 6
BEGIN
SET @Teller = @Teller + 1
END
SET @StartDate = DATEADD(dd,1,@StartDate)
END
END
RETURN @Teller
END
मैंने विभिन्न उदाहरण यहां दिए हैं, लेकिन मेरी विशेष स्थिति में हमारे पास डिलीवरी के लिए एक @PromisedDate और आइटम की वास्तविक प्राप्ति के लिए एक @ReceivedDate है। जब "वादा" से पहले एक आइटम प्राप्त किया गया था, तो गणना सही ढंग से टोटल नहीं हो रही थी, जब तक कि मैं कैलेंडर आदेश के अनुसार फ़ंक्शन में पारित तारीखों का आदेश नहीं देता। हर बार तारीखों की जांच नहीं करने के कारण, मैंने इसे संभालने के लिए फ़ंक्शन को बदल दिया।
Create FUNCTION [dbo].[fnGetBusinessDays]
(
@PromiseDate date,
@ReceivedDate date
)
RETURNS integer
AS
BEGIN
DECLARE @days integer
SELECT @days =
Case when @PromiseDate > @ReceivedDate Then
DATEDIFF(d,@PromiseDate,@ReceivedDate) +
ABS(DATEDIFF(wk,@PromiseDate,@ReceivedDate)) * 2 +
CASE
WHEN DATENAME(dw, @PromiseDate) <> 'Saturday' AND DATENAME(dw, @ReceivedDate) = 'Saturday' THEN 1
WHEN DATENAME(dw, @PromiseDate) = 'Saturday' AND DATENAME(dw, @ReceivedDate) <> 'Saturday' THEN -1
ELSE 0
END +
(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 -
CASE
WHEN DATENAME(dw, @PromiseDate) <> 'Saturday' AND DATENAME(dw, @ReceivedDate) = 'Saturday' THEN 1
WHEN DATENAME(dw, @PromiseDate) = 'Saturday' AND DATENAME(dw, @ReceivedDate) <> 'Saturday' THEN -1
ELSE 0
END -
(Select COUNT(*) FROM CompanyHolidays
WHERE HolidayDate BETWEEN @PromiseDate and @ReceivedDate
AND DATENAME(dw, HolidayDate) <> 'Saturday' AND DATENAME(dw, HolidayDate) <> 'Sunday')
End
RETURN (@days)
END
यदि आपको दी गई तारीख में कार्य दिवस जोड़ने की आवश्यकता है, तो आप एक फ़ंक्शन बना सकते हैं जो कैलेंडर तालिका पर निर्भर करता है, नीचे वर्णित है:
CREATE TABLE Calendar
(
dt SMALLDATETIME PRIMARY KEY,
IsWorkDay BIT
);
--fill the rows with normal days, weekends and holidays.
create function AddWorkingDays (@initialDate smalldatetime, @numberOfDays int)
returns smalldatetime as
begin
declare @result smalldatetime
set @result =
(
select t.dt from
(
select dt, ROW_NUMBER() over (order by dt) as daysAhead from calendar
where dt > @initialDate
and IsWorkDay = 1
) t
where t.daysAhead = @numberOfDays
)
return @result
end
DatedIFF के साथ, मैं अंत की तारीख को अंतराल का हिस्सा नहीं मानता। (उदाहरण के लिए) रविवार की संख्या @StartDate और @EndDate के बीच के रविवारों की संख्या "प्रारंभिक" सोमवार और @EndDate के बीच के रविवारों की संख्या है, जो इस "प्रारंभिक" सोमवार और @StartDate के बीच है। यह जानते हुए, हम कार्यदिवसों की संख्या की गणना इस प्रकार कर सकते हैं:
DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME
SET @StartDate = '2018/01/01'
SET @EndDate = '2019/01/01'
SELECT DATEDIFF(Day, @StartDate, @EndDate) -- Total Days
- (DATEDIFF(Day, 0, @EndDate)/7 - DATEDIFF(Day, 0, @StartDate)/7) -- Sundays
- (DATEDIFF(Day, -1, @EndDate)/7 - DATEDIFF(Day, -1, @StartDate)/7) -- Saturdays
सादर!
वह मेरे लिए काम कर रहा है, मेरे देश में शनिवार और रविवार गैर-कार्य दिवस हैं।
मेरे लिए @StartDate और @EndDate का समय महत्वपूर्ण है।
CREATE FUNCTION [dbo].[fnGetCountWorkingBusinessDays]
(
@StartDate as DATETIME,
@EndDate as DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @res int
SET @StartDate = CASE
WHEN DATENAME(dw, @StartDate) = 'Saturday' THEN DATEADD(dd, 2, DATEDIFF(dd, 0, @StartDate))
WHEN DATENAME(dw, @StartDate) = 'Sunday' THEN DATEADD(dd, 1, DATEDIFF(dd, 0, @StartDate))
ELSE @StartDate END
SET @EndDate = CASE
WHEN DATENAME(dw, @EndDate) = 'Saturday' THEN DATEADD(dd, 0, DATEDIFF(dd, 0, @EndDate))
WHEN DATENAME(dw, @EndDate) = 'Sunday' THEN DATEADD(dd, -1, DATEDIFF(dd, 0, @EndDate))
ELSE @EndDate END
SET @res =
(DATEDIFF(hour, @StartDate, @EndDate) / 24)
- (DATEDIFF(wk, @StartDate, @EndDate) * 2)
SET @res = CASE WHEN @res < 0 THEN 0 ELSE @res END
RETURN @res
END
GO
फ़ंक्शन बनाएं जैसे:
CREATE FUNCTION dbo.fn_WorkDays(@StartDate DATETIME, @EndDate DATETIME= NULL )
RETURNS INT
AS
BEGIN
DECLARE @Days int
SET @Days = 0
IF @EndDate = NULL
SET @EndDate = EOMONTH(@StartDate) --last date of the month
WHILE DATEDIFF(dd,@StartDate,@EndDate) >= 0
BEGIN
IF DATENAME(dw, @StartDate) <> 'Saturday'
and DATENAME(dw, @StartDate) <> 'Sunday'
and Not ((Day(@StartDate) = 1 And Month(@StartDate) = 1)) --New Year's Day.
and Not ((Day(@StartDate) = 4 And Month(@StartDate) = 7)) --Independence Day.
BEGIN
SET @Days = @Days + 1
END
SET @StartDate = DATEADD(dd,1,@StartDate)
END
RETURN @Days
END
आप फ़ंक्शन को कॉल कर सकते हैं जैसे:
select dbo.fn_WorkDays('1/1/2016', '9/25/2016')
या पसंद करें:
select dbo.fn_WorkDays(StartDate, EndDate)
from table1
Create Function dbo.DateDiff_WeekDays
(
@StartDate DateTime,
@EndDate DateTime
)
Returns Int
As
Begin
Declare @Result Int = 0
While @StartDate <= @EndDate
Begin
If DateName(DW, @StartDate) not in ('Saturday','Sunday')
Begin
Set @Result = @Result +1
End
Set @StartDate = DateAdd(Day, +1, @StartDate)
End
Return @Result
समाप्त
मैं नीचे TSQL एक काफी सुंदर समाधान पाया (मैं कार्यों को चलाने के लिए अनुमति नहीं है)। मुझे DATEDIFFनज़रअंदाज़ कर दिया गया DATEFIRSTऔर मैं चाहता था कि सप्ताह का पहला दिन सोमवार हो। मैं यह भी चाहता था कि पहला कार्य दिवस एक शून्य निर्धारित किया जाए और यदि यह सोमवार को गिरता है तो यह शून्य होगा। यह किसी ऐसे व्यक्ति की मदद कर सकता है जिसकी थोड़ी अलग आवश्यकता है :)
यह बैंक की छुट्टियों को नहीं संभालता है
SET DATEFIRST 1
SELECT
,(DATEDIFF(DD, [StartDate], [EndDate]))
-(DATEDIFF(wk, [StartDate], [EndDate]))
-(DATEDIFF(wk, DATEADD(dd,-@@DATEFIRST,[StartDate]), DATEADD(dd,-@@DATEFIRST,[EndDate]))) AS [WorkingDays]
FROM /*Your Table*/
एक दृष्टिकोण एक मामले की अभिव्यक्ति के साथ शुरू से अंत तक तारीखों को 'चलना' है जो यह जांचता है कि क्या दिन शनिवार या रविवार नहीं है और इसे हरी झंडी दिखा रहा है (सप्ताहांत के लिए 1, सप्ताहांत के लिए 0)। और अंत में बस झंडे (यह 1-झंडे की गिनती के बराबर होगा क्योंकि अन्य ध्वज 0 है) आपको सप्ताह के दिनों की संख्या देगा।
आप GetNums (startNumber, endNumber) प्रकार के उपयोगिता फ़ंक्शन का उपयोग कर सकते हैं जो प्रारंभ तिथि से लेकर समाप्ति तिथि तक 'लूपिंग' के लिए संख्याओं की एक श्रृंखला उत्पन्न करता है। एक कार्यान्वयन के लिए http://tsql.solidq.com/SourceCodes/GetNums.txt देखें । तर्क को छुट्टियों के लिए पूरा करने के लिए भी बढ़ाया जा सकता है (यदि आपके पास एक अवकाश तालिका है)
declare @date1 as datetime = '19900101'
declare @date2 as datetime = '19900120'
select sum(case when DATENAME(DW,currentDate) not in ('Saturday', 'Sunday') then 1 else 0 end) as noOfWorkDays
from dbo.GetNums(0,DATEDIFF(day,@date1, @date2)-1) as Num
cross apply (select DATEADD(day,n,@date1)) as Dates(currentDate)
मैंने अपना समाधान बनाने के लिए दूसरों से कुछ विचार उधार लिए। मैं सप्ताहांत और अमेरिकी संघीय छुट्टियों को अनदेखा करने के लिए इनलाइन कोड का उपयोग करता हूं। मेरे वातावरण में, EndDate अशक्त हो सकता है, लेकिन यह StartDate से पहले कभी नहीं होगा।
CREATE FUNCTION dbo.ufn_CalculateBusinessDays(
@StartDate DATE,
@EndDate DATE = NULL)
RETURNS INT
AS
BEGIN
DECLARE @TotalBusinessDays INT = 0;
DECLARE @TestDate DATE = @StartDate;
IF @EndDate IS NULL
RETURN NULL;
WHILE @TestDate < @EndDate
BEGIN
DECLARE @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 holiday
SELECT @TotalBusinessDays += (
SELECT CASE
--Saturday OR Sunday
WHEN @DayOfWeek IN (6,7) THEN 0
--New Year's Day
WHEN @Month = 1 AND @Day = 1 THEN 0
--MLK Jr. Day
WHEN @Month = 1 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
--G. Washington's Birthday
WHEN @Month = 2 AND @DayOfWeek = 1 AND @DayOccurrence = 3 THEN 0
--Memorial Day
WHEN @Month = 5 AND @DayOfWeek = 1 AND @Day BETWEEN 25 AND 31 THEN 0
--Independence Day
WHEN @Month = 7 AND @Day = 4 THEN 0
--Labor Day
WHEN @Month = 9 AND @DayOfWeek = 1 AND @DayOccurrence = 1 THEN 0
--Columbus Day
WHEN @Month = 10 AND @DayOfWeek = 1 AND @DayOccurrence = 2 THEN 0
--Veterans Day
WHEN @Month = 11 AND @Day = 11 THEN 0
--Thanksgiving
WHEN @Month = 11 AND @DayOfWeek = 4 AND @DayOccurrence = 4 THEN 0
--Christmas
WHEN @Month = 12 AND @Day = 25 THEN 0
ELSE 1
END AS Result);
SET @TestDate = DATEADD(dd, 1, @TestDate);
END
RETURN @TotalBusinessDays;
END