programing

날짜 범위로부터 일수를 생성하다

firstcheck 2023. 1. 21. 09:57
반응형

날짜 범위로부터 일수를 생성하다

다음과 같은 쿼리를 실행하고 싶습니다.

select ... as days where `date` is between '2010-01-20' and '2010-01-24'

그리고 다음과 같은 데이터를 반환합니다.

날들----------2010-01-202010-01-212010-01-222010-01-232010-01-24

이 솔루션에서는 루프, 프로시저 또는 임시 테이블을 사용하지 않습니다.서브쿼리는 지난 10,000일 동안의 날짜를 생성하며 원하는 만큼 이전 또는 앞으로 이동할 수 있도록 확장할 수 있습니다.

select a.Date 
from (
    select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY as Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
) a
where a.Date between '2010-01-20' and '2010-01-24' 

출력:

Date
----------
2010-01-24
2010-01-23
2010-01-22
2010-01-21
2010-01-20

퍼포먼스에 관한 주의사항

여기서 테스트한 결과, 퍼포먼스는 놀라울 정도로 우수합니다.상기 쿼리는 0.0009초 걸립니다.

서브쿼리를 확장하여 약 10만 개의 숫자(즉, 약 274년치)를 생성하면 0.0458초에 실행됩니다.

덧붙여서, 이것은 매우 휴대하기 쉬운 기술이며, 대부분의 데이터베이스에서는 약간의 조정이 필요합니다.

1,000일을 반환하는 SQL Fidle 예제

다음은 뷰를 사용한 다른 변형입니다.

CREATE VIEW digits AS
  SELECT 0 AS digit UNION ALL
  SELECT 1 UNION ALL
  SELECT 2 UNION ALL
  SELECT 3 UNION ALL
  SELECT 4 UNION ALL
  SELECT 5 UNION ALL
  SELECT 6 UNION ALL
  SELECT 7 UNION ALL
  SELECT 8 UNION ALL
  SELECT 9;

CREATE VIEW numbers AS
  SELECT
    ones.digit + tens.digit * 10 + hundreds.digit * 100 + thousands.digit * 1000 AS number
  FROM
    digits as ones,
    digits as tens,
    digits as hundreds,
    digits as thousands;

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers;

다음으로 간단하게 (얼마나 우아한지) 확인할 수 있습니다.

SELECT
  date
FROM
  dates
WHERE
  date BETWEEN '2010-01-20' AND '2010-01-24'
ORDER BY
  date

갱신하다

현재 날짜부터는 과거 날짜만 생성할 수 있습니다.날짜 범위(과거, 미래 및 중간)를 생성하려면 대신 이 보기를 사용해야 합니다.

CREATE VIEW dates AS
  SELECT
    SUBDATE(CURRENT_DATE(), number) AS date
  FROM
    numbers
  UNION ALL
  SELECT
    ADDDATE(CURRENT_DATE(), number + 1) AS date
  FROM
    numbers;

승인된 답변이 PostgreSQL에 대해 작동하지 않았습니다('a' 또는 그 근처에서의 구문 오류).

Postgre에서 이 작업을 수행하는 방법SQL은 다음과 같은 기능을 사용합니다.

SELECT day::date
FROM generate_series('2010-01-20', '2010-01-24', INTERVAL '1 day') day;

    day
------------
 2010-01-20
 2010-01-21
 2010-01-22
 2010-01-23
 2010-01-24
(5 rows)

CTE(Recursive Common Table Expression)를 사용하여 날짜 목록을 생성한 후 해당 목록에서 선택할 수 있습니다.일반적으로 300만 개의 날짜를 만들고 싶지 않을 것입니다. 따라서 이것은 단지 가능성을 보여주는 것입니다.CTE 내에서 날짜 범위를 제한하고 CTE를 사용하여 select 문에서 where 구를 생략할 수 있습니다.

