복붙노트

[SQL] 날짜 범위 사이의 날짜를 생성

SQL

날짜 범위 사이의 날짜를 생성

나는이 주어진 날짜 사이의 날짜 범위를 저장하는 테이블을 채울 필요가 : 09/01/11를 - 10/10/11

따라서이 경우에는 테이블이 09/01/11에서 시작하고 10/10/11에 도착까지 하루를 저장하는 것 나는 현재 SQL 서버를 2008 년 감사를 사용하고 있습니다 - SQL 서버에서이 일을 매끄러운 방법이 있다면 궁금 해서요

해결법

  1. ==============================

    1.SQL 2005 + 간편한; 당신은 숫자 또는 집계 테이블이있는 경우 쉽게. 나는 그것을 아래 위조 :

    SQL 2005 + 간편한; 당신은 숫자 또는 집계 테이블이있는 경우 쉽게. 나는 그것을 아래 위조 :

    DECLARE @StartDate DATE = '20110901'
      , @EndDate DATE = '20111001'
    
    SELECT  DATEADD(DAY, nbr - 1, @StartDate)
    FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
              FROM      sys.columns c
            ) nbrs
    WHERE   nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)
    

    당신이 집계 테이블이있는 경우, 테이블과 하위 쿼리를 교체합니다. 아니 재귀 없습니다.

  2. ==============================

    2.당신은 SQL 서버 2005 이상을 사용하는 경우이 시도 :

    당신은 SQL 서버 2005 이상을 사용하는 경우이 시도 :

    WITH Dates AS (
            SELECT
             [Date] = CONVERT(DATETIME,'09/01/2011')
            UNION ALL SELECT
             [Date] = DATEADD(DAY, 1, [Date])
            FROM
             Dates
            WHERE
             Date < '10/10/2011'
    ) SELECT
     [Date]
    FROM
     Dates
     OPTION (MAXRECURSION 45)
    

    멋진 물건의 좋은 예 당신은 CTE로 할 수 있습니다.

  3. ==============================

    3.- 선언

    - 선언

    DECLARE @dates TABLE(dt datetime)    
    DECLARE @dateFrom datetime
    DECLARE @dateTo datetime
    
    SET @dateFrom = '2001/01/01'
    SET @dateTo = '2001/01/12'
    

    - 검색어 :

    WHILE(@dateFrom < @dateTo)
    BEGIN
       SELECT @dateFrom = DATEADD(day, 1,@dateFrom)
       INSERT INTO @dates 
       SELECT @dateFrom
    END
    

    - 출력

    SELECT * FROM @dates
    
  4. ==============================

    4.여기에 재귀를 필요로하지 않는 솔루션과 동시에,이 테이블 반환 함수는 다시 보일러 변수의 선언을 반복 할 필요없이 많은 쿼리에 다시 사용할 수 있습니다. 이것은 재귀를 원하지 않는 사람들을위한 유일한 대안이다.

    여기에 재귀를 필요로하지 않는 솔루션과 동시에,이 테이블 반환 함수는 다시 보일러 변수의 선언을 반복 할 필요없이 많은 쿼리에 다시 사용할 수 있습니다. 이것은 재귀를 원하지 않는 사람들을위한 유일한 대안이다.

    이 간단한 함수를 만듭니다 :

    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;
    

    그리고에 의해 선택 :

    select *
    from dbo.GenerateDateRange('2017-01-03', '2017-12-01', 1)
    
  5. ==============================

    5.사용 MVJ의 F_TABLE_DATE 기능, 그것은 순전히 굉장합니다 :

    사용 MVJ의 F_TABLE_DATE 기능, 그것은 순전히 굉장합니다 :

    http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=61519

    이 구현되면 바로 시작 날짜와 종료 날짜를 전달하면 사이의 모든 날짜를 삽입 할 수 있습니다.

  6. ==============================

    6.타인의 편의를 위해 @Abe Miesler의 답변을 사용하여 난 이후 SQL 서버 2008에 대한 TVF로를 건설했다. 그것은 다른 사람들을 도울 수 있습니다 - 나는 TVF 내부의 CTE를 포함 할 수있는 방법을 찾아야했다!

    타인의 편의를 위해 @Abe Miesler의 답변을 사용하여 난 이후 SQL 서버 2008에 대한 TVF로를 건설했다. 그것은 다른 사람들을 도울 수 있습니다 - 나는 TVF 내부의 CTE를 포함 할 수있는 방법을 찾아야했다!

        --Generate a range of dates with interval option, courtesy of Abe Miessler for the core query here!
    ALTER FUNCTION [dbo].[DateRange]
    (@startDate AS DATE,
     @EndDate AS   DATE,
     @interval AS  INT
    )
    RETURNS @Dates TABLE(dateValue DATE)
    AS
         BEGIN
             WITH Dates
                  AS (
                  SELECT [Date] = CONVERT( DATETIME, @startDate)
                  UNION ALL
                  SELECT [Date] = DATEADD(DAY, ISNULL(@interval, 1), [Date])
                  FROM Dates
                  WHERE Date < @EndDate)
                  INSERT INTO @Dates
                         SELECT [Date]
                         FROM Dates
                         OPTION(MAXRECURSION 900);
             RETURN;
         END;
    
  7. ==============================

    7.

    Declare @StartDate datetime = '2015-01-01'
    Declare @EndDate datetime = '2016-12-01'
    declare @DaysInMonth int
    declare @tempDateRange Table
    (
    DateFrom datetime,
    DateThru datetime
    );
    
    While @StartDate<=@EndDate
    begin
        SET @DaysInMonth=DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,@StartDate),0)))
    
        IF DAY(@StartDate)=1 
            SET @EndDate=DATEADD(DAY,14,@StartDate)
        ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
            SET @EndDate=DATEADD(DAY,14,@StartDate)
        ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
            SET @EndDate=DATEADD(DAY,15,@StartDate)
        ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
            SET @EndDate=DATEADD(DAY,12,@StartDate)
        ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
            SET @EndDate=DATEADD(DAY,13,@StartDate)
    
        INSERT INTO @tempDateRange (DateFrom,DateThru)
        VALUES 
         (
            @StartDate,
            @EndDate
         )
    
        SET @StartDate=DATEADD(DAY,1,@EndDate)
    
        IF @EndDate< '2016-12-31'
         IF DAY(@StartDate)=1 
            SET @EndDate=DATEADD(DAY,14,@StartDate)
         ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
            SET @EndDate=DATEADD(DAY,14,@StartDate)
         ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
            SET @EndDate=DATEADD(DAY,15,@StartDate)
         ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
            SET @EndDate=DATEADD(DAY,12,@StartDate)
         ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
            SET @EndDate=DATEADD(DAY,13,@StartDate)
    end ;
    
    select * from @tempDateRange
    
    +++++++++++++++++++++++++++++
    Result:
    DateFrom |DateThru
    
  8. ==============================

    8.어떤 이유로 당신이 그런 미인에 파생 테이블을 사용할 때와 같은 변수를 선언 할 수없는 경우는 다음과 같이 갈 수 있습니다 :

    어떤 이유로 당신이 그런 미인에 파생 테이블을 사용할 때와 같은 변수를 선언 할 수없는 경우는 다음과 같이 갈 수 있습니다 :

    select
      dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
    from (
      select row_number() over (order by c.object_id) as nbr from sys.columns c
    ) nbrs
    where
      nbr - 1 <= datediff(
        day,
        convert(date, '2017-01-01'),
        convert(date, '2018-12-31')
      )
    

    그런데,이 날짜 시리즈보기 LookML처럼 보일 수있는 방법입니다 :

    view: date_series {
      derived_table: {
        sql:
          select
            dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
          from (
            select row_number() over (order by c.object_id) as nbr from sys.columns c
          ) nbrs
          where
            nbr - 1 <= datediff(day, convert(date, '2017-01-01'), convert(date, '2018-12-31')) ;;
      }
    
      dimension: date {
        primary_key: yes
        type: date
        sql: ${TABLE}.d ;;
      }
    }
    
  9. ==============================

    9.

    CREATE table #ProductSales (ProjectID Int, ProjectName varchar(100), TotalBillableFees Money, StartDate Date, EndDate Date, DataDate Date)
    
      Insert into #ProductSales
      Values
      (373104,'Product Sales - Flex Creation Test',40000.00,'2019-04-01','2020-06-01','2019-08-01'),
      (375111,'Product Sales - SMART',40000.00,'2019-04-01','2019-09-01','2019-08-01')
    
      ;WITH Dates AS (
            SELECT ProjectiD
            ,Convert(decimal(10,2),TotalBillableFees/IIF(DATEDIFF(MONTH,StartDate,EndDate)=0,1,DATEDIFF(MONTH,StartDate,EndDate))) AS BillableFeesPerMonths,EndDate
             ,[Date] = CONVERT(DATETIME,EOMONTH(StartDate))
             FROM #ProductSales
            UNION ALL SELECT ProjectiD,BillableFeesPerMonths,EndDate,
             [Date] = DATEADD(MONTH, 1, [Date])
            FROM
             Dates
            WHERE
             Date < EOMONTH(EndDate)
    ) SELECT ProjectID,BillableFeesPerMonths,
     CAST([Date] as Date) Date
    FROM
     Dates
     OPTION (MAXRECURSION 45)
    
  10. ==============================

    10.나는이 오래된 스레드 실현,하지만 난 여기에 주어진 순환 및 루핑 솔루션의 과잉에 나의 실망을 인정해야한다. 나는 재귀 아무 이상이 매우 비싼 루프보다 없다는 것을 깨닫게 얼마나 많은 사람들 궁금해? 나는 테이블 반환 함수를 만들 수있는 욕망을 이해하지만, 나는 그것이 반복, 재귀없이, 설정을 기반으로, 또는 단일 삽입 문을 반복으로 다음과 같은 훨씬 더 효율적입니다 제안 :

    나는이 오래된 스레드 실현,하지만 난 여기에 주어진 순환 및 루핑 솔루션의 과잉에 나의 실망을 인정해야한다. 나는 재귀 아무 이상이 매우 비싼 루프보다 없다는 것을 깨닫게 얼마나 많은 사람들 궁금해? 나는 테이블 반환 함수를 만들 수있는 욕망을 이해하지만, 나는 그것이 반복, 재귀없이, 설정을 기반으로, 또는 단일 삽입 문을 반복으로 다음과 같은 훨씬 더 효율적입니다 제안 :

    CREATE FUNCTION dbo.GenerateDateRange(@StartDate AS DATE, @EndDate AS DATE)
    RETURNS TABLE WITH SCHEMABINDING AS
        WITH e1(n) AS (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS x(n)) -- 16 records
            ,e2(n) AS (SELECT 1 FROM e1 a CROSS JOIN e1 b) -- 16^2 or 256 records (16*16)
            ,cteTally(n) AS (SELECT ROW_NUMBER() over (ORDER BY 1) AS n FROM e2 a CROSS JOIN e2 b) -- 16^4 or 65,536 records (256*256)
        SELECT DATEADD(DAY, n-1, @StartDate)
        FROM cteTally
        WHERE n <= DATEDIFF(DAY, @StartDate, @EndDate) + 1;
    GO
    
  11. from https://stackoverflow.com/questions/7824831/generate-dates-between-date-ranges by cc-by-sa and MIT license