【问题标题】:Repeat rows based on range of dates in two columns根据两列中的日期范围重复行
【发布时间】:2013-02-08 22:11:40
【问题描述】:

我有一个包含以下列的表格:

ID startdate enddate

我希望此表的行重复与 startdate 和 enddate 之间的差异一样多的次数,以及一个列,该列为表中的每个 id 提供这两天之间的所有日期。所以,我的新表应该是这样的:

ID Date

A startdate
A startdate +1 day
A startdate +2 days (till enddate)
B startdate
B startdate + 1 day ....

请注意,我对不同的 ID 有不同的开始和结束日期。

我尝试了以下问题的答案,但这不起作用:

Mysql select multiple rows based on one row related date range

【问题讨论】:

  • 您想要查询(选择)或表格(带 pl)?
  • @twillouer 我希望将其插入新表中。另外,我不明白“pl”是什么意思。谢谢。

标签: mysql date range rows repeat


【解决方案1】:

这是一种方法。

这使用内联视图(别名为 i 来生成从 0 到 999 的整数值,并连接到您的表以生成最多 1000 个日期值,从 startdate 到 enddate 的每一行。

内联视图i 可以轻松扩展以生成 10,000 或 100,000 行,遵循相同的模式。

这假定startdateenddate 列的数据类型为DATE。 (或DATETIMETIMESTAMP 或可隐式转换为有效DATE 值的数据类型。

SELECT t.id
     , t.startdate + INTERVAL i.i DAY AS `Date`
  FROM ( SELECT d3.n*100 + d2.n*10 + d1.n AS i
           FROM ( 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
                ) d1
          CROSS
           JOIN ( 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
                ) d2
          CROSS
           JOIN ( 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
                ) d3
       ) i
  JOIN mytable t
    ON i.i <= DATEDIFF(t.enddate,t.startdate)

【讨论】:

  • 感谢您的回复@spencer7593,但我先尝试了 Robin 的代码,效果很好。感谢您的帮助。
  • @Sun Mun:使用 Robin 的方法,您的查询取决于表的存在以及该表的内容。对于一些大型商店的一些开发人员来说,DBA 似乎只有在国会法案和陆军工程兵团的环境影响研究之后才会创建新表......动态生成一组整数是一种方便的方法.
  • 非常感谢。我一直在寻找这个答案的年龄,而你的答案似乎确实适用于我正在尝试做的事情:)
  • @user1942165 :这是一种对我有用的技术,它不需要创建和填充表,或者创建用户定义的函数;这仅使用普通的旧 SQL。 (其他一些数据库有更方便的方法来生成整数序列。这个答案中演示的方法使用“base 10”,但是同样的方法可以很容易地使用 base 2 或任何其他基数。我们只是更熟悉以 10 为基数。)
  • 上面的一个快速的.... 9 在每个部分重复,需要是 8,否则它会给出奇怪的结果。
【解决方案2】:

您需要一个数字表...创建一个包含数字 1 到 X 的临时表或虚拟表(X 是两个日期之间可能的最大差异)

然后使用日期差异加入该表

恐怕我是 SQL Server,所以不确定 datediff 函数在 mysql 中的工作方式是否相同,但你应该明白。

SELECT
    DateTable.Id,
    DATEADD(dd, NumbersTable.Number, DateTable.StartDate)
FROM
    DateTable
INNER JOIN
    NumbersTable
ON
    DATEADD(dd, NumbersTable.Number, DateTable.StartDate) <= DateTable.EndDate
ORDER BY
    DateTable.Id,
    DATEADD(dd, NumbersTable.Number, DateTable.StartDate)

【讨论】:

  • 完美运行。非常感谢罗宾日。如果以后有人看到这篇文章,您可以使用@Pittsburgh DBA 在stackoverflow.com/questions/186756/… 上提供的代码生成一个包含 0-999 数字的表格。
  • 对于将来查看这篇文章的任何人来说也是一个注释,这个答案中的语法对 MySQL 无效。 (MySQL 有一个 DATE_ADD 函数和一个 ADDDATE 函数,并且两者的参数都与此答案中给出的(SQL Server)DATEADD 函数不同。MySQL 还支持方便的“date + INTERVAL n unit”语法。另请注意“数字表”很方便,但实际上并不是“需要”。可以动态生成一组整数,而不需要“需要”数字表。
【解决方案3】:

我知道现在回答很晚 但还有一个使用递归 cte 的答案

with  recursive cte ( id, startdate) as
(
select id,startdate  from test t1
union all
select t2.id,(c.startdate + interval '1 day')::date
from test t2
 join cte c on c.id=t2.id and (c.startdate + interval '1 day')::date<=t2.enddate
)
select id,startdate as date from cte
order by id, startdate

它是 PostgreSQL 特有的,但它应该可以在其他关系数据库中使用,而 Date 函数的变化很小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    • 2018-06-10
    • 1970-01-01
    • 1970-01-01
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多