with [dates] as (
    select convert(datetime, '1753-01-01') as [date] --start
    union all
    select dateadd(day, 1, [date])
    from [dates]
    where [date] < '9999-12-31' --end
)
select [date]
from [dates]
where [date] between '2013-01-01' and '2013-12-31'
option (maxrecursion 0)

Microsoft SQL Server 2005에서는 가능한 모든 날짜의 CTE 목록을 생성하는 데 1:08이 걸렸습니다.100년을 생성하는 데 1초도 걸리지 않았습니다.

MS SQL 쿼리

select datetable.Date 
from (
    select DATEADD(day,-(a.a + (10 * b.a) + (100 * c.a)),getdate()) AS Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) datetable
where datetable.Date between '2014-01-20' and '2014-01-24' 
order by datetable.Date DESC

산출량

Date
-----
2014-01-23 12:35:25.250
2014-01-22 12:35:25.250
2014-01-21 12:35:25.250
2014-01-20 12:35:25.250

이 작업을 하기 위한 기존 은 "/"를 입니다.NUMBERS1로 이 있습니다.

CREATE TABLE  `example`.`numbers` (
  `id` int(10) unsigned NOT NULL auto_increment,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

필요에 따라 충분한 레코드가 테이블에 입력되어야 합니다.

INSERT INTO NUMBERS (id) VALUES (NULL);

그 다음에NUMBERS테이블, 다음 중 하나를 사용할 수 있습니다.

SELECT x.start_date + INTERVAL n.id-1 DAY
  FROM NUMBERS n
  JOIN (SELECT STR_TO_DATE('2010-01-20', '%Y-%m-%d') AS start_date 
          FROM DUAL) x
 WHERE x.start_date + INTERVAL n.id-1 DAY <= '2010-01-24'

절대적인 로우테크 솔루션은 다음과 같습니다.

SELECT STR_TO_DATE('2010-01-20', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-21', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-22', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-23', '%Y-%m-%d')
 FROM DUAL
UNION ALL
SELECT STR_TO_DATE('2010-01-24', '%Y-%m-%d')
 FROM DUAL

어디에 쓰시겠습니까?


조인(LEFT JOIN)을 위해 날짜 또는 숫자 목록을 생성합니다.데이터의 어디에 갭이 있는지 확인하기 위해 이 작업을 수행합니다.순차 데이터 목록에 왼쪽 조인(LEFT JOIN)하기 때문입니다. null 값은 갭이 있는 위치를 나타냅니다.

Access 2010의 경우 - 여러 단계가 필요합니다.상기와 같은 패턴을 따르지만 Access에서 다른 사람을 도울 수 있다고 생각했습니다.나한테는 아주 잘 먹혔어, 난 씨앗이 뿌려진 날짜표를 쓸 필요가 없었지.

DUAL이라는 테이블을 만듭니다(Oracle DUAL 테이블의 동작 방식과 유사합니다).

  • ID(Auto Number)
  • 더미 컬럼(텍스트)
  • 행 값 1개 추가(1,"DummyRow")

"ZeroThru9Q"라는 이름의 쿼리를 만듭니다.다음 구문을 수동으로 입력합니다.

SELECT 0 AS a
FROM dual
UNION ALL
SELECT 1
FROM dual
UNION ALL
SELECT 2
FROM dual
UNION ALL
SELECT 3
FROM dual
UNION ALL
SELECT 4
FROM dual
UNION ALL
SELECT 5
FROM dual
UNION ALL
SELECT 6
FROM dual
UNION ALL
SELECT 7
FROM dual
UNION ALL
SELECT 8
FROM dual
UNION ALL
SELECT 9
FROM dual;

"TodayMinus1KQ"라는 이름의 쿼리를 만듭니다(오늘 이전 날짜의 경우). 수동으로 다음 구문을 입력합니다.

SELECT date() - (a.a + (10 * b.a) + (100 * c.a)) AS MyDate
FROM
  (SELECT *
   FROM ZeroThru9Q) AS a,

  (SELECT *
   FROM ZeroThru9Q) AS b,

  (SELECT *
   FROM ZeroThru9Q) AS c

"TodayPlus1KQ"라는 이름의 쿼리를 만들고(오늘 이후 날짜의 경우) 다음 구문을 수동으로 입력합니다.

SELECT date() + (a.a + (10 * b.a) + (100 * c.a)) AS MyDate
FROM
  (SELECT *
   FROM ZeroThru9Q) AS a,

  (SELECT *
   FROM ZeroThru9Q) AS b,

  (SELECT *
   FROM ZeroThru9Q) AS c;

"TodayPlus1KQ"라는 유니언 쿼리를 만듭니다(날짜 +/- 1000일).

SELECT MyDate
FROM TodayMinus1KQ
UNION
SELECT MyDate
FROM TodayPlus1KQ;

이제 쿼리를 사용할 수 있습니다.

SELECT MyDate
FROM TodayPlusMinus1KQ
WHERE MyDate BETWEEN #05/01/2014# and #05/30/2014#

절차 + 임시 테이블:

DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `days`(IN dateStart DATE, IN dateEnd DATE)
BEGIN

    CREATE TEMPORARY TABLE IF NOT EXISTS date_range (day DATE);

    WHILE dateStart <= dateEnd DO
      INSERT INTO date_range VALUES (dateStart);
      SET dateStart = DATE_ADD(dateStart, INTERVAL 1 DAY);
    END WHILE;

    SELECT * FROM date_range;
    DROP TEMPORARY TABLE IF EXISTS date_range;

END

thx Pentium 10 - stackoverflow에 참여하게 해주셨습니다 :) - 이것은 msaccess로의 포팅입니다.어떤 버전에서도 동작할 수 있다고 생각합니다.

SELECT date_value
FROM (SELECT a.espr1+(10*b.espr1)+(100*c.espr1) AS integer_value,
dateadd("d",integer_value,dateserial([start_year], [start_month], [start_day])) as date_value
FROM (select * from 
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as a,
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as b,
    (
    select top 1 "0" as espr1 from MSysObjects
    union all
    select top 1 "1" as espr2 from MSysObjects
    union all
    select top 1 "2" as espr3 from MSysObjects
    union all
    select top 1 "3" as espr4 from MSysObjects
    union all
    select top 1 "4" as espr5 from MSysObjects
    union all
    select top 1 "5" as espr6 from MSysObjects
    union all
    select top 1 "6" as espr7 from MSysObjects
    union all
    select top 1 "7" as espr8 from MSysObjects
    union all
    select top 1 "8" as espr9 from MSysObjects
    union all
    select top 1 "9" as espr9 from MSysObjects
    ) as c   
)  as d) 
WHERE date_value 
between dateserial([start_year], [start_month], [start_day]) 
and dateserial([end_year], [end_month], [end_day]);

MSysObjects를 참조했습니다.이것은 액세스에 적어도1개의 레코드가 필요하기 때문입니다.from 절에서는 적어도1개의 레코드가 있는 테이블이면 됩니다.

MariaDB > = 10.3 및 MySQL > = 8.0의 새로운 재귀(Common Table Expressions) 기능을 사용한 우아한 솔루션.

WITH RECURSIVE t as (
    select '2019-01-01' as dt
  UNION
    SELECT DATE_ADD(t.dt, INTERVAL 1 DAY) FROM t WHERE DATE_ADD(t.dt, INTERVAL 1 DAY) <= '2019-04-30'
)
select * FROM t;

위는 '2019-01-01'과 '2019-04-30' 사이의 날짜 표를 반환합니다.그것은 또한 꽤 빠르다.1000년치(약 365,000일)의 날짜를 되돌리는 데 약 400ms가 걸립니다.

이미 제시된 많은 훌륭한 답변에서 언급되었듯이(또는 적어도 언급되었듯이) 이 문제는 작업할 수 있는 일련의 숫자만 있으면 쉽게 해결할 수 있습니다.

주의: 다음은 T-SQL입니다만, 여기와 인터넷에서 이미 언급한 일반적인 개념을 특별히 구현한 것입니다.코드를 사용자가 선택한 방언으로 변환하는 것은 비교적 간단해야 합니다.

어떻게요? 다음 질문을 고려해보세요.

SELECT DATEADD(d, N, '0001-01-22')
FROM Numbers -- A table containing the numbers 0 through N
WHERE N <= 5;

위의 경우 날짜 범위는 1/22/0001 ~ 1/27/0001 이며 극히 사소한 것입니다.상기 쿼리에는 2가지 중요한 정보가 있습니다.시작일0001-01-22및 의 오프셋5이 두 가지 정보를 조합하면 확실히 종료일이 됩니다.의 날짜가 하는 것은 과 같이 수 .

  • 주어진 두 날짜(오프셋)의 차이를 쉽게 찾을 수 있습니다.

    -- Returns 125 SELECT ABS(DATEDIFF(d, '2014-08-22', '2014-12-25'))

    「」를 사용합니다.ABS()여기서 날짜 순서가 무관함을 확인합니다.

  • 제한된 숫자 집합 생성도 간단합니다.

    -- Returns the numbers 0-2 SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 FROM(SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A')

    .FROM도 있고 하는 사람도 하면알 수 .TVF 방송CTE를 사용하는 사람도 있고 숫자표를 사용하는 사람도 있습니다. 알고 있는 하는 것을 합니다.여러분도 이해하실 수 있는 가장 뛰어난 솔루션을 사용하는 것을 지지합니다.

이 두 가지 방법을 조합하면 문제가 해결됩니다.

DECLARE @date1 DATE = '9001-11-21';
DECLARE @date2 DATE = '9001-11-23';

SELECT D = DATEADD(d, N, @date1)
FROM (
    SELECT N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1
    FROM (SELECT 'A' AS S UNION ALL SELECT 'A' UNION ALL SELECT 'A') S
) Numbers
WHERE N <= ABS(DATEDIFF(d, @date1, @date2));

위의 예는 끔찍한 코드이지만 모든 것이 어떻게 결합되는지를 보여줍니다.

한층 더 즐겁다

저는 이런 일을 많이 해야 하기 때문에 논리를 두 개의 TVF로 압축했습니다.첫 번째는 숫자의 범위를 생성하고 두 번째는 이 기능을 사용하여 날짜 범위를 생성합니다.은 입력 가 되지 이고, 하지 않도록 .또한 이 계산에서 사용할 수 있는 모든 범위의 숫자를 사용하고 싶었기 때문입니다.GenerateRangeSmallInt.

다음 함수는 최대 범위인 65536일을 반환하는 데 최대 16ms의 CPU 시간이 걸립니다.

CREATE FUNCTION dbo.GenerateRangeDate (   
    @date1 DATE,   
    @date2 DATE   
)   
RETURNS TABLE
WITH SCHEMABINDING   
AS   
RETURN (
    SELECT D = DATEADD(d, N + 32768, CASE WHEN @date1 <= @date2 THEN @date1 ELSE @date2 END)
    FROM dbo.GenerateRangeSmallInt(-32768, ABS(DATEDIFF(d, @date1, @date2)) - 32768)
);

GO

CREATE FUNCTION dbo.GenerateRangeSmallInt (
    @num1 SMALLINT = -32768
  , @num2 SMALLINT = 32767
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
    WITH Numbers(N) AS (
        SELECT N FROM(VALUES
            (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 16
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 32
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 48
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 64
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 80
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 96
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 112
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 128
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 144
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 160
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 176
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 192
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 208
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 224
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 240
          , (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1), (1) -- 256
        ) V (N)
    )
    SELECT TOP(ABS(CAST(@num1 AS INT) - CAST(@num2 AS INT)) + 1)
           N = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) + CASE WHEN @num1 <= @num2 THEN @num1 ELSE @num2 END - 1
    FROM Numbers A
       , Numbers B
);

이거 먹어봐.

SELECT TO_DATE('20160210','yyyymmdd') - 1 + LEVEL AS start_day 
from DUAL
connect by level <= (TO_DATE('20160228','yyyymmdd') + 1) - TO_DATE('20160210','yyyymmdd') ;

저장된 보기로 원하는 사용자(MySQL은 보기에서 중첩된 선택 문을 지원하지 않음):

create view zero_to_nine as
    select 0 as n union all 
    select 1 union all 
    select 2 union all 
    select 3 union all 
    select 4 union all 
    select 5 union all 
    select 6 union all 
    select 7 union all 
    select 8 union all 
    select 9;

create view date_range as
    select curdate() - INTERVAL (a.n + (10 * b.n) + (100 * c.n)) DAY as date
    from zero_to_nine as a
    cross join zero_to_nine as b
    cross join zero_to_nine as c;

그러면 다음 작업을 수행할 수 있습니다.

select * from date_range

갖기 위해

date
---
2017-06-06
2017-06-05
2017-06-04
2017-06-03
2017-06-02
...

날짜 범위를 얻고자 합니다.

이 예에서는 '2010-01-20'에서 '2010-01-24' 사이의 날짜를 얻으려고 합니다.

가능한 해결책:

 select date_add('2010-01-20', interval row day) from
 ( 
    SELECT @row := @row + 1 as row FROM 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
    (select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
    (SELECT @row:=-1) r
 ) sequence
 where date_add('2010-01-20', interval row day) <= '2010-01-24'

설명.

MySQL에는 date_add 함수가 있기 때문에

select date_add('2010-01-20', interval 1 day)

너에게 줄 것이다

2010-01-21

dateiff 함수는 이 작업을 반복해야 한다는 것을 자주 알려줍니다.

select datediff('2010-01-24', '2010-01-20')

이 값은 반환됩니다

 4

날짜 범위의 날짜 목록을 가져오면 정수 시퀀스를 만드는 것으로 요약됩니다. MySQL에서 정수 시퀀스를 생성합니다.

여기서 가장 높은 평가를 받은 답변은 https://stackoverflow.com/a/2652051/1497139과 유사한 접근방식을 기반으로 하고 있습니다.

SELECT @row := @row + 1 as row FROM 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
(SELECT @row:=0) r
limit 4

그 결과적으로는

row
1.0
2.0
3.0
4.0

이제 행을 사용하여 지정된 시작 날짜에서 날짜 목록을 만들 수 있습니다.시작 날짜를 포함하려면 -1행부터 시작합니다.

select date_add('2010-01-20', interval row day) from
 ( 
    SELECT @row := @row + 1 as row FROM 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
    (SELECT @row:=-1) r
 ) sequence
 where date_add('2010-01-20', interval row day) <= '2010-01-24'

만약 당신이 며칠이상 더 필요하다면, 당신은 테이블이 필요합니다.

mysql에서 날짜 범위 생성

그리고나서,

select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;

두 날짜 필드 사이의 날짜 생성

SQL CTE 쿼리에 대해 알고 있다면 이 솔루션을 통해 문제를 해결할 수 있습니다.

여기 예가 있습니다.

우리는 한 테이블에 날짜가 있다.

테이블 이름:"테스트 날짜"

STARTDATE   ENDDATE
10/24/2012  10/24/2012
10/27/2012  10/29/2012
10/30/2012  10/30/2012

결과 요구:

STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012

솔루션:

WITH CTE AS
  (SELECT DISTINCT convert(varchar(10),StartTime, 101) AS StartTime,
                   datediff(dd,StartTime, endTime) AS diff
   FROM dbo.testdate
   UNION ALL SELECT StartTime,
                    diff - 1 AS diff
   FROM CTE
   WHERE diff<> 0)
SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime
FROM CTE

설명: CTE 재귀 쿼리 설명

  • 다음 중 하나:

    SELECT DISTINCT convert(varchar(10), StartTime, 101) AS StartTime, datediff(dd, StartTime, endTime) AS diff FROM dbo.testdate

    첫 번째 두은 "되며 "로 간주됩니다.

  • " " " " " : "

    UNION ALL SELECT StartTime, diff-1 AS diff FROM CTE WHERE diff<>0

    "은 결과가 따라서 "는 생성된 -되므로 0Union까지, 2, 1처럼 보입니다.「Start Time」의 「Start Time」의 「CTE」의 「diff」의 「decrement」의 「diff」, 「decrement - 1」의 「0」의 「Start Time」의 「Start Time」의 「Start Time」의 「CTE」의 「diff」, 「ducructure - 1」의 「0」의 「Diff」.

예를들면

STARTDATE   DIFF
10/24/2012  0
10/27/2012  0
10/27/2012  1
10/27/2012  2
10/30/2012  0

결과 사양

STARTDATE       Specification
10/24/2012  --> From Record 1
10/27/2012  --> From Record 2
10/27/2012  --> From Record 2
10/27/2012  --> From Record 2
10/30/2012  --> From Record 3
  • 질의의 세 번째 부분

    SELECT DISTINCT DateAdd(dd,diff, StartTime) AS StartTime FROM CTE

    day "diff는 다음과 .

결과

STARTDATE
10/24/2012
10/27/2012
10/28/2012
10/29/2012
10/30/2012

수용된 답변보다 짧은 답변, 동일한 아이디어:

(SELECT TRIM('2016-01-05' + INTERVAL a + b DAY) date
FROM
(SELECT 0 a UNION SELECT 1 a UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
UNION SELECT 8 UNION SELECT 9 ) d,
(SELECT 0 b UNION SELECT 10 UNION SELECT 20
UNION SELECT 30 UNION SELECT 40) m
WHERE '2016-01-05' + INTERVAL a + b DAY  <=  '2016-01-21')

mysql 8.0.1 및 mariadb 10.2.2에 대한 재귀적 공통 테이블 식을 사용하는 또 하나의 솔루션:

with recursive dates as (
    select '2010-01-20' as date
    union all
    select date + interval 1 day from dates where date < '2010-01-24'
)
select * from dates;

이러한 날짜를 즉시 생성하는 것이 좋습니다.그러나 저는 이 작업을 매우 넓은 범위로 수행하는 것이 불편하다고 느꼈기 때문에 다음과 같은 해결책을 제시했습니다.

  1. 날짜 계산에 사용되는 숫자를 포함하는 "DatesNumbers" 테이블을 만들었습니다.
CREATE TABLE DatesNumbers (
    i MEDIUMINT NOT NULL,
    PRIMARY KEY (i)
)
COMMENT='Used by Dates view'
;
  1. 위의 기술을 사용하여 표에 -599999 ~40000의 숫자를 입력.이 범위는 599999일(~164년) 후부터 40,000일(109년) 후까지입니다.
INSERT INTO DatesNumbers
SELECT 
    a.i + (10 * b.i) + (100 * c.i) + (1000 * d.i) + (10000 * e.i) - 59999 AS i
FROM 
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d,
  (SELECT 0 AS i UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS e
;
  1. "날짜" 보기를 만들었습니다.
SELECT
      i,
      CURRENT_DATE() + INTERVAL i DAY AS Date
FROM
    DatesNumbers

바로 그겁니다.

  • (+) 읽기 쉬운 쿼리
  • (+ 플라이 넘버 세대에서는 없음)
  • (+) 과거와 미래의 날짜를 표시하며, 이 게시물에서는 UNION이 표시되지 않습니다.
  • "에만" 는 (+) "과거에만" 또는 "과거에만" 또는 "미래에만"을 사용하여 수 WHERE i < 0 ★★★★★★★★★★★★★★★★★」WHERE i > 0(PK)
  • (-) 테이블과 뷰가 사용됩니다.

AWS MySQL에서 작동하는 보다 일반적인 답변입니다.

select datetable.Date
from (
    select date_format(adddate(now(),-(a.a + (10 * b.a) + (100 * c.a))),'%Y-%m-%d') AS Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b

    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4
     union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) datetable
where datetable.Date between now() - INTERVAL 14 Day and Now()
order by datetable.Date DESC

알겠습니다.http://www.devshed.com/c/a/MySQL/Delving-Deeper-into-MySQL-50/ 를 사용해 보세요.
http://dev.mysql.com/doc/refman/5.0/en/loop-statement.htmlhttpdev.mysql.com/doc/refman/5.0/en/.html
http://www.roseindia.net/sql/mysql-example/mysql-loop.shtmlhttpwww.roseindia.net/sql//mysql-loop.shtml

이를 사용하여 임시 테이블을 생성한 다음 임시 테이블에서 *를 선택합니다.또는 결과를 한 번에 하나씩 출력합니다.
당신이 말하고 싶은 것은 SELECT 문으로는 할 없지만 MySQL 특유의 문으로는 할 수 있을 입니다.
커서가 필요할 수도 있습니다.http://dev.mysql.com/doc/refman/5.0/en/cursors.html

Oracle의 경우 솔루션은 다음과 같습니다.

select trunc(sysdate-dayincrement, 'DD') 
  from dual, (select level as dayincrement 
                from dual connect by level <= 30)

sysdate를 특정 날짜로 변경할 수 있으며 레벨 번호를 변경하여 더 많은 날짜를 지정할 수 있습니다.

두 날짜 사이의 날짜 목록을 원하는 경우:

create table #dates ([date] smalldatetime)
while @since < @to
begin
     insert into #dates(dateadd(day,1,@since))
     set @since = dateadd(day,1,@since)
end
select [date] from #dates

* 여기 주소: http://sqlfiddle.com/ #!6/9eecb/3469

set language  'SPANISH'
DECLARE @table table(fechaDesde datetime , fechaHasta datetime ) 
INSERT @table VALUES('20151231' , '20161231');
WITH x AS 
    (
        SELECT   DATEADD( m , 1 ,fechaDesde ) as fecha  FROM @table
        UNION ALL
        SELECT  DATEADD( m , 1 ,fecha )
        FROM @table t INNER JOIN x ON  DATEADD( m , 1 ,x.fecha ) <= t.fechaHasta
    )
SELECT LEFT( CONVERT( VARCHAR, fecha , 112 ) , 6 ) as Periodo_Id 
,DATEPART ( dd, DATEADD(dd,-(DAY(fecha)-1),fecha)) Num_Dia_Inicio
,DATEADD(dd,-(DAY(fecha)-1),fecha) Fecha_Inicio
,DATEPART ( mm , fecha ) Mes_Id
,DATEPART ( yy , fecha ) Anio
,DATEPART ( dd, DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha))) Num_Dia_Fin
,DATEADD(dd,-(DAY(DATEADD(mm,1,fecha))),DATEADD(mm,1,fecha)) ultimoDia
,datename(MONTH, fecha) mes
,'Q' + convert(varchar(10),  DATEPART(QUARTER, fecha)) Trimestre_Name
FROM x 
OPTION(MAXRECURSION 0)
DELIMITER $$
CREATE PROCEDURE GenerateRangeDates(IN dateStart DATE, IN dateEnd DATE)
BEGIN

    CREATE TEMPORARY TABLE IF NOT EXISTS dates (day DATE);

    loopDate: LOOP
        INSERT INTO dates(day) VALUES (dateStart); 
        SET dateStart = DATE_ADD(dateStart, INTERVAL 1 DAY);

        IF dateStart <= dateEnd 
            THEN ITERATE loopDate;
            ELSE LEAVE loopDate;
        END IF;
    END LOOP loopDate;

    SELECT day FROM dates;
    DROP TEMPORARY TABLE IF EXISTS dates;

END 
$$

-- Call procedure
call GenerateRangeDates( 
        now() - INTERVAL 40 DAY,
        now()
    );

Red Filters 상위 솔루션의 SQLite 버전

select d.Date
from (
    select 
    date(julianday('2010-01-20') + (a.a + (10 * b.a) + (100 * c.a))) as Date
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) d
where 
d.Date between '2010-01-20' and '2010-01-24' 
order by d.Date

평일 및 Powerpivot 날짜 테이블에 대한 커스텀 홀리데이 테이블 Microsoft MSQL 2012에 참여함으로써 개선되었습니다.https://gist.github.com/josy1024/cb1487d66d9e0ccbd420bc4a23b6e90e

with [dates] as (
    select convert(datetime, '2016-01-01') as [date] --start
    union all
    select dateadd(day, 1, [date])
    from [dates]
    where [date] < '2018-01-01' --end
)
select [date]
, DATEPART (dw,[date]) as Wochentag
, (select holidayname from holidaytable 
where holidaytable.hdate = [date]) 
as Feiertag
from [dates]
where [date] between '2016-01-01' and '2016-31-12'
option (maxrecursion 0)
WITH
  Digits AS (SELECT 0 D UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9),
  Dates AS (SELECT adddate('1970-01-01',t4.d*10000 + t3.d*1000 + t2.d*100 + t1.d*10 +t0.d) AS date FROM Digits AS t0, Digits AS t1, Digits AS t2, Digits AS t3, Digits AS t4)
SELECT * FROM Dates WHERE date BETWEEN '2017-01-01' AND '2017-12-31'

요일과 다른 시간 맵을 사용하여 달력 테이블을 작성하는 프로시저를 작성할 수도 있습니다.각 분기별 테이블을 원하시면

예.

2019-01-22 08:45:00
2019-01-22 09:00:00
2019-01-22 09:15:00
2019-01-22 09:30:00
2019-01-22 09:45:00
2019-01-22 10:00:00

사용할 수 있습니다.

CREATE DEFINER=`root`@`localhost` PROCEDURE `generate_calendar_table`()
BEGIN

select unix_timestamp('2014-01-01 00:00:00') into @startts;
select unix_timestamp('2025-01-01 00:00:00') into @endts;

if ( @startts < @endts ) then

    DROP TEMPORARY TABLE IF EXISTS calendar_table_tmp;

    CREATE TEMPORARY TABLE calendar_table_tmp (ts int, dt datetime); 

    WHILE ( @startts < @endts)
        DO 
        SET @startts = @startts + 900;
        INSERT calendar_table_tmp VALUES (@startts, from_unixtime(@startts));
    END WHILE;

END if;

END


그런 다음 이 모든 것을 통해

select ts, dt from calendar_table_tmp;

ts도 얻을 수 있습니다.

'1548143100', '2019-01-22 08:45:00'
'1548144000', '2019-01-22 09:00:00'
'1548144900', '2019-01-22 09:15:00'
'1548145800', '2019-01-22 09:30:00'
'1548146700', '2019-01-22 09:45:00'
'1548147600', '2019-01-22 10:00:00'

여기서 다음과 같은 다른 정보를 추가할 수 있습니다.

select ts, dt, weekday(dt) as wd from calendar_table_tmp;

또는 create table 문을 사용하여 실제 테이블을 만듭니다.

D'Arcy Rittich의 답변과 비슷하지만 SQL SERVER의 경우

;WITH t AS
(
    SELECT n = a.n * 10 + b.n * 100 + c.n
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) a(n)
    CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) b(n)
    CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) c(n)
)
SELECT DATEADD(DAY, t.n, '2022-01-01')
FROM t
ORDER BY T.n;

또는 CTE 없음

SELECT DATEADD(DAY, nums.n, '2022-01-01') AS d FROM (
    SELECT n = a.n * 10 + b.n * 100 + c.n
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) a(n)
    CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) b(n)
    CROSS JOIN (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)) c(n)
) nums
order by d

언급URL : https://stackoverflow.com/questions/2157282/generate-days-from-date-range

반응형