SQL 服务器上的工作日在函数中使用 CTE
Working days on SQL Server using CTE in a function
我正在尝试编写一个函数来 return 两个日期之间的工作日数。我有一个包含所有银行假日的 table,其中有两个字段:BHID 和 BHDate。
我编写了以下 SELECT 查询来检验我的理论,它运行良好:
DECLARE @StartDate AS Date, @EndDate AS Date
SET @StartDate = '2015-01-01'
SET @EndDate = '2015-07-01'
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);
但是当我尝试将它放入一个函数中时,我在 SET 行周围遇到了一些错误,这可能是我在函数方面不如我的其他知识那么好,或者我想知道它是否在 SET 行之前没有使用 CTE 怎么办?这是我的尝试:
CREATE FUNCTION [dbo].[WorkingDays]
(@StartDate AS Date, @EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SET @Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);)
RETURN @Days
END
我什至尝试将 INT 的结果插入到临时 table 中,然后在 returning @Days 之前设置 @Days 之后删除它,但这会导致错误允许作为函数的一部分生成临时 tables。
任何帮助都会很棒,我确定这是一件小事,但目前只是在逃避我。
使用这个功能
CREATE FUNCTION [dbo].[WorkingDays]
(@Start_Date AS Date, @end_Date AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
WITH AllDays
AS ( SELECT @start_date AS [Date], 1 AS [level]
UNION ALL
SELECT DATEADD(DAY, 1, [Date]), [level] + 1
FROM AllDays
WHERE [Date] < @end_date )
SELECT @Days =COUNT(*) AS Days
FROM AllDays
LEFT JOIN psd.dbo.LUBankHolidays BH
ON AllDays.Date= BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, AllDays.Date) ,1) <> 'S'
RETURN @Days
END
因为 CTE 只能在查询中使用,而不是使用 SET
来设置变量,所以使用 SELECT
代替:
SELECT @Days =
(SELECT COUNT(*) AS Days
FROM CTE …
来自MSDN:
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE
statement that references some or all the CTE columns.
在 stuartd 的帮助下解决了这个问题:
CREATE FUNCTION [dbo].[WorkingDays]
(@StartDate AS Date, @EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT @Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S')
option (Maxrecursion 0);
RETURN @Days
END
谢谢大家
我正在尝试编写一个函数来 return 两个日期之间的工作日数。我有一个包含所有银行假日的 table,其中有两个字段:BHID 和 BHDate。
我编写了以下 SELECT 查询来检验我的理论,它运行良好:
DECLARE @StartDate AS Date, @EndDate AS Date
SET @StartDate = '2015-01-01'
SET @EndDate = '2015-07-01'
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);
但是当我尝试将它放入一个函数中时,我在 SET 行周围遇到了一些错误,这可能是我在函数方面不如我的其他知识那么好,或者我想知道它是否在 SET 行之前没有使用 CTE 怎么办?这是我的尝试:
CREATE FUNCTION [dbo].[WorkingDays]
(@StartDate AS Date, @EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SET @Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S'
option (Maxrecursion 0);)
RETURN @Days
END
我什至尝试将 INT 的结果插入到临时 table 中,然后在 returning @Days 之前设置 @Days 之后删除它,但这会导致错误允许作为函数的一部分生成临时 tables。
任何帮助都会很棒,我确定这是一件小事,但目前只是在逃避我。
使用这个功能
CREATE FUNCTION [dbo].[WorkingDays]
(@Start_Date AS Date, @end_Date AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
WITH AllDays
AS ( SELECT @start_date AS [Date], 1 AS [level]
UNION ALL
SELECT DATEADD(DAY, 1, [Date]), [level] + 1
FROM AllDays
WHERE [Date] < @end_date )
SELECT @Days =COUNT(*) AS Days
FROM AllDays
LEFT JOIN psd.dbo.LUBankHolidays BH
ON AllDays.Date= BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, AllDays.Date) ,1) <> 'S'
RETURN @Days
END
因为 CTE 只能在查询中使用,而不是使用 SET
来设置变量,所以使用 SELECT
代替:
SELECT @Days =
(SELECT COUNT(*) AS Days
FROM CTE …
来自MSDN:
A CTE must be followed by a single SELECT, INSERT, UPDATE, or DELETE statement that references some or all the CTE columns.
在 stuartd 的帮助下解决了这个问题:
CREATE FUNCTION [dbo].[WorkingDays]
(@StartDate AS Date, @EndDate AS Date
)
RETURNS INT
AS
BEGIN
DECLARE @Days AS INT
;WITH CTE AS (
SELECT @StartDate AS StartDate, @EndDate AS EndDate, @StartDate AS DateCalc
UNION ALL
SELECT @StartDate AS StartDate, @EndDate AS EndDate, DATEADD(dd, 1, DateCalc) AS DateCalc FROM CTE
WHERE DATEADD(dd, 1, DateCalc) <= EndDate)
SELECT @Days =
(SELECT COUNT(*) AS Days
FROM CTE
LEFT JOIN psd.dbo.LUBankHolidays BH
ON CTE.DateCalc = BH.BHDate
WHERE BHID IS NULL
AND LEFT(DATENAME(dw, DateCalc) ,1) <> 'S')
option (Maxrecursion 0);
RETURN @Days
END
谢谢大家