当您可以更有效地生成集合时,请尽量避免循环,并且请停止varchar
无长度声明。
这是一个结合了您的两个要求的函数(生成日期集并将它们格式化为您尴尬的输出格式):
CREATE FUNCTION dbo.fn_GetRunDatesShort_2
(
@StartDate DATE, @Weeks TINYINT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @output VARCHAR(MAX);
;WITH cte1(m,d) AS
(
SELECT DATENAME(MONTH, wd), CONVERT(VARCHAR(2), DAY(wd)) FROM
(
SELECT TOP (@Weeks) DATEADD(WEEK, ROW_NUMBER() OVER
(ORDER BY [object_id]), @StartDate)
FROM sys.all_objects ORDER BY [object_id]
) AS sq(wd)
),
cte2(ds) AS
(
SELECT DISTINCT m + STUFF((SELECT ', ' + d FROM cte1 AS cte1_a
WHERE cte1_a.m = cte1.m
FOR XML PATH(''), TYPE).value('.[1]','varchar(max)'),1,1,'')
FROM cte1
)
SELECT @output = STUFF((SELECT ' | ' + ds FROM cte2
FOR XML PATH(''),TYPE).value('.[1]','varchar(max)'),1,3,'');
RETURN (@output);
END
GO
(如果你有一个 Numbers 表——你应该这样做——你可以将查询替换为sys.all_objects
与 Numbers 表相似的查询,然后你可以添加WITH SCHEMABINDING
到函数中——这在这种情况下可能没有帮助,但这是我尝试的尽可能始终如一地做。)
用法:
SELECT dbo.fn_GetRunDatesShort_2(GETDATE(), 4);
结果:
August 21, 28 | September 4, 11
如果你的方法是 52,那么问题就来了——如果你的日期是今年 8 月,而日期是明年 8@weeks
月,你期望什么输出?
编辑 2014-05-19
为确保以正确的方向排序(去年 8 月运行良好,但现在似乎在 5 月更改了顺序),您可以对函数进行以下更改:
CREATE FUNCTION dbo.fn_GetRunDatesShort_2
(
@StartDate DATE, @Weeks TINYINT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE @output VARCHAR(MAX);
;WITH cte1(mn,m,d) AS
(
SELECT
DATEPART(YEAR, wd) * 100 + DATEPART(MONTH, wd),
DATENAME(MONTH, wd), CONVERT(VARCHAR(2), DATEPART(DAY,wd))
FROM
(
SELECT TOP (@Weeks) DATEADD(WEEK, ROW_NUMBER() OVER
(ORDER BY [object_id]), @StartDate)
FROM sys.all_objects ORDER BY [object_id]
) AS sq(wd)
),
cte2(mn,ds) AS
(
SELECT DISTINCT mn, m + STUFF((SELECT ', ' + d FROM cte1 AS cte1_a
WHERE cte1_a.m = cte1.m ORDER BY mn
FOR XML PATH(''), TYPE).value('.[1]','varchar(max)'),1,1,'')
FROM cte1
)
SELECT @output = STUFF((SELECT ' | ' + ds FROM cte2 ORDER BY mn
FOR XML PATH(''),TYPE).value('.[1]','varchar(max)'),1,3,'');
RETURN (@output);
END
GO