获取两个日期之间的日期列表
使用标准 mysql 函数有一种方法可以编写一个查询,该查询将返回两个日期之间的天数列表。
例如,给定 2009-01-01 和 2009-01-13 它将返回一个包含以下值的一列表:
2009-01-01
2009-01-02
2009-01-03
2009-01-04
2009-01-05
2009-01-06
2009-01-07
2009-01-08
2009-01-09
2009-01-10
2009-01-11
2009-01-12
2009-01-13
编辑:看来我还不清楚。 我想生成这个列表。 我将值存储在数据库中(按日期时间),但希望将它们聚合在左外连接上到上面的日期列表(我预计该连接的右侧部分为空,并且将处理此问题) )。
Using standard mysql functions is there a way to write a query that will return a list of days between two dates.
eg given 2009-01-01 and 2009-01-13 it would return a one column table with the values:
2009-01-01
2009-01-02
2009-01-03
2009-01-04
2009-01-05
2009-01-06
2009-01-07
2009-01-08
2009-01-09
2009-01-10
2009-01-11
2009-01-12
2009-01-13
Edit: It appears I have not been clear. I want to GENERATE this list. I have values stored in the database (by datetime) but want them to be aggregated on a left outer join to a list of dates as above (I am expecting null from the right side of some of this join for some days and will handle this).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(24)
对于 Access(或任何 SQL 语言)
创建一个包含 2 个字段的表,我们将此表称为
tempRunDates
:--字段
fromDate
和toDate
--然后仅插入 1 条记录,该记录具有开始日期和结束日期。
创建另一个表:
Time_Day_Ref
--将日期列表(在 Excel 中制作列表很容易)导入到此表中。
-- 在我的例子中,字段名称是
Greg_Dt
,代表公历日期--我的列表是从 2009 年 1 月 1 日到 2020 年 1 月 1 日。
运行查询:
简单!
For Access (or any SQL language)
Create one table that has 2 fields, we'll call this table
tempRunDates
:--Fields
fromDate
andtoDate
--Then insert only 1 record, that has the start date and the end date.
Create another table:
Time_Day_Ref
--Import a list of dates (make list in excel is easy) into this table.
--The field name in my case is
Greg_Dt
, for Gregorian Date--I made my list from jan 1 2009 through jan 1 2020.
Run the query:
Easy!
你可以用这个
You can use this
通常,人们会使用您通常为此目的而保留的辅助数字表,并对此进行一些变化:
我已经看到了表值函数的变化等。
您还可以保留一个永久的日期列表。 我们的数据仓库中有它以及一天中的时间列表。
Typically one would use an auxiliary numbers table you usually keep around for just this purpose with some variation on this:
I've seen variations with table-valued functions, etc.
You can also keep a permanent list of dates. We have that in our data warehouse as well as a list of times of day.
我们在 HRMS 系统中使用了它,您会发现它很有用
We used this in our HRMS System you will find it useful
该解决方案适用于 MySQL 5.0
创建一个表 -
mytable
。架构并不重要。 重要的是其中的行数。
因此,您可以仅保留一列 INT 类型的列,其中包含 10 行,值 - 1 到 10。
SQL:
限制:
上述查询返回的最大日期数将为
(mytable 中的行数)*(mytable 中的行数) = 10*10 = 100。
您可以通过更改 sql 中的表单部分来增加此范围:
来自 mytable x、mytable y、mytable z
因此,范围为
10*10*10 =1000
等等。This solution is working with MySQL 5.0
Create a table -
mytable
.The schema does not material. What matters is the number of rows in it.
So, you can keep just one column of type INT with 10 rows, values - 1 to 10.
SQL:
Limitation:
The maximum number of dates returned by above query will be
(rows in mytable)*(rows in mytable) = 10*10 = 100.
You can increase this range by changing form part in sql:
from mytable x,mytable y, mytable z
So, the range be
10*10*10 =1000
and so on.没有临时表 | 无需手续 | 无函数
下面的示例显示一个月的日期范围 - 从同月的第一天到最后一天。 您可以通过使用 @e `INTERVAL` 值来更改日期范围。
结果:
No temp table | No procedure | No functions
The example below present one month date range - from day 1 to the last day of the same month. You can change the date range by playing with @e `INTERVAL` values.
Result:
我会使用与此类似的内容:
然后
@HOLDER
变量表保存这两个日期之间按天递增的所有日期,准备好加入您心中的内容。I would use something similar to this:
Then the
@HOLDER
Variable table holds all the dates incremented by day between those two dates, ready to join at your hearts content.我已经为此奋斗了很长一段时间。 由于这是我搜索解决方案时在 Google 上的第一次点击,因此让我发布到目前为止我所得到的结果。
将
[yourTable]
替换为数据库中的表。 技巧是您选择的表中的行数必须 >= 您想要返回的日期数。 我尝试使用表占位符 DUAL,但它只会返回一行。I've been fighting with this for quite a while. Since this is the first hit on Google when I searched for the solution, let me post where I've gotten so far.
Replace
[yourTable]
with a table from your database. The trick is that the number of rows in the table you select must be >= the number of dates you want to be returned. I tried using the table placeholder DUAL, but it would only return one single row.在这里,首先在当前结束日期上添加一天,即 2011-02-28 00:00:00,然后减去一秒以使结束日期为 2011-02-27 23:59:59。 通过这样做,您可以获得给定间隔之间的所有日期。
输出:
2011/02/25
2011/02/26
2011/02/27
Here, first add a day to the current endDate, it will be 2011-02-28 00:00:00, then you subtract one second to make the end date 2011-02-27 23:59:59. By doing this, you can get all the dates between the given intervals.
output:
2011/02/25
2011/02/26
2011/02/27
此过程将插入从年初至今的所有日期,只需替换“开始”和“结束”的日期,就可以开始了!
this procedure will insert all dates from the beginning of the year till now, just substitue the days of the "start" and "end", and you are ready to go!
我需要一个包含两个日期之间所有月份的列表以进行统计。 这两个日期是订阅的开始日期和结束日期。
因此列表显示所有月份以及每月的订阅量。
MYSQL
I needed a list with all months between 2 dates for statistics. The 2 dates are the start and enddate from a subscription.
So the list shows all months and the amount of subscriptions per month.
MYSQL
无函数,无过程
UNIONS 定义可供选择的可用日期的长度和范围。 因此,请务必确保其记录足够多。
基于这篇文章< br>
经过测试并按预期工作
No Function, No Procedures
UNIONS define the length and range of available dates to elect from. So always make sure to make it log enough.
Based on this article
Tested and working as expected
改进@brad答案,我使用了带有光标的CTE:
Improving on @brad answer, I used a CTE with a cursor:
便携式解决方案
Portable solution
通过递归我确实喜欢这样。
With recursive i did like this.
创建一个带有两个参数 a_begin 和 a_end 的存储过程。
在其中创建一个名为 t 的临时表,声明变量 d,将 a_begin 分配给 d,然后运行
WHILE
循环将 dINSERT
插入 t 并调用ADDDATE< /code> 函数增加值 d。 最后
SELECT * FROM t
。Create a stored procedure which takes two parameters a_begin and a_end.
Create a temporary table within it called t, declare a variable d, assign a_begin to d, and run a
WHILE
loopINSERT
ing d into t and callingADDDATE
function to increment the value d. FinallySELECT * FROM t
.我正在使用
服务器版本:5.7.11-log MySQL Community Server (GPL)
现在我们将通过简单的方式解决这个问题。
我现在创建了一个名为“datetable”的表
,我们将看到其中插入的记录。
这里我们的查询是获取两个日期内的记录而不是这些日期。
希望这对很多人有帮助。
I am using
Server version: 5.7.11-log MySQL Community Server (GPL)
Now we will solve this in a simple way.
I have created a table named "datetable"
now, wee will see the inserted records within.
and here our query to fetch records within two dates rather than those dates.
hope this would help many ones.
我们在 BIRT 报告中也遇到了类似的问题,因为我们想要报告那些没有数据的日子。 由于没有这些日期的条目,对我们来说最简单的解决方案是创建一个存储所有日期的简单表,并使用它来获取范围或连接以获取该日期的零值。
我们有一项每月运行一次的工作,以确保该表在未来 5 年内被填充。 表是这样创建的:
毫无疑问,有一些神奇而棘手的方法可以使用不同的 DBMS 来做到这一点,但我们总是选择最简单的解决方案。 该表的存储要求很小,并且使查询变得更加简单和便携。 从性能的角度来看,这种解决方案几乎总是更好,因为它不需要对数据进行每行计算。
另一个选项(我们之前使用过这个)是确保表中每个日期都有一个条目。 我们定期扫描表格并为不存在的日期和/或时间添加零条目。 对于您的情况,这可能不是一个选项,这取决于存储的数据。
如果您真的认为填充
all_dates
表很麻烦,那么可以使用存储过程来返回包含这些日期的数据集。 这几乎肯定会更慢,因为您必须在每次调用时计算范围,而不仅仅是从表中提取预先计算的数据。但是,说实话,您可以将表填充 1000 年而不会出现任何严重的数据存储问题 - 365,000 个 16 字节(例如)日期加上复制日期的索引加上 20% 的安全开销,我粗略估计为大约 14M [365,000 * 16 * 2 * 1.2 = 14,016,000 字节]),在事物方案中是一个很小的表。
We had a similar problem with BIRT reports in that we wanted to report on those days that had no data. Since there were no entries for those dates, the easiest solution for us was to create a simple table that stored all dates and use that to get ranges or join to get zero values for that date.
We have a job that runs every month to ensure that the table is populated 5 years out into the future. The table is created thus:
No doubt there are magical tricky ways to do this with different DBMS' but we always opt for the simplest solution. The storage requirements for the table are minimal and it makes the queries so much simpler and portable. This sort of solution is almost always better from a performance point-of-view since it doesn't require per-row calculations on the data.
The other option (and we've used this before) is to ensure there's an entry in the table for every date. We swept the table periodically and added zero entries for dates and/or times that didn't exist. This may not be an option in your case, it depends on the data stored.
If you really think it's a hassle to keep the
all_dates
table populated, a stored procedure is the way to go which will return a dataset containing those dates. This will almost certainly be slower since you have to calculate the range every time it's called rather than just pulling pre-calculated data from a table.But, to be honest, you could populate the table out for 1000 years without any serious data storage problems - 365,000 16-byte (for example) dates plus an index duplicating the date plus 20% overhead for safety, I'd roughly estimate at about 14M [365,000 * 16 * 2 * 1.2 = 14,016,000 bytes]), a minuscule table in the scheme of things.
在 MariaDB >= 10.3 和 MySQL >= 8.0 中使用新的递归(通用表表达式)功能的优雅解决方案。
上面的代码返回
2019-01-01
和2019-04-30
之间的日期表。Elegant solution using new recursive (Common Table Expressions) functionality in MariaDB >= 10.3 and MySQL >= 8.0.
The above returns a table of dates between
2019-01-01
and2019-04-30
.借用 这个答案,您可以设置一个包含 0 到 9 的表格,并使用它来生成日期列表。
这将允许您生成最多包含 1000 个日期的列表。 如果需要更大的范围,可以向内部查询添加另一个交叉联接。
Borrowing an idea from this answer, you can set up a table with 0 through 9 and use that to generate your list of dates.
This will allow you to generate a list of up to 1000 dates. If you need to go larger, you can add another cross join to the inner query.
我将使用此存储过程在名为 time_intervals 的临时表中生成所需的时间间隔,然后将数据表与临时 time_intervals 表连接并聚合。
该过程可以生成您在其中指定的所有不同类型的间隔:
这篇文章,我为 SQL Server 构建了一个类似的函数。
I would use this stored procedure to generate the intervals you need into the temp table named time_intervals, then JOIN and aggregate your data table with the temp time_intervals table.
The procedure can generate intervals of all the different types you see specified in it:
Similar example data scenario at the bottom of this post, where I built a similar function for SQL Server.
对于 MSSQL,您可以使用它。 这是非常快的。
您可以将其包装在表值函数或存储过程中,并将开始日期和结束日期解析为变量。
编辑2021/01(V博士):
我喜欢这个解决方案并使其适用于 mySQL V8。 这是代码,将其包装到一个过程中:
For MSSQL you can use this. It is VERY quick.
You can wrap this up in a table valued function or stored proc and parse in the start and end dates as variables.
Edit 2021/01 (Dr. V):
I liked this solution and made it work for mySQL V8. Here is the code, wrapping it into a procedure:
您可以像这样使用 MySQL 的用户变量:
@num是-1,因为你第一次使用它时添加了它。 另外,您不能使用“HAVING date_sequence”,因为这会使用户变量每行增加两次。
You can use MySQL's user variables like this:
@num is -1 because you add to it the first time you use it. Also, you can't use "HAVING date_sequence" because that makes the user variable increment twice for each row.