从date范围中生成date

我想运行一个查询

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

此解决scheme不使用循环,过程或临时表 。 子查询会生成最近一千天的date,并且可以按照您的意愿延伸到前后。

 select a.Date from ( select curdate() - INTERVAL (aa + (10 * ba) + (100 * ca)) 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 ) 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 

性能注意事项

在这里testing一下 ,性能出奇的好: 上面的查询需要0.0009秒。

如果我们扩展子查询来生成约。 100,000个数字(因此约274年的date),它运行在0.0458秒。

顺便说一句,这是一个非常便携的技术,与大多数数据库一起工作,只需稍作调整。

返回1000天的SQL小提琴示例

这是使用视图的另一个变体:

 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 

更新

值得注意的是,您只能从当前date开始生成过去的date 。 如果你想生成任何types的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”或附近的语法错误)。

在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) 

使用recursion通用expression式(CTE),您可以生成date列表,然后从中进行select。 显然,你通常不想创build300万个date,所以这只是说明了可能性。 您可以简单地限制CTE内的date范围,并使用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上,生成所有可能date的CTE列表1:08。 生成一百年不到一秒钟。

没有循环/游标的旧式解决scheme是创build一个NUMBERS表,该表有一个Integer列,其值从1开始。

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

您需要填充足够的logging以满足您的需求:

 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' 

绝对的低技术解决scheme将是:

 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 

你会用它做什么?


生成date或数字列表以便左键join。 你会这样做,以便查看数据中有什么空白,因为你是左连接到一个序列数据列表 – 空值将使它明显的地方存在差距。

MSSQL查询

 select datetable.Date from ( select DATEADD(day,-(aa + (10 * ba) + (100 * ca)),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 

对于Access 2010 – 需要多个步骤; 我遵循上面发布的相同模式,但认为我可以帮助Access中的某个人。 为我工作很好,我不必保留一个种子的date表。

创build一个名为DUAL的表(类似于Oracle DUAL表的工作方式)

  • ID(自动编号)
  • DummyColumn(文本)
  • 添加一行值(1,“DummyRow”)

创build一个名为“ZeroThru9Q”的查询; 手动input以下语法:

 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; 

创build一个名为“TodayMinus1KQ”的查询(用于今天之前的date); 手动input以下语法:

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

创build一个名为“TodayPlus1KQ”的查询(用于今天之后的date); 手动input以下语法:

 SELECT date() + (aa + (10 * ba) + (100 * ca)) AS MyDate FROM (SELECT * FROM ZeroThru9Q) AS a, (SELECT * FROM ZeroThru9Q) AS b, (SELECT * FROM ZeroThru9Q) AS c; 

创build名为“TodayPlusMinus1KQ”的联合查询(date为+/- 1000天):

 SELECT MyDate FROM TodayMinus1KQ UNION SELECT MyDate FROM TodayPlus1KQ; 

现在你可以使用查询:

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

thx奔腾10 – 你让我joinstackoverflow 🙂 – 这是我的移植到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只是因为访问需要一个表countin'至less有一条logging,在一个from子句 – 任何至less有一个logging的表会做。

如果你将需要更多的几天,你需要一张桌子。

在mysql中创build一个date范围

然后,

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

程序+临时表:

 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 

比被接受的答案更短,同样的想法:

 (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') 

尝试这个。

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

好吧..试试这个: 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

对于Oracle,我的解决scheme是:

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

系统date可以更改为特定的date和级别号码可以更改以提供更多的date。

正如已经提到的许多精彩的答案所说的(或者至less是暗示的),一旦你有一组数字来处理这个问题就很容易解决。

注意:以下是T-SQL,但这仅仅是我在这里和在networking上已经提到的一般概念的具体实现。 将代码转换为您select的方言应该相对简单。

怎么样? 考虑这个查询:

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

以上产生date范围1/22/0001 – 1/27/0001,是非常平凡的。 上述查询中有2个关键信息: 开始date 0001-01-22偏移量 5 。 如果我们结合这两个信息,那么我们显然有我们的结束date。 因此,给定两个date,产生一个范围可以被分解如下:

  • find两个给定date(偏移量)之间的差异,轻松:

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

    这里使用ABS()确保date顺序不相关。

  • 生成一个有限的数字,也很容易:

    -- 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这里select什么。 我们只需要一个集合来处理,以便计算它的行​​数。 我个人使用TVF,有的使用CTE,有的使用数字表,而是使用了。 我主张使用您也了解的性能最高的解决scheme。

结合这两种方法将解决我们的问题:

 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中。 第一个生成一个数字范围,第二个使用这个function来生成一个date范围。 math是确保input顺序无关紧要,因为我想使用GenerateRangeSmallInt可用的全部数字。

以下函数需要16ms的CPU时间才能返回65536个date的最大范围。

 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 ); 

如果你想要两个date之间的date列表:

 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

在两个date字段之间生成date

如果你知道SQL CTE查询,那么这个解决scheme将帮助你解决你的问题

这里是例子

我们有一张桌子的date

表名称:“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 

说明:CTErecursion查询说明

  • 查询的第一部分:

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

    说明:firstcolumn是“startdate”,第二列是开始date和结束date的差异,将被视为“差异”列

  • 查询的第二部分:

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

    说明:Union all将inheritance上述查询的结果,直到结果变为null,所以“StartTime”结果是从生成的CTE查询inheritance的,并且从diff减去-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 
 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() ); 

SQLite版本的RedFilters顶级解决scheme

 select d.Date from ( select date(julianday('2010-01-20') + (aa + (10 * ba) + (100 * ca))) 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 

改进工作日join自定义假期表 microsoft MSSQL 2012 for powerpivotdate表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) 

对于任何想要这个作为保存视图的人(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 (an + (10 * bn) + (100 * cn)) 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 ... 

在飞行中生成这些date是一个好主意。 不过,我觉得自己并不舒服,所以我最终select了以下解决scheme:

  1. 创build了一个表格“DatesNumbers”,它将包含用于date计算的数字:

CREATE TABLE DatesNumbers ( i MEDIUMINT NOT NULL, PRIMARY KEY (i) ) COMMENT='Used by Dates view' ;

  1. 使用上述技术填充表格,数字从-59999到40000.这个范围将使我的date从59999天(〜164年)到40000天(109年)

INSERT INTO DatesNumbers SELECT ai + (10 * bi) + (100 * ci) + (1000 * di) + (10000 * ei) - 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. 创build一个视图“date”:

SELECT i , CURRENT_DATE() + INTERVAL i DAY AS Date FROM DatesNumbers

而已。

  • (+)易于阅读的查询
  • (+)没有在飞行数字世代
  • (+)提供过去和未来的date,因此在这个post中没有任何联盟。
  • (+)“过去只有”或“将来只有”date可以使用WHERE i < 0WHERE i > 0 (PK)
  • ( – )使用“临时”表和视图
Interesting Posts