Sql 常规?从2014年1月4日开始,我想知道每两个月的第二周星期六的日期。因此,如果1月1日至4日居住在1月1日的第一周,则为1月11日“。1月11日之后,我们将迎来3月8日,因为我认为3月1日也是第一周的第一个星期六。@pm-77-1对此表示抱歉,但请检查解
Sql 常规?从2014年1月4日开始,我想知道每两个月的第二周星期六的日期。因此,如果1月1日至4日居住在1月1日的第一周,则为1月11日“。1月11日之后,我们将迎来3月8日,因为我认为3月1日也是第一周的第一个星期六。@pm-77-1对此表示抱歉,但请检查解,sql,sql-server,sql-server-2008,tsql,datetime,Sql,Sql Server,Sql Server 2008,Tsql,Datetime,常规?从2014年1月4日开始,我想知道每两个月的第二周星期六的日期。因此,如果1月1日至4日居住在1月1日的第一周,则为1月11日“。1月11日之后,我们将迎来3月8日,因为我认为3月1日也是第一周的第一个星期六。@pm-77-1对此表示抱歉,但请检查解释中的粗体行和评论中最近的示例。您询问的是SQL/T-SQL解决方案,因此请将预期结果以表格形式添加到您的帖子中。”。 CREATE TABLE Calendar ( [Date] date NOT NULL, [NthWeek
常规?从2014年1月4日开始,我想知道每两个月的第二周星期六的日期。因此,如果1月1日至4日居住在1月1日的第一周,则为1月11日“。1月11日之后,我们将迎来3月8日,因为我认为3月1日也是第一周的第一个星期六。@pm-77-1对此表示抱歉,但请检查解释中的粗体行和评论中最近的示例。您询问的是SQL/T-SQL解决方案,因此请将预期结果以表格形式添加到您的帖子中。”。
CREATE TABLE Calendar
(
[Date] date NOT NULL,
[NthWeekdayInMonth] int,
CONSTRAINT PK_Calendar
PRIMARY KEY CLUSTERED ([Date])
WITH FILLFACTOR = 100
)
;WITH cte AS
(
SELECT
DATEADD(d, (a.Number * 256) + b.Number, '01/01/2000') AS [Date]
FROM
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) a (Number),
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) b (Number)
)
INSERT INTO Calendar
SELECT
[Date],
ROW_NUMBER() OVER (PARTITION BY YEAR([Date]), MONTH([Date]), DATEPART(dw, [Date]) ORDER BY [Date]) FROM cte
ORDER BY
[Date]
GO
2014-01-11
2014-03-08
2014-05-10
2014-07-12
DECLARE @startDate date
DECLARE @everyNMonths int
DECLARE @numResults int
DECLARE @nthAppearanceOfDay int
SET @startDate = '01/11/2014' -- First occurence is on this date
SET @everyNMonths = 2 -- Skip every n months
SET @numResults = 4 -- Max # of results to return
-- Figure out which x-day of the month this is. For example, if the starting
-- date is 1/11/2014 that was the second Saturday so this will be set to 2.
SELECT @nthAppearanceOfDay = NthWeekdayInMonth FROM calendar WHERE [date] = @startDate
-- Use a CTE to get all the months involved in this calculation
;WITH candidateMonths AS (
SELECT
1 AS [resultnum], @startDate AS [date]
UNION ALL
SELECT resultnum + 1, DATEADD(month, @everyNMonths, [date]) FROM candidateMonths
WHERE resultnum + 1 <= @numResults
)
-- Now evaluate every date for each of the candidate months. If the day of week matches
-- that of the start date AND it is the Nth occurrence of that day of week in the month
-- include it
SELECT
c.[Date]
FROM
candidateMonths cm
INNER JOIN calendar c ON ( (YEAR(c.[Date]) = YEAR(cm.[Date])) AND (MONTH(c.[Date]) = MONTH(cm.[Date])))
WHERE
(DATEPART(dw, c.[date]) = DATEPART(dw, @startDate)) -- Same day of week
AND
(c.NthWeekdayInMonth = @nthAppearanceOfDay) -- Same week of month
SELECT * FROM dbo.NthWeekday(GETDATE(), 1, 1);
SELECT * FROM dbo.NthWeekday(GETDATE(), 1, -1);
DECLARE @date DATE = GETDATE();
DECLARE @numMonths INT = -5
DECLARE @weekday INT = 1;
DECLARE @n INT = 2;
SELECT C.D
FROM dbo.RangeSmallInt(0, @numMonths - SIGN(@numMonths)) A
CROSS APPLY ( -- MonthBegin
SELECT DT = DATEADD(m, DATEDIFF(m, 0, @date) + A.N, 0)
) B
CROSS APPLY dbo.NthWeekday(B.DT, @weekday, @n) C;
Results: 2014-12-14
2015-01-11
2015-02-08
2015-03-08
2015-04-12
CREATE FUNCTION dbo.NthWeekday (
@date DATE = NULL
, @weekday INT = NULL
, @n INT = 1
)
RETURNS TABLE
AS
RETURN (
SELECT D = CASE SIGN(@n)
WHEN -1 THEN DATEADD(d, -(DATEPART(dw, @date) + @@DATEFIRST - @weekday) % 7 + ((@n + 1) * 7), @date)
ELSE DATEADD(d, (@weekday - DATEPART(dw, @date) + @@DATEFIRST) % 7 + ((@n - SIGN(@n)) * 7), @date)
END
);
-- Generate a range of up to 65,536 contiguous BIGINTS
CREATE FUNCTION dbo.RangeSmallInt (
@num1 BIGINT = NULL
, @num2 BIGINT = NULL
)
RETURNS TABLE
AS
RETURN (
WITH Numbers(N) AS (
SELECT N FROM(VALUES
(1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 16
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 32
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 48
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 64
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 80
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 96
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 112
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 128
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 144
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 160
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 176
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 192
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 208
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 224
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 240
, (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 256
) V (N)
)
SELECT TOP (
CASE
WHEN @num1 IS NOT NULL AND @num2 IS NOT NULL THEN ABS(@num1 - @num2) + 1
ELSE 0
END
)
N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) + CASE WHEN @num1 <= @num2 THEN @num1 ELSE @num2 END - 1
FROM Numbers A
, Numbers B
WHERE ABS(@num1 - @num2) + 1 < 65537
);