基于日期获取所有日期 - 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”只是一种查询语言,而不是特定数据库产品的名称。请为您正在使用的数据库产品添加标签postgresqloraclesql-serverdb2、... edit您的问题并添加一些sample data 和基于该数据的预期输出。 Formatted text 请no screen shots。 (edit 您的问题 - 在 cmets 中不要邮政编码或其他信息) 我已经编辑了我的问题 也许这是一个很好的起点:sqlservercentral.com/articles/calendar/145206 【参考方案1】:

在范围之间生成日期的另一种方法可能类似于以下查询。与CTEWHILE 循环相比,这将更快。

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 =, !=, &lt;, &lt;= , &gt;, &gt;= 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 &lt; 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的主要内容,如果未能解决你的问题,请参考以下文章

SQL获取日期的所有格式

SQL — 获取 A 列日期与 B 列日期相差 7 天的所有行

SQL获取两个日期之间的所有星期六

SQL 按日期排序并按用户获取结果

获取日期范围与列中最小日期之间的所有行

SQL 获取帖子的最新评论日期 - 论坛