传递工作日名称以获得最近的日期 SQL
Passing in Week Day name to get nearest date in SQL
我正在处理一个处理频率值(即星期一、星期二等 - 想想作业)的查询。
所以在我的查询中,我目前的结果是
jobId:1, personId:100, frequencyVal: 'Mondays'
jobId:2, personId:101, frequencyVal: 'Saturdays'
我需要的是 frequencyVal 接下来的 4 个未来(或当前)日期。
所以如果今天是 1/3/2015
我需要我的结果集是
jobId:1, personId:100, frequencyVal: 'Mondays', futureDates: '1/5,1/12,1/19,1/26'
jobId:2, personId:102, frequencyVal: 'Saturdays', futureDates: '1/3,1/10,1/17,1/24'
我正在查看以下帖子:
How to find the Nearest (day of the week) for a given date
但这将其设置为特定日期。我正在查看这是一个 Web 应用程序,我想要当前日期的日期。因此,如果我尝试在下周二运行此查询 jobId:1 would remove the 1/5 and add the 2/2
.
的未来日期
有没有办法传入工作日值以获得下一个最近的日期?
没有内置函数可以执行此操作。但是你可以试试这个,你可以把它放在一个标量值函数中:
DECLARE @WeekDay VARCHAR(10) = 'Monday';
DECLARE @WeekDayInt INT;
SELECT @WeekDayInt = CASE @WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
SELECT CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + @WeekDayInt) % 7, GETDATE())) AS NearestDate
更新:
看来雷达是对的,这是解决方案:
DECLARE @WeekDay VARCHAR(10) = 'Monday';
DECLARE @WeekDayInt INT;
DECLARE @Date DATETIME = GETDATE();
SELECT @WeekDayInt = CASE @WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
DECLARE @Diff INT = DATEPART(WEEKDAY, @Date) - @WeekDayInt;
SELECT CONVERT(DATE, DATEADD(DAY, CASE WHEN @Diff >= 0 THEN 7 - @Diff ELSE ABS(@Diff) END, @Date)) AS NearestDate
试试这个 - 根据 答案以获得最近的日期。
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
WITH cte(n) AS
(
SELECT 0
UNION ALL
SELECT n+1 FROM cte WHERE n < 3
)
select #t.jobId, #t.personId, #t.frequencyVal, STUFF(a.d, 1, 1, '') AS FutureDates
from #t
cross apply (SELECT CASE #t.frequencyVal
WHEN 'SUNDAYS' THEN 1
WHEN 'MONDAYS' THEN 2
WHEN 'TUESDAYS' THEN 3
WHEN 'WEDNESDAYS' THEN 4
WHEN 'THURSDAYS' THEN 5
WHEN 'FRIDAYS' THEN 6
WHEN 'SATURDAYS' THEN 7
END)tranlationWeekdays(n)
cross apply (select ',' + CONVERT(varchar(10), CONVERT(date,dateadd(WEEK, cte.n,CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + tranlationWeekdays.n) % 7, GETDATE()))))) from cte FOR XML PATH('')) a(d);
drop table #t;
这是我认为比较简单的方法,我觉得很符合你的要求。
请注意,我已将您的 frequency_val
列更改为代表 SQL 服务器角度的星期几的整数,并添加了一个计算列以说明您如何轻松导出日期名称从那个。
declare @t table
(
jobId int,
personId int,
--frequencyVal varchar(10)
frequency_val int,
frequency_day as datename(weekday,frequency_val -1) + 's'
);</p>
<p>declare @num_occurances int = 4
declare @from_date date = dateadd(dd,3,getdate()) -- this will allow you to play with the date simply by changing the increment value</p>
<p>insert into @t
values
(1,100,1),--'Mondays'),
(2,101,6),--'Saturdays');
(3,101,7),--'Saturdays');
(4,100,2)--'Mondays'),
--select * from @t</p>
<p>;with r_cte (days_ahead, occurance_date)
as (select 0, convert(date,@from_date,121)
union all
select r_cte.days_ahead +1, convert(date,dateadd(DD, r_cte.days_ahead+1, @from_date),121)
from r_cte
where r_cte.days_ahead < 7 * @num_occurances
)
select t.*, r_cte.occurance_date
from
@t t
inner join r_cte
on DATEPART(WEEKDAY, dateadd(dd,@@DATEFIRST - 1 ,r_cte.occurance_date)) = t.frequency_val
</pre>
对于此类查询,我更喜欢日历 table。实际上,对于大多数查询,我更喜欢日历 table 而不是日期函数。这是一个最小的。我在生产中使用的那个有更多的列和更多的行。 (100 年的数据只有 37k 行。)
create table calendar (
cal_date date not null primary key,
day_of_week varchar(15)
);
insert into calendar (cal_date) values
('2015-01-01'), ('2015-01-02'), ('2015-01-03'), ('2015-01-04'),
('2015-01-05'), ('2015-01-06'), ('2015-01-07'), ('2015-01-08'),
('2015-01-09'), ('2015-01-10'), ('2015-01-11'), ('2015-01-12'),
('2015-01-13'), ('2015-01-14'), ('2015-01-15'), ('2015-01-16'),
('2015-01-17'), ('2015-01-18'), ('2015-01-19'), ('2015-01-20'),
('2015-01-21'), ('2015-01-22'), ('2015-01-23'), ('2015-01-24'),
('2015-01-25'), ('2015-01-26'), ('2015-01-27'), ('2015-01-28'),
('2015-01-29'), ('2015-01-30'), ('2015-01-31'),
('2015-02-01'), ('2015-02-02'), ('2015-02-03'), ('2015-02-04'),
('2015-02-05'), ('2015-02-06'), ('2015-02-07'), ('2015-02-08'),
('2015-02-09'), ('2015-02-10'), ('2015-02-11'), ('2015-02-12'),
('2015-02-13'), ('2015-02-14'), ('2015-02-15'), ('2015-02-16'),
('2015-02-17'), ('2015-02-18'), ('2015-02-19'), ('2015-02-20'),
('2015-02-21'), ('2015-02-22'), ('2015-02-23'), ('2015-02-24'),
('2015-02-25'), ('2015-02-26'), ('2015-02-27'), ('2015-02-28')
;
update calendar
set day_of_week = datename(weekday, cal_date);
alter table calendar
alter column day_of_week varchar(15) not null;
alter table calendar
add constraint cal_date_matches_dow
check (datename(weekday, cal_date) = day_of_week);
create index day_of_week_ix on calendar (day_of_week);
设置权限以便
- 每个人都可以 select,但是
- 几乎没有人可以插入新行,并且
- 更少的人可以删除行。
(或者写一个可以保证没有间隙的约束。我认为你可以在SQL服务器中做到这一点。)
您可以使用非常简单的 SQL 语句 select 今天之后的四个星期一。 (当前日期是 2015-01-05,是星期一。)
select top 4 cal_date
from calendar
where cal_date > convert(date, getdate())
and day_of_week = 'Monday'
order by cal_date;
CAL_DATE
--
2015-01-12
2015-01-19
2015-01-26
2015-02-02
对我来说,这是一个巨大的优势。没有程序代码。很简单SQL 明明是对的。大赢家。
试试这个,
DECLARE @YEAR INT=2015
DECLARE @MONTH INT=1
DECLARE @DAY INT=1
DECLARE @DATE DATE = (SELECT DateFromParts(@Year, @Month, @Day))
DECLARE @TOTAL_DAYS INT =(SELECT DatePart(DY, @DATE));
WITH CTE1
AS (SELECT T_DAY=(SELECT DateName(DW, @DATE)),
@DATE AS T_DATE,
@DAY AS T_DDAY
UNION ALL
SELECT T_DAY=(SELECT DateName(DW, DateAdd(DAY, T_DDAY + 1, @DATE))),
DateAdd(DAY, T_DDAY + 1, @DATE) AS T_DATE,
T_DDAY + 1
FROM CTE1
WHERE T_DDAY + 1 <= 364)
SELECT DISTINCT T_DAY,
Stuff((SELECT ',' + CONVERT(VARCHAR(30), T_DATE)
FROM CTE1 A
WHERE A.T_DAY=CTE1.T_DAY AND A.T_DATE > GetDate() AND A.T_DATE<(DATEADD(WEEK,4,GETDATE()))
FOR XML PATH('')), 1, 1, '') AS FUTURE
FROM CTE1
ORDER BY T_DAY
OPTION (MAXRECURSION 365)
你的样本table
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
QUERY 1 : Select 特定工作日当月最近 4 周的天数
-- Gets first day of month
DECLARE @FIRSTDAY DATE=DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
;WITH CTE as
(
-- Will find all dates in current month
SELECT CAST(@FIRSTDAY AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(MONTH,1,@FIRSTDAY)
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal,DATES,
-- Get week difference for each weekday
DATEDIFF(WEEK,DATES,GETDATE()) WEEKDIFF,
-- Count the number of weekdays in a month
COUNT(DATES) OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES)) WEEKCOUNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
WHERE MONTH(DATES)= MONTH(GETDATE())
)
-- Converts to CSV and make sure that only nearest 4 week of days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal AND
((WEEKDIFF<3 AND WEEKDIFF>-3 AND WEEKCOUNT = 5) OR WEEKCOUNT <= 4)
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
例如Query2中最近的日期(这里我们以星期六为例)
2015-Jan-10 will be 01/03,01/10,01/17,01/24
2015-Jan-24 will be 01/10,01/17,01/24,01/31
问题 2:Select 与月份无关的特定工作日的接下来 4 周的日期
;WITH CTE as
(
-- Will find the next 4 week details
SELECT CAST(GETDATE() AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(DAY,28,GETDATE())
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal, DATES,
ROW_NUMBER() OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES) ORDER BY CTE.DATES) DATECNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
)
-- Converts to CSV and make sure that only 4 days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal
AND DATECNT < 5
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
如果 GETDATE()
(如果是星期六)是
,则输出如下
2015-01-05 - 1/10, 1/17, 1/24, 1/31
2015-01-24 - 1/24, 1/31, 2/7, 2/14
在已经给出的一些答案中看到了 DATENAME
的使用,我想指出 DATENAME
的 return 值可能会有所不同取决于您的 current language setting,但您可以保存当前语言设置并确保使用 us_english
,这样您就可以自信地使用英文工作日名称。
现在这是我使用用户定义的 table 值函数来获取某个(已知)工作日的 4 个下一个日期的稍微不同的方法,该函数允许创建数字序列 table (是的,这是一个非常乏味的函数,您必须将 MaxValue 传递给更大的 MinValue,但是如果需要,可以很容易地增强它,但是嘿,它完成了工作)。使用该函数跨越 table 超过 28 个值 (接下来的 28 天确实应该包括接下来的 4 个相关工作日;)),在 [=15= 上应用 DATEADD
] 并将带有 WHERE
的结果集减少到只有那些具有正确工作日的值:
CREATE FUNCTION GetIntSequence(@MinValue INT, @MaxValue INT)
RETURNS @retSequence TABLE
(
IntValue INT NOT NULL
)
BEGIN
DECLARE @i INT = (SELECT @MinValue)
WHILE @i <= @MaxValue
BEGIN
INSERT INTO @retSequence (IntValue) SELECT @i
SELECT @i = @i + 1
END
RETURN
END
GO
DECLARE @weekDay NVARCHAR(MAX) = 'Monday' --(or Tuesday, wednesday, ...)
--save current language setting
DECLARE @languageBackup NVARCHAR(MAX) = (SELECT @@LANGUAGE)
--ensure us english language setting for reliable weekday names
SET LANGUAGE us_english;
SELECT FourWeeks.SomeDay FROM
(
SELECT
DATEADD(DAY, IntValue, GETDATE()) AS SomeDay
FROM dbo.GetIntSequence(1, 28)
) AS FourWeeks
WHERE DATENAME(WEEKDAY, SomeDay) = @weekDay
--restore old language setting
SET LANGUAGE @languageBackup;
GO
DROP FUNCTION dbo.GetIntSequence
我正在处理一个处理频率值(即星期一、星期二等 - 想想作业)的查询。
所以在我的查询中,我目前的结果是
jobId:1, personId:100, frequencyVal: 'Mondays'
jobId:2, personId:101, frequencyVal: 'Saturdays'
我需要的是 frequencyVal 接下来的 4 个未来(或当前)日期。
所以如果今天是 1/3/2015
我需要我的结果集是
jobId:1, personId:100, frequencyVal: 'Mondays', futureDates: '1/5,1/12,1/19,1/26'
jobId:2, personId:102, frequencyVal: 'Saturdays', futureDates: '1/3,1/10,1/17,1/24'
我正在查看以下帖子: How to find the Nearest (day of the week) for a given date
但这将其设置为特定日期。我正在查看这是一个 Web 应用程序,我想要当前日期的日期。因此,如果我尝试在下周二运行此查询 jobId:1 would remove the 1/5 and add the 2/2
.
有没有办法传入工作日值以获得下一个最近的日期?
没有内置函数可以执行此操作。但是你可以试试这个,你可以把它放在一个标量值函数中:
DECLARE @WeekDay VARCHAR(10) = 'Monday';
DECLARE @WeekDayInt INT;
SELECT @WeekDayInt = CASE @WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
SELECT CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + @WeekDayInt) % 7, GETDATE())) AS NearestDate
更新:
看来雷达是对的,这是解决方案:
DECLARE @WeekDay VARCHAR(10) = 'Monday';
DECLARE @WeekDayInt INT;
DECLARE @Date DATETIME = GETDATE();
SELECT @WeekDayInt = CASE @WeekDay
WHEN 'SUNDAY' THEN 1
WHEN 'MONDAY' THEN 2
WHEN 'TUESDAY' THEN 3
WHEN 'WEDNESDAY' THEN 4
WHEN 'THURSDAY' THEN 5
WHEN 'FRIDAY' THEN 6
WHEN 'SATURDAY' THEN 7 END
DECLARE @Diff INT = DATEPART(WEEKDAY, @Date) - @WeekDayInt;
SELECT CONVERT(DATE, DATEADD(DAY, CASE WHEN @Diff >= 0 THEN 7 - @Diff ELSE ABS(@Diff) END, @Date)) AS NearestDate
试试这个 - 根据
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
WITH cte(n) AS
(
SELECT 0
UNION ALL
SELECT n+1 FROM cte WHERE n < 3
)
select #t.jobId, #t.personId, #t.frequencyVal, STUFF(a.d, 1, 1, '') AS FutureDates
from #t
cross apply (SELECT CASE #t.frequencyVal
WHEN 'SUNDAYS' THEN 1
WHEN 'MONDAYS' THEN 2
WHEN 'TUESDAYS' THEN 3
WHEN 'WEDNESDAYS' THEN 4
WHEN 'THURSDAYS' THEN 5
WHEN 'FRIDAYS' THEN 6
WHEN 'SATURDAYS' THEN 7
END)tranlationWeekdays(n)
cross apply (select ',' + CONVERT(varchar(10), CONVERT(date,dateadd(WEEK, cte.n,CONVERT(DATE, DATEADD(DAY, (DATEPART(WEEKDAY, GETDATE()) + tranlationWeekdays.n) % 7, GETDATE()))))) from cte FOR XML PATH('')) a(d);
drop table #t;
这是我认为比较简单的方法,我觉得很符合你的要求。
请注意,我已将您的 frequency_val
列更改为代表 SQL 服务器角度的星期几的整数,并添加了一个计算列以说明您如何轻松导出日期名称从那个。
declare @t table
(
jobId int,
personId int,
--frequencyVal varchar(10)
frequency_val int,
frequency_day as datename(weekday,frequency_val -1) + 's'
);</p>
<p>declare @num_occurances int = 4
declare @from_date date = dateadd(dd,3,getdate()) -- this will allow you to play with the date simply by changing the increment value</p>
<p>insert into @t
values
(1,100,1),--'Mondays'),
(2,101,6),--'Saturdays');
(3,101,7),--'Saturdays');
(4,100,2)--'Mondays'),
--select * from @t</p>
<p>;with r_cte (days_ahead, occurance_date)
as (select 0, convert(date,@from_date,121)
union all
select r_cte.days_ahead +1, convert(date,dateadd(DD, r_cte.days_ahead+1, @from_date),121)
from r_cte
where r_cte.days_ahead < 7 * @num_occurances
)
select t.*, r_cte.occurance_date
from
@t t
inner join r_cte
on DATEPART(WEEKDAY, dateadd(dd,@@DATEFIRST - 1 ,r_cte.occurance_date)) = t.frequency_val
</pre>
对于此类查询,我更喜欢日历 table。实际上,对于大多数查询,我更喜欢日历 table 而不是日期函数。这是一个最小的。我在生产中使用的那个有更多的列和更多的行。 (100 年的数据只有 37k 行。)
create table calendar (
cal_date date not null primary key,
day_of_week varchar(15)
);
insert into calendar (cal_date) values
('2015-01-01'), ('2015-01-02'), ('2015-01-03'), ('2015-01-04'),
('2015-01-05'), ('2015-01-06'), ('2015-01-07'), ('2015-01-08'),
('2015-01-09'), ('2015-01-10'), ('2015-01-11'), ('2015-01-12'),
('2015-01-13'), ('2015-01-14'), ('2015-01-15'), ('2015-01-16'),
('2015-01-17'), ('2015-01-18'), ('2015-01-19'), ('2015-01-20'),
('2015-01-21'), ('2015-01-22'), ('2015-01-23'), ('2015-01-24'),
('2015-01-25'), ('2015-01-26'), ('2015-01-27'), ('2015-01-28'),
('2015-01-29'), ('2015-01-30'), ('2015-01-31'),
('2015-02-01'), ('2015-02-02'), ('2015-02-03'), ('2015-02-04'),
('2015-02-05'), ('2015-02-06'), ('2015-02-07'), ('2015-02-08'),
('2015-02-09'), ('2015-02-10'), ('2015-02-11'), ('2015-02-12'),
('2015-02-13'), ('2015-02-14'), ('2015-02-15'), ('2015-02-16'),
('2015-02-17'), ('2015-02-18'), ('2015-02-19'), ('2015-02-20'),
('2015-02-21'), ('2015-02-22'), ('2015-02-23'), ('2015-02-24'),
('2015-02-25'), ('2015-02-26'), ('2015-02-27'), ('2015-02-28')
;
update calendar
set day_of_week = datename(weekday, cal_date);
alter table calendar
alter column day_of_week varchar(15) not null;
alter table calendar
add constraint cal_date_matches_dow
check (datename(weekday, cal_date) = day_of_week);
create index day_of_week_ix on calendar (day_of_week);
设置权限以便
- 每个人都可以 select,但是
- 几乎没有人可以插入新行,并且
- 更少的人可以删除行。
(或者写一个可以保证没有间隙的约束。我认为你可以在SQL服务器中做到这一点。)
您可以使用非常简单的 SQL 语句 select 今天之后的四个星期一。 (当前日期是 2015-01-05,是星期一。)
select top 4 cal_date
from calendar
where cal_date > convert(date, getdate())
and day_of_week = 'Monday'
order by cal_date;
CAL_DATE -- 2015-01-12 2015-01-19 2015-01-26 2015-02-02
对我来说,这是一个巨大的优势。没有程序代码。很简单SQL 明明是对的。大赢家。
试试这个,
DECLARE @YEAR INT=2015
DECLARE @MONTH INT=1
DECLARE @DAY INT=1
DECLARE @DATE DATE = (SELECT DateFromParts(@Year, @Month, @Day))
DECLARE @TOTAL_DAYS INT =(SELECT DatePart(DY, @DATE));
WITH CTE1
AS (SELECT T_DAY=(SELECT DateName(DW, @DATE)),
@DATE AS T_DATE,
@DAY AS T_DDAY
UNION ALL
SELECT T_DAY=(SELECT DateName(DW, DateAdd(DAY, T_DDAY + 1, @DATE))),
DateAdd(DAY, T_DDAY + 1, @DATE) AS T_DATE,
T_DDAY + 1
FROM CTE1
WHERE T_DDAY + 1 <= 364)
SELECT DISTINCT T_DAY,
Stuff((SELECT ',' + CONVERT(VARCHAR(30), T_DATE)
FROM CTE1 A
WHERE A.T_DAY=CTE1.T_DAY AND A.T_DATE > GetDate() AND A.T_DATE<(DATEADD(WEEK,4,GETDATE()))
FOR XML PATH('')), 1, 1, '') AS FUTURE
FROM CTE1
ORDER BY T_DAY
OPTION (MAXRECURSION 365)
你的样本table
create table #t
(
jobId int,
personId int,
frequencyVal varchar(10)
);
insert into #t values (1,100,'Mondays'),(2,101,'Saturdays');
QUERY 1 : Select 特定工作日当月最近 4 周的天数
-- Gets first day of month
DECLARE @FIRSTDAY DATE=DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
;WITH CTE as
(
-- Will find all dates in current month
SELECT CAST(@FIRSTDAY AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(MONTH,1,@FIRSTDAY)
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal,DATES,
-- Get week difference for each weekday
DATEDIFF(WEEK,DATES,GETDATE()) WEEKDIFF,
-- Count the number of weekdays in a month
COUNT(DATES) OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES)) WEEKCOUNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
WHERE MONTH(DATES)= MONTH(GETDATE())
)
-- Converts to CSV and make sure that only nearest 4 week of days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal AND
((WEEKDIFF<3 AND WEEKDIFF>-3 AND WEEKCOUNT = 5) OR WEEKCOUNT <= 4)
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
例如Query2中最近的日期(这里我们以星期六为例)
2015-Jan-10 will be 01/03,01/10,01/17,01/24
2015-Jan-24 will be 01/10,01/17,01/24,01/31
问题 2:Select 与月份无关的特定工作日的接下来 4 周的日期
;WITH CTE as
(
-- Will find the next 4 week details
SELECT CAST(GETDATE() AS DATE) as DATES
UNION ALL
SELECT DATEADD(DAY,1,DATES)
FROM CTE
WHERE DATES < DATEADD(DAY,28,GETDATE())
)
,CTE2 AS
(
-- Join the #t table with CTE on the datename+'s'
SELECT jobId,personId,frequencyVal, DATES,
ROW_NUMBER() OVER(PARTITION BY DATENAME(WEEKDAY,CTE.DATES) ORDER BY CTE.DATES) DATECNT
FROM CTE
JOIN #t ON DATENAME(WEEKDAY,CTE.DATES)+'s' = #t.frequencyVal
)
-- Converts to CSV and make sure that only 4 days are generated for month
SELECT DISTINCT C2.jobId,C2.personId,frequencyVal,
SUBSTRING(
(SELECT ', ' + CAST(DATEPART(MONTH,DATES) AS VARCHAR(2)) + '/' +
CAST(DATEPART(DAY,DATES) AS VARCHAR(2))
FROM CTE2
WHERE C2.jobId=jobId AND C2.personId=personId AND C2.frequencyVal=frequencyVal
AND DATECNT < 5
ORDER BY CTE2.DATES
FOR XML PATH('')),2,200000) futureDates
FROM CTE2 C2
如果 GETDATE()
(如果是星期六)是
2015-01-05 - 1/10, 1/17, 1/24, 1/31
2015-01-24 - 1/24, 1/31, 2/7, 2/14
在已经给出的一些答案中看到了 DATENAME
的使用,我想指出 DATENAME
的 return 值可能会有所不同取决于您的 current language setting,但您可以保存当前语言设置并确保使用 us_english
,这样您就可以自信地使用英文工作日名称。
现在这是我使用用户定义的 table 值函数来获取某个(已知)工作日的 4 个下一个日期的稍微不同的方法,该函数允许创建数字序列 table (是的,这是一个非常乏味的函数,您必须将 MaxValue 传递给更大的 MinValue,但是如果需要,可以很容易地增强它,但是嘿,它完成了工作)。使用该函数跨越 table 超过 28 个值 (接下来的 28 天确实应该包括接下来的 4 个相关工作日;)),在 [=15= 上应用 DATEADD
] 并将带有 WHERE
的结果集减少到只有那些具有正确工作日的值:
CREATE FUNCTION GetIntSequence(@MinValue INT, @MaxValue INT)
RETURNS @retSequence TABLE
(
IntValue INT NOT NULL
)
BEGIN
DECLARE @i INT = (SELECT @MinValue)
WHILE @i <= @MaxValue
BEGIN
INSERT INTO @retSequence (IntValue) SELECT @i
SELECT @i = @i + 1
END
RETURN
END
GO
DECLARE @weekDay NVARCHAR(MAX) = 'Monday' --(or Tuesday, wednesday, ...)
--save current language setting
DECLARE @languageBackup NVARCHAR(MAX) = (SELECT @@LANGUAGE)
--ensure us english language setting for reliable weekday names
SET LANGUAGE us_english;
SELECT FourWeeks.SomeDay FROM
(
SELECT
DATEADD(DAY, IntValue, GETDATE()) AS SomeDay
FROM dbo.GetIntSequence(1, 28)
) AS FourWeeks
WHERE DATENAME(WEEKDAY, SomeDay) = @weekDay
--restore old language setting
SET LANGUAGE @languageBackup;
GO
DROP FUNCTION dbo.GetIntSequence