php - 从天数中获取范围

标签 php mysql

我有这个表结构:

编辑更复杂的例子:添加隐藏范围

category|   day      |   a   |
--------|------------|-------|
1       | 2012-01-01 |   4   |
1       | 2012-01-02 |   4   |
1       | 2012-01-03 |   4   |
1       | 2012-01-04 |   4   |
1       | 2012-01-05 |   5   |
1       | 2012-01-06 |   5   |
1       | 2012-01-07 |   5   |
1       | 2012-01-08 |   4   |
1       | 2012-01-09 |   4   |
1       | 2012-01-10 |   4   |
1       | 2012-01-11 |   5   |
1       | 2012-01-12 |   5   |
1       | 2012-01-16 |   5   |
1       | 2012-01-17 |   5   |
1       | 2012-01-18 |   5   |
1       | 2012-01-19 |   5   |
...

以“category-day”作为唯一键。我会根据“a”列和给定的限制范围,为每个类别提取一系列日期,如下所示:

1,2012-01-01|2012-01-04,4
1,2012-01-05|2012-01-07,5
1,2012-01-08|2012-01-10,4
1,2012-01-11|2012-01-12,5
1,2012-01-13|2012-01-15,0
1,2012-01-16|2012-01-19,5

或类似的。

我正在寻找最好的方法。最好只使用 mysql,但也要使用一点 php。

注意 1:并非所有日期都被插入:在两天之间,非连续日期不能是其他日期。在这种情况下,我将使用“a”= 0 列输出错过的范围。

注意 2:我用一个简单的查询和一些 php 行完成了它,但我不喜欢它,因为我的简单算法需要一个周期,范围内的每一天都与找到的每个类别相乘。如果范围太大,类别太多,那就不太好了。

最终编辑:好的!阅读所有评论和答案后,我认为不存在有效、高效且同时可读的解决方案。所以 Mosty Mostacho 的答案不是 100% 有效的解决方案,但它有 100% 有效的建议。谢谢大家。

最佳答案

新编辑:

正如我在评论中告诉您的那样,我强烈建议您使用快速查询,然后在 PHP 中处理缺失的日期,因为这样会更快且更具可读性:

select
  concat(@category := category, ',', min(day)) col1,
  concat(max(day), ',', @a := a) col2
from t, (select @category := '', @a := '', @counter := 0) init
where @counter := @counter + (category != @category or a != @a)
group by @counter, category, a

但是,如果您仍然想使用查询版本,那么试试这个:

select
  @counter := @counter + (category != @category or a != @a) counter,
  concat(@category := category, ',', min(day)) col1,
  concat(max(day), ',', @a := a) col2
from (
  select distinct s.day, s.category, coalesce(t1.a, 0) a
  from (
    select (select min(day) from t) + interval val - 1 day day, c.category
    from seq s, (select distinct category from t) c
    having day <= (select max(day) from t)
  ) s
  left join t t1 on s.day = t1.day and s.category = t1.category
  where s.day between (
    select min(day) from t t2
    where s.category = t2.category) and (
    select max(day) from t t2
    where s.category = t2.category)
  order by s.category, s.day
) t, (select @category := '', @a := '', @counter := 0) init
group by counter, category, a
order by category, min(day)

请注意,MySQL 不允许您动态创建数据,除非您对UNIONS 进行硬编码,对于example。 .这是一个昂贵的过程,这就是为什么我强烈建议您创建一个只有 integer 字段且值从 1X 的表,其中 X至少min(day)max(day) 与你的 table 。如果您不确定该日期,只需添加 100,000 数字,您就可以生成超过 200 年的范围周期。在前面的查询中,此表是 seq,它的列是 val

这导致:

+--------------+--------------+
|     COL1     |     COL2     |
+--------------+--------------+
| 1,2012-01-01 | 2012-01-04,4 |
| 1,2012-01-05 | 2012-01-07,5 |
| 1,2012-01-08 | 2012-01-10,4 |
| 1,2012-01-11 | 2012-01-12,5 |
| 1,2012-01-13 | 2012-01-15,0 |
| 1,2012-01-16 | 2012-01-19,5 |
+--------------+--------------+

好吧,我在撒谎。结果实际上是返回一个 counter 列。忽略它,因为删除它(使用派生表)的性能会更低!

关于php - 从天数中获取范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9945741/

相关文章:

mysql - 如何自动删除数据库表中的旧记录?

java - 连接到本地主机 MySQL 数据库的问题

php - 如何使用 php 将搜索结果插入到表中?

php - CodeIgniter 和 Smarty

php - 在 Phpmyadmin 中插入表中的编辑值不起作用

php - Laravel - SQLSTATE[HY001] 无法分配足够的内存 - MsSQL

jquery - 多雇主对员工管理

PHP+MySQL : searching using wildcards

php - 如何在 PHPMyAdmin 中使 MySql 中的字段自动递增?

php - 如何在纯 PHP 中创建刷新 token ?