같은 쿼리를 실행하고 싶습니다
select ... as days where `date` is between '2010-01-20' and '2010-01-24'
그리고 다음과 같은 데이터를 반환하십시오.
일 ---------- 2010-01-20 2010-01-21 2010-01-22 2010-01-23 2010-01-24
insert into table select ... as days date between '' and ''
같은 쿼리를 실행하고 싶습니다
select ... as days where `date` is between '2010-01-20' and '2010-01-24'
그리고 다음과 같은 데이터를 반환하십시오.
일 ---------- 2010-01-20 2010-01-21 2010-01-22 2010-01-23 2010-01-24
insert into table select ... as days date between '' and ''
답변:
이 솔루션은 루프, 프로 시저 또는 임시 테이블을 사용 하지 않습니다 . 하위 쿼리는 지난 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 초가 걸립니다.
하위 쿼리를 확장하여 약. 100,000 개의 숫자 (따라서 약 274 년의 날짜)는 0.0458 초로 실행됩니다.
또한 이것은 약간의 조정만으로 대부분의 데이터베이스에서 작동하는 매우 이식성이 뛰어난 기술입니다.
UNION
에 UNION ALL
존재하지 않는 것을 제거하기 위해 중복 검사 그것의 시간 낭비 -. 그럼에도 불구하고 너무 복잡합니다. UNION을 사용하여 결과 집합을 구성하려는 경우 날짜를 지정하고 완료하는 것이 어떻습니까?
뷰를 사용하는 또 다른 변형은 다음과 같습니다.
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;
dates
위에서 언급 한 첫 번째보기 는 현재 날짜부터 시작하는 날짜를 계산 하기 때문에 미래에 설정된 날짜를 검색 할 수 없기 때문입니다. @RedFilter의 답변에는 동일한 디자인 결함이 있습니다. 그래도 답변에 해결 방법을 추가했습니다.
UNION
단일 SQL 문에서 모든 절이 이상하게 보입니다.
수락 된 답변이 PostgreSQL에서 작동하지 않았습니다 ( "a"또는 그 근처의 구문 오류).
PostgreSQL에서이를 수행하는 방법은 다음과 같은 generate_series
기능 을 사용하는 것입니다.
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)을 사용하여 날짜 목록을 생성 한 후 선택할 수 있습니다. 분명히 당신은 일반적으로 3 백만 날짜를 만들고 싶지 않을 것이므로 이것은 가능성을 보여줍니다. 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이 걸렸습니다. 백 년을 생성하는 데 1 초도 걸리지 않았습니다.
MSSQL 쿼리
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
루프 / 커서없이이 작업을 수행하는 구식 솔루션은 NUMBERS
값이 1부터 시작하는 단일 정수 열이있는 테이블 을 만드는 것 입니다.
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
왼쪽에 참여하기 위해 날짜 또는 숫자 목록을 생성합니다. 시퀀셜 데이터 목록에 왼쪽으로 참여하기 때문에 데이터에 차이가있는 곳을 확인하기 위해이 작업을 수행합니다. null 값은 간격이 존재하는 곳을 분명하게합니다.
DUAL
테이블은 FROM
절 에서 독립 테이블로 사용하기 위해 Oracle 및 MySQL에서 지원됩니다 . 존재하지 않으며 값을 선택하면 값이 무엇이든 반환됩니다. SELECT 쿼리에는 FROM
적어도 하나의 테이블을 지정 하는 절이 필요하기 때문에이 아이디어는 독립형을 유지하는 것이 었습니다 .
Access 2010의 경우 여러 단계가 필요합니다. 위에 게시 된 것과 같은 패턴을 따랐지만 Access의 누군가를 도울 수 있다고 생각했습니다. 나를 위해 훌륭하게 일 했으므로 씨앗 날짜 테이블을 유지할 필요가 없었습니다.
DUAL이라는 테이블을 만듭니다 (Oracle DUAL 테이블의 작동 방식과 유사)
"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;
"TodayPlusMinus1KQ"라는 이름의 통합 쿼리를 만듭니다 (날짜 +/- 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 Pentium10-당신이 나를 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]);
참조 MSysObject는 from 절에서 적어도 하나의 레코드가 필요하므로 '액세스에 테이블 카운트가 필요합니다.'레코드가 1 개 이상인 모든 테이블이 수행합니다.
이미 주어진 많은 훌륭한 답변들에서 언급했듯이 (또는 적어도 언급 된 바와 같이),이 문제는 일련의 숫자를 가지고 있으면 쉽게 해결됩니다.
참고 : 다음은 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') ;
날짜 범위를 얻으려고합니다.
귀하의 예에서 '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
DATEDIFF의 기능은이를 반복해야 할 것 자주 알려 것
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'
며칠 이상이 필요할 경우 테이블이 필요합니다.
그때,
select from days.day, count(mytable.field) as fields from days left join mytable on day=date where date between x and y;
여기에 예가 있습니다
우리는 하나의 테이블에 날짜가 있습니다
테이블 이름 :“testdate”
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
설명 : firstcolumn은 "startdate"이고 두 번째 열은 시작 날짜와 종료 날짜의 차이 (일)이며 "diff"열로 간주됩니다.
쿼리의 두 번째 부분 :
UNION ALL SELECT StartTime, diff-1 AS diff FROM CTE WHERE diff<>0
설명 : Union all은 결과가 null이 될 때까지 위 쿼리의 결과를 상속하므로 "StartTime"결과는 생성 된 CTE 쿼리에서 상속되며 diff, reduce-1에서 상속되므로 3, 2 및 1과 같습니다. 0까지
예를 들어
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
"startdate"에 "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은 뷰에서 중첩 된 select 문을 지원하지 않습니다) :
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
...
MariaDB> = 10.3 및 MySQL> = 8.0의 새로운 재귀 (공통 테이블 표현식) 기능을 사용하는 우아한 솔루션.
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가 걸립니다.
이 날짜를 즉석에서 생성하는 것이 좋습니다. 그러나 꽤 넓은 범위 에서이 작업을 수행하는 것이 편하지 않기 때문에 다음 솔루션으로 끝났습니다.
CREATE TABLE DatesNumbers (
i MEDIUMINT NOT NULL,
PRIMARY KEY (i)
)
COMMENT='Used by Dates view'
;
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
;
SELECT
i,
CURRENT_DATE() + INTERVAL i DAY AS Date
FROM
DatesNumbers
그게 다야.
WHERE i < 0
또는 WHERE i > 0
(PK)를 사용하여 필터링 할 수 있습니다.좋습니다. 이것을 시도하십시오 :
http://www.devshed.com/c/a/MySQL/Delving-Deeper-into-MySQL-50/
http://dev.mysql.com/doc/refman/5.0/en/ loop-statement.html
http://www.roseindia.net/sql/mysql-example/mysql-loop.shtml
이를 사용하여 임시 테이블을 생성 한 다음 임시 테이블에서 select *를 수행하십시오. 또는 한 번에 하나씩 결과를 출력하십시오.
당신이하고 싶은 말은 SELECT 문 으로 할 수 없지만 MySQL과 관련된 것들로 할 수 있습니다.
그런 다음 커서가 필요할 수도 있습니다. http://dev.mysql.com/doc/refman/5.0/en/cursors.html
두 날짜 사이의 날짜 목록을 원하는 경우 :
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()
);
RedFilters 최고 솔루션의 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
평일 개선 사용자 지정 휴일 테이블에 합류 마이크로 소프트 MSSQL 의 PowerPivot 날짜 테이블에 대한 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 문 으로 실제 테이블을 만듭니다.
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
재귀 공통 테이블 표현식을 사용하는 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;