【问题标题】:USE DATENAME IN SQL SERVER IN STORE PRODECURE在存储过程中使用 SQL SERVER 中的 DATENAME
【发布时间】:2020-08-17 23:13:52
【问题描述】:

我有这个带有 3 个参数的存储过程 -1:开始日期 -2:结束日期 -3 : 日期名称 这个存储过程的功能是在不计算特定日期的情况下获取两个日期之间的差异

CREATE PROCEDURE TEST (@start_date DATE,@end_date DATE,@name_days VARCHAR(MAX))
AS
BEGIN
DECLARE @NUMBER_DAYS INT;
;with AllDates AS
(
    SELECT @start_date AS DateOf
    UNION ALL
    SELECT DateAdd(day,1,DateOf)
        FROM AllDates
    WHERE DateOf<@end_date
)
select SUM(CASE WHEN DATENAME(weekday,dateof) in (@name_days) THEN 0 ELSE 1 END) as SumOfDays
FROM AllDates;
END

我的问题是我需要知道我是否可以像示例一样在执行过程中添加两个天的名称(但这对我不起作用,请有任何建议!以及如何做)

EXEC TEST '2020-07-01','2020-07-13','Monday Tuesday'

【问题讨论】:

  • 您可以运行它,但它不会返回任何结果,因为日期名称与参数值不匹配。您将不得不更改比较方法。
  • in (@name_days) 不会像你期望的那样。

标签: sql sql-server tsql


【解决方案1】:

我建议使用日历表,但如果您使用的是 SQL 2016+,则可以使用 STRING_SPLIT 函数完成此操作:

CREATE PROCEDURE TEST (@start_date DATE,@end_date DATE,@name_days VARCHAR(MAX))
AS
BEGIN

DECLARE @NUMBER_DAYS INT;
;with AllDates AS
(
    SELECT @start_date AS DateOf
    UNION ALL
    SELECT DateAdd(day,1,DateOf)
        FROM AllDates
    WHERE DateOf<@end_date
)

select COUNT(*) SumOfDays
FROM AllDates
WHERE NOT EXISTS(SELECT 1 
                    FROM STRING_SPLIT(@name_days,' ') 
                    WHERE DATENAME(weekday,dateof) = value)

END

【讨论】:

  • (是的,但不确定日历表如何帮助匹配/分解像'Monday Tuesday' 这样的字符串。)
【解决方案2】:

一种方法是使用表类型参数。我还从您使用 rCTE 的迭代(和缓慢)方法切换到更快的 Tally Table。

然而,理想情况下,如果您想更频繁地执行此操作,最好使用日历表(使用您最喜欢的搜索引擎,您会找到 1000 个有关如何构建这些的示例)而不是而不是内联的 Tally。

无论如何,使用表格类型参数,您可以执行以下操作:

USE Sandbox;
GO

CREATE TYPE dbo.DayNames AS table(DayName varchar(15));
GO
CREATE PROC dbo.TEST @StartDate date, @EndDate Date, @DayNames dbo.DayNames READONLY AS
BEGIN

    WITH N AS(
        SELECT N
        FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
    Tally AS(
        SELECT TOP (SELECT DATEDIFF(DAY, @StartDate, @EndDate) +1)
               ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
        FROM N N1, N N2, N N3, N N4), --10,000 days
    Dates AS(
        SELECT DATEADD(DAY, T.I, @StartDate) AS Date,
               DATENAME(WEEKDAY, DATEADD(DAY, T.I, @StartDate)) AS DayName
        FROM Tally T)
    SELECT COUNT(*) AS NumOfDays
    FROM Dates D
         JOIN @DayNames DN ON D.DayName = DN.DayName;

END;

GO

DECLARE @DayNames dbo.DayNames;
INSERT INTO @DayNames
VALUES ('Monday'),('Tuesday');

EXEC dbo.TEST '20000101', '20200817', @DayNames;
GO

--Cleanup

DROP PROC dbo.TEST;
DROP TYPE dbo.DayNames;

如果你不想使用表类型参数,你可以传入一个分隔列表,然后使用字符串拆分器,例如STRING_SPLIT(在 SQL Server 2016+ 中)或用户构建的函数,例如作为DelimitedSplit8K_LEAD(谷歌搜索)。

【讨论】:

    猜你喜欢
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多