SQL-将表中范围内的所有日期插入另一个

时间:2019-02-26 13:44:45

标签: sql sql-server tsql

我正在根据另一个表中包含的值填充一个带有日期的表。

Source : tblA
dtFrom       dtTo
2019-01-01   2019-01-03
2019-02-01   2019-02-02
2019-03-01   2019-03-01

Destination : tblB
sDate
2019-01-01
2019-01-02
2019-01-03
2019-02-01
2019-02-02
2019-03-01

SQL Server2014。一如既往,在此先感谢:-)

5 个答案:

答案 0 :(得分:2)

您可以使用递归CTE:

with dates as (
      select dtfrom as dt, dtto
      from tblA
      union all
      select dateadd(day, 1, dt), dtto
      from dates
      where dt < dtto
    )
insert tblB (sDate)
select distinct dt
from dates;

select distinct仅在处理重叠期间是必需的。如果您知道没有重叠,那就不要使用它。

答案 1 :(得分:0)

您可以使用union将两列中的值合并为一个行集:

insert  tblB
        (sDate)
select  distinct dt
from    (
        select  dtFrom as dt
        from    tblA
        union all
        select  dtTo
        from    tblA
        ) s

答案 2 :(得分:0)

使用始终方便使用的Calendar Table,该表在特定年份之间的所有天中每天都有1行。您可以添加诸如IsBusinessDayWorkingStartHour / WorkingEndHour之类的其他列,以使日期查询更加轻松。

-- Create Calendar Table
DECLARE @StartDate DATE = '2000-01-01'
DECLARE @EndDate DATE = '2050-01-01'

SET DATEFIRST 1 -- 1: Monday, 7: Sunday

CREATE TABLE CalendarTable (
    Date DATE PRIMARY KEY,
    IsWorkingDay BIT
    -- Other columns you might need
    )

;WITH RecursiveCTE AS
(
    SELECT
        Date = @StartDate

    UNION ALL

    SELECT
        Date = DATEADD(DAY, 1, R.Date)
    FROM
        RecursiveCTE AS R
    WHERE
        DATEADD(DAY, 1, R.Date) <= @EndDate
)
INSERT INTO CalendarTable (
    Date,
    IsWorkingDay)
SELECT
    Date = R.Date,
    IsWorkingDay = CASE WHEN DATEPART(WEEKDAY, R.Date) BETWEEN 1 AND 5 THEN 1 ELSE 0 END
FROM
    RecursiveCTE AS R
OPTION
    (MAXRECURSION 0)

现在有了日历表,只需将BETWEENINSERT加入目标表即可。您可以使用DISTINCT来确保日期不会重复:

INSERT INTO tblB (
    sDate)
SELECT DISTINCT
    sDate = C.Date
FROM
    tlbA AS A
    INNER JOIN CalendarTable AS C ON C.Date BETWEEN A.dtFrom AND A.dtTo

例如,假设您只想插入工作日(星期一至星期五)的记录。您只需要过滤日历表并完成。您可以在表上添加所需的任何逻辑,并在使用时对其进行过滤,而无需重复复杂的日期时间逻辑。

INSERT INTO tblB (
    sDate)
SELECT DISTINCT
    sDate = C.Date
FROM
    tlbA AS A
    INNER JOIN CalendarTable AS C ON C.Date BETWEEN A.dtFrom AND A.dtTo
WHERE
    C.IsWorkingDay = 1

答案 3 :(得分:0)

使用日历,您可以在范围上进行内部联接以产生Insert语句。

DECLARE @StartDate DATETIME = (SELECT MIN(dtFrom) FROM tblA)
DECLARE @EndDate DATETIME = (SELECT MAX(dtTo) FROM tblB)
;WITH Calendar as 
( 
    SELECT CalendarDate = @StartDate, CalendarYear = DATEPART(YEAR, @StartDate), CalendarMonth = DATEPART(MONTH, @StartDate) 
    UNION ALL 
    SELECT CalendarDate = DATEADD(MONTH, 1, CalendarDate), CalendarYear = DATEPART(YEAR, CalendarDate), CalendarMonth = DATEPART(MONTH, CalendarDate) 
    FROM Calendar WHERE DATEADD (MONTH, 1, CalendarDate) <= @EndDate 
) 

INSERT INTO tblB
SELECT DISTINCT
    C.CalendarDate
FROM
    Calendar C
    INNER JOIN tblA A ON C.CalendarDate BETWEEN A.dtFrom AND A.dtTo

答案 4 :(得分:0)

您可以通过使用以下查询来获得此结果。

步骤1-创建一个自定义函数,它将日期范围作为参数并返回日期序列。

oneResult

第2步-将此自定义函数与表tblA结合在一起,并根据需要将记录插入tblb中

CREATE FUNCTION [dbo].[GenerateDateRange]
(@StartDate AS DATE,
 @EndDate AS   DATE,
 @Interval AS  INT
)
RETURNS @Dates TABLE(DateValue DATE)
AS
BEGIN
    DECLARE @CUR_DATE DATE
    SET @CUR_DATE = @StartDate
    WHILE @CUR_DATE <= @EndDate BEGIN
        INSERT INTO @Dates VALUES(@CUR_DATE)
        SET @CUR_DATE = DATEADD(DAY, @Interval, @CUR_DATE)
    END
    RETURN;
END;