【问题标题】:SQL Query which returns a table where each row represents a date in a given rangeSQL 查询返回一个表,其中每一行代表给定范围内的日期
【发布时间】:2026-01-16 13:35:01
【问题描述】:

是否可以创建一个 SQL 查询,该查询将返回一列,其中包含给定日期范围内的日期(例如,从去年到今天的所有日期)。例如

dat
----
2007-10-01
2007-10-02
2007-10-03
2007-10-04
...

我想知道这是否可以替代创建一个包含所有预先计算的日期的表格。

更新:我需要 MYSQL 的解决方案。在这种情况下,我对任何其他数据库都不感兴趣。

【问题讨论】:

  • 我们不要把它变成 IRC。请至少接受这些有见地的答案之一。我不在乎它是不是我的;只接受一个。
  • smink 的建议应该很好地转化为 MySQL 的存储过程。试试看。

标签: sql mysql


【解决方案1】:

我现在手头没有 MySQL 实例,但看看这是否可行。根据需要替换参数。我为示例硬编码了 2007-01-01。

问候。

SELECT
    ADDDATE('2007-01-01' INTERVAL SeqValue DAY) DateValue
FROM
(
SELECT
    (HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
FROM
    (
    SELECT 0  SeqValue
    UNION ALL
    SELECT 1 SeqValue
    UNION ALL
    SELECT 2 SeqValue
    UNION ALL
    SELECT 3 SeqValue
    UNION ALL
    SELECT 4 SeqValue
    UNION ALL
    SELECT 5 SeqValue
    UNION ALL
    SELECT 6 SeqValue
    UNION ALL
    SELECT 7 SeqValue
    UNION ALL
    SELECT 8 SeqValue
    UNION ALL
    SELECT 9 SeqValue
    ) ONES
CROSS JOIN
    (
    SELECT 0 SeqValue
    UNION ALL
    SELECT 10 SeqValue
    UNION ALL
    SELECT 20 SeqValue
    UNION ALL
    SELECT 30 SeqValue
    UNION ALL
    SELECT 40 SeqValue
    UNION ALL
    SELECT 50 SeqValue
    UNION ALL
    SELECT 60 SeqValue
    UNION ALL
    SELECT 70 SeqValue
    UNION ALL
    SELECT 80 SeqValue
    UNION ALL
    SELECT 90 SeqValue
    ) TENS
CROSS JOIN
    (
    SELECT 0 SeqValue
    UNION ALL
    SELECT 100 SeqValue
    UNION ALL
    SELECT 200 SeqValue
    UNION ALL
    SELECT 300 SeqValue
    UNION ALL
    SELECT 400 SeqValue
    UNION ALL
    SELECT 500 SeqValue
    UNION ALL
    SELECT 600 SeqValue
    UNION ALL
    SELECT 700 SeqValue
    UNION ALL
    SELECT 800 SeqValue
    UNION ALL
    SELECT 900 SeqValue
    ) HUNDREDS
) SEQ
WHERE
    SEQ.SeqValue < = 366 AND
    ADDDATE('2007-01-01' INTERVAL SeqValue DAY) < ADDDATE('2007-01-01' INTERVAL 1 YEAR)
ORDER BY
    ADDDATE('2007-01-01' INTERVAL SeqValue DAY) ASC

【讨论】:

  • 很好,但是如果您只想在外部查询中省略它们,则不需要在 HUNDREDS 派生表中从 SELECT 400 到 SELECT 900。 :-)
  • 比尔,我认为你的评论是开玩笑的。该示例的目的是演示该策略,而不一定要将其限制为 400 天。
  • @Pittsburgh DBA - 我正要问一个类似的问题,我发现这个答案非常有帮助。
【解决方案2】:

在 CTE 之前,人们会使用标准的预加载整数表(实用程序表中通常有几千个,请参阅this article)并在必要时加入它。这将在 mysql 中为您工作:

CREATE TABLE dbo.Numbers 
( 
    Number INT IDENTITY(1,1) PRIMARY KEY CLUSTERED 
) 

WHILE COALESCE(SCOPE_IDENTITY(), 0) <= 1024 
BEGIN 
    INSERT dbo.Numbers DEFAULT VALUES 
END

SELECT DATEADD(dd, Number, DATEADD(dd, 0, DATEDIFF(dd, 0, DATEADD(yy, -1, GETDATE())))) AS Date
FROM Numbers
WHERE Number BETWEEN 0 AND 366

在 SQL Server 2005 中,您可以使用公用表表达式和递归:

WITH DateRange(Date) AS
(
    SELECT DATEADD(dd, 0, DATEDIFF(dd, 0, DATEADD(yy, -1, GETDATE()))) AS Date
    UNION ALL
    SELECT DATEADD(day, 1, Date) AS Date
    FROM DateRange
    WHERE Date <= GETDATE()
)
SELECT Date 
FROM DateRange
OPTION (MAXRECURSION 366)

【讨论】:

    【解决方案3】:

    AFAIK 你不能用单个 SQL 查询来做到这一点。然而,下面的代码块将完成这项工作。

    目前在 Transact-SQL(用于 SQL Server)中。我不知道这如何转化为 MySQL。

    DECLARE @start datetime
    DECLARE @end datetime
    DECLARE @results TABLE
    (
       val datetime not null
    )
    set @start = '2008-10-01'
    set @end = getdate()
    while @start < @end
    begin
        insert into @results values(@start)
        SELECT @start = DATEADD (d, 1, @start)
    end
    select val from @results
    

    这个输出:

    2008-10-01 00:00:00.000
    2008-10-02 00:00:00.000
    2008-10-03 00:00:00.000
    

    【讨论】:

      最近更新 更多