基于日期获取所有日期 - sql
Posted
技术标签:
【中文标题】基于日期获取所有日期 - sql【英文标题】:Based on day fetch all dates - sql 【发布时间】:2018-04-11 11:13:09 【问题描述】:我有开始日期、结束日期和日期名称。如何在sql中获取特定日期的这两个日期之间的所有日期?
示例数据:
开始日期:2018 年 4 月 11 日 结束日期:2018 年 5 月 11 日 日期:星期一、星期四预期输出:周一和周四开始和结束日期之间的所有日期并将它们存储在表中
更新 我现在的代码(不工作)
; WITH CTE(dt)
AS
(
SELECT @P_FROM_DATE
UNION ALL
SELECT DATEADD(dw, 1, dt) FROM CTE
WHERE dt < @P_TO_DATE
)
INSERT INTO Table_name
(
ID
,DATE_TIME
,STATUS
,CREATED_DATE
,CREATED_BY
)
SELECT @P_ID
,(SELECT dt FROM CTE WHERE DATENAME(dw, dt) In ('tuesday','friday',null))
,'NOT SENT'
,CAST(GETDATE() AS DATE)
,@USER_ID
【问题讨论】:
你需要一个日历表,或者一个 cte 生产日历表。 您使用的是哪个DBMS? “SQL”只是一种查询语言,而不是特定数据库产品的名称。请为您正在使用的数据库产品添加标签postgresql
、oracle
、sql-server
、db2
、...
请edit您的问题并添加一些sample data 和基于该数据的预期输出。 Formatted text 请no screen shots。 (edit 您的问题 - 在 cmets 中不要邮政编码或其他信息)
我已经编辑了我的问题
也许这是一个很好的起点:sqlservercentral.com/articles/calendar/145206
【参考方案1】:
在范围之间生成日期的另一种方法可能类似于以下查询。与CTE
或WHILE
循环相比,这将更快。
DECLARE @StartDate DATETIME = '2018-04-11'
DECLARE @EndDate DATETIME = '2018-05-15'
SELECT @StartDate + RN AS DATE FROM
(
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)))-1 RN
FROM master..[spt_values] T1
) T
WHERE RN <= DATEDIFF(DAY,@StartDate,@EndDate)
AND DATENAME(dw,@StartDate + RN) IN('Monday','Thursday')
注意:
如果master..[spt_values]
中存在的行数不足以满足提供的范围,您可以进行交叉连接以获得更大的范围,如下所示。
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)))-1 RN
FROM master..[spt_values] T1
CROSS JOIN master..[spt_values] T2
通过这种方式,您将能够在间隔为 6436369 天的范围内生成日期。
【讨论】:
对此的几点说明:1. spt_values is undocumented。 2.您可以摆脱最外层的查询,并在中间查询上执行它的 where 子句。 3.除此之外,它与我即将发布的内容非常接近,所以+1。 @ZoharPeled,感谢您的输入,您是正确的。我已经删除了外部选择。【参考方案2】:您可以使用recursive common table expression (CTE) 生成日期列表。使用datepart(dw, ...)
,您可以过滤一周中的特定日期。
创建 3 月 1 日至今天之间的星期一和星期四列表的示例:
create table ListOfDates (dt date);
with cte as
(
select cast('2018-03-01' as date) as dt -- First day of interval
union all
select dateadd(day, 1, dt)
from cte
where dt < getdate() -- Last day of interval
)
insert into ListOfDates
(dt)
select dt
from cte
where datepart(dw, dt) in (2, 5) -- 2=Monday and 5=Thursday
option (maxrecursion 0)
See it working at SQL Fiddle.
【讨论】:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
这是我遇到的错误。
不知道怎么解释,上面的查询可以在 SQL Fiddle 上运行!
create table ListOfDates (dt date, name varchar(20)); with cte as ( select cast('2018-03-01' as date) as dt union all select dateadd(day, 1, dt) from cte where dt < getdate() ) insert into ListOfDates (dt, name) select (select dt from cte where datepart(dw, dt) in (2, 5) ),-- Monday and Thursday 'hello'
在小提琴中尝试同样的方法
查询的select
部分不能产生多行。这必须在from
部分完成。有关插入名称和日期的方法,请参见此处:sqlfiddle.com/#!18/66678/1/0【参考方案3】:
这对你有用:
DECLARE @table TABLE(
ID INT IDENTITY(1,1),
Date DATETIME,
Day VARCHAR(50)
)
DECLARE @Days TABLE(
ID INT IDENTITY(1,1),
Day VARCHAR(50)
)
INSERT INTO @Days VALUES ('Monday')
INSERT INTO @Days VALUES ('Thursday')
DECLARE @StartDate DATETIME='2018-01-01';
DECLARE @EndDate DATETIME=GETDATE();
DECLARE @Day VARCHAR(50)='Friday';
DECLARE @TempDate DATETIME=@StartDate;
WHILE CAST(@TempDate AS DATE)<=CAST(@EndDate AS DATE)
BEGIN
IF EXISTS (SELECT 1 FROM @Days WHERE DAY IN (DATENAME(dw,@TempDate)))
BEGIN
INSERT INTO @table
VALUES (
@TempDate, -- Date - datetime
DATENAME(dw,@TempDate) -- Day - varchar(50)
)
END
SET @TempDate=DATEADD(DAY,1,@TempDate)
END
SELECT * FROM @table
【讨论】:
【参考方案4】:INSERT INTO TargetTab(dateCOL)
SELECT dateCOL
FROM tab
WHERE dateCOL >= startdate AND dateCOL <= enddate
AND (DATENAME(dw,dateCOL) ='Thursday' OR DATENAME(dw,dateCOL) = 'Monday')
试试这个查询来得到你的结果。
【讨论】:
我不明白dateCol
是什么
将其替换为您的表格日期列的名称【参考方案5】:
使用递归 CTE 生成日期,然后按工作日过滤。
SET DATEFIRST 1 -- 1: Monday, 7 Sunday
DECLARE @StartDate DATE = '2018-04-11'
DECLARE @EndDate DATE = '2018-05-15'
DECLARE @WeekDays TABLE (WeekDayNumber INT)
INSERT INTO @WeekDays (
WeekDayNumber)
VALUES
(1), -- Monday
(4) -- Thursday
;WITH GeneratingDates AS
(
SELECT
GeneratedDate = @StartDate,
WeekDay = DATEPART(WEEKDAY, @StartDate)
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, G.GeneratedDate),
WeekDay = DATEPART(WEEKDAY, DATEADD(DAY, 1, G.GeneratedDate))
FROM
GeneratingDates AS G -- Notice that we are referencing a CTE that we are also declaring
WHERE
G.GeneratedDate < @EndDate
)
SELECT
G.GeneratedDate
FROM
GeneratingDates AS G
INNER JOIN @WeekDays AS W ON G.WeekDay = W.WeekDayNumber
OPTION
(MAXRECURSION 30000)
【讨论】:
【参考方案6】:试试这个:
declare @start date = '04-11-2018'
declare @end date = '05-11-2018'
declare @P_ID int = 1
declare @USER_ID int = 11
;with cte as(
select @start [date]
union all
select dateadd(DAY, 1, [date]) from cte
where [date] < @end
)
--if MY_TABLE doesn't exist
select @P_ID,
[date],
'NOT SENT',
cast(getdate() as date),
@USER_ID
into MY_TABLE
from cte
--here you can specify days: 1 - Sunday, 2 - Monday, etc.
where DATEPART(dw,[date]) in (2, 5)
option (maxrecursion 0)
--if MY_TABLE does exist
--insert into MY_TABLE
--select @P_ID,
-- [date],
-- 'NOT SENT',
-- cast(getdate() as date),
-- @USER_ID
--from cte
--where DATEPART(dw,[date]) in (2, 5)
--option (maxrecursion 0)
【讨论】:
@prasanna 请尝试更新查询。此外,您可以删除评论,因为它们与讨论无关(我删除了我的)。以上是关于基于日期获取所有日期 - sql的主要内容,如果未能解决你的问题,请参考以下文章