如何解决如何使用这种复杂的表格结构按日期和时间订购商品?
| 我正在使用糟糕的CMS系统。 它的事件模块可以按明确的日期/时间来存储事件,例如2011-08-04 13:30:00
或按每周重复发生的事件,其重复发生的日期存储为基于0的整数,并将时间添加到日期/时间字段(数据为0),例如0000-00-00 13:30:00
。
我需要在接下来的2周内发布所有活动。这意味着我需要所有每周定期发生的事件以及接下来两周内的明确日期。
我不是sql专家。我写了这个查询...
SELECT `id`,`name`,`info`,`date_time`,`weekly_day`
FROM `events` AS a
WHERE `active` = true
AND `id` IN (SELECT `id`
FROM `events`
WHERE WEEK(`date_time`) BETWEEN WEEK(Now()) AND WEEK(
DATE_ADD(Now(),INTERVAL
1 WEEK)))
OR DATE(`date_time`) = 0
ORDER BY Time_to_sec(IF(TIME(`date_time`),TIME(`date_time`),Concat(EXTRACT(HOUR FROM `date_time`
),\":\",EXTRACT(MINUTE FROM `date_time`)))),IF(DATE(`date_time`),Dayofweek(`date_time`),`weekly_day` + 1) ASC
(请注意,上面的“ 3”已替换为某些PHP,并以MysqL格式显示当前日期。MysqL服务器的时区与我想要的时区不同。)
这样可以成功获取我想要的所有记录,但是顺序不正确。例如,6月9日的事件出现在6月2日的事件之前。
如何解决查询?
干杯。
更新资料
我想出了这个办法,但我仍然坚持……尽管日期似乎正确,但它不会显示每周的活动。
SELECT `id`,`weekly_day`,( DATE(`date_time`) = 0 ) AS `weekly`
FROM `events`
WHERE `active` = true
AND IF (DATE(`date_time`),WEEK(`date_time`),DATE_ADD(
Concat(DATE(Now()),\" \",Concat(EXTRACT(HOUR FROM `date_time`),EXTRACT
(
MINUTE FROM `date_time`))),INTERVAL
`weekly_day`
DAY))
BETWEEN WEEK(
Now()) AND WEEK(DATE_ADD(Now(),INTERVAL 2 WEEK))
ORDER BY `date_time` ASC
我无法使用TIME()
提取时间部分,因为它一直返回NULL
。
我究竟做错了什么?
解决方法
我分两步来做:
在接下来的两周内将周期性条目转换为两个DATETIME值。这将是一个子查询。
收集同一期间的非经常性分录。这将是第二个子查询。
这两个子查询的UNION会为您提供所有事件及其实际发生的日期和时间。正确地订购它是微不足道的。
如果您需要记录信息是否来自定期会议,请在两个子查询的选择列表中保留一些内容(可能是简单的\'R \'或\'N \'),以便您判断是否原始条目是重复发生的还是非重复发生的。
我不是MySQL DATETIME操作的专家-但我确实知道我在另一个DBMS(即Informix)这一领域的经验。就我在此讨论中的目的而言,表中只有两个有趣的列:
date_time
和weekly_day
。我假设您使用的MySQL约定为1 = Sunday,7 = Saturday。由于我们需要2周的信息来重复发生事件,因此生成3周并过滤掉无关的信息可能最容易。
给定一个参考日期和一个星期的整数,我们可以使用以下方法从中获取三个值:
refdate - DAYOFWEEK(refdate) + day_of_week
refdate - DAYOFWEEK(refdate) + day_of_week + INTERVAL 7 DAYS
refdate - DAYOFWEEK(refdate) + day_of_week + INTERVAL 14 DAYS
这产生了三个日期。第一个可能在过去,第三个可能在将来太远(因此需要丢弃)。当日期是自参考日期以来的天数时,这是一种算术(如Informix)。要将\'refdate \'设为NOW()
,将第三行翻译成MySQL,我们似乎不得不写(非常冗长-我认为Informix对于DATETIME操作非常冗长):
DATE_ADD(DATE_ADD(DATE_SUB(NOW(),DAYOFWEEK(NOW())),INTERVAL weekly_day DAY),INTERVAL 14 DAY)
在这里,我假设我可以将weekly_day
中的整数转换为几天。必要时进行调整。这些公式为每个重复条目提供三个DATE值,其中两个是相关的。为了增加时间,我认为我们需要:
DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(),INTERVAL 14 DAY),INTERVAL TIME(date_time) HOUR_SECOND)
因此,我最初的回答中提到的第一个子查询本身必须是3向UNION。
SELECT \'R\' AS info_mode,DATE_ADD(DATE_ADD(DATE_ADD(DATE_SUB(NOW(),INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT \'R\' AS info_mode,INTERVAL 7 DAY),DATE_ADD(DATE_ADD(DATE_SUB(NOW(),INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events;
现在,您需要针对“接下来的两周”进行过滤。究竟是哪个日期/时间范围?从参考时刻开始-指定为NOW()?还是从参考日开始?还是从参考日后的第二天开始?一切都看似合理;由于代码似乎使用了引用模式(这是最简单的),因此我们将继续:
SELECT *
FROM (SELECT \'R\' AS info_mode,INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT \'R\' AS info_mode,INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events) AS r
WHERE r.event_time BETWEEN NOW() AND DATE_ADD(NOW(),INTERVAL 14 DAY);
这给出了重复发生的事件。可以在UNION的每个分支中将r.event_time
上的过滤条件下推(复制),但我暂时将其保留在原处。
使用以下方法可以找到非重复事件:
SELECT \'N\' AS info_mode,date_time AS event_time
FROM events AS e
WHERE e.date_time BETWEEN NOW() AND DATE_ADD(NOW(),INTERVAL 14 DAY)
AND DATE(e.date_time) != DATE \'0000-00-00\';
因此,我们可以创建这两个查询的并集。可以将条件event_time
从两个子查询中拖出(并且我们希望优化程序然后“将其放回”)。
并且非重复事件子查询仅成为UNION的第四部分,从而导致:
SELECT *
FROM (SELECT \'R\' AS info_mode,INTERVAL TIME(date_time) HOUR_SECOND) AS event_time
FROM events
UNION
SELECT \'N\' AS info_mode,date_time AS event_time
FROM events
WHERE DATE(e.date_time) != DATE \'0000-00-00\'
) AS e
WHERE e.event_time BETWEEN NOW() AND DATE_ADD(NOW(),INTERVAL 14 DAY);
因此,这应该为您提供事件类型列表(重复发生,非重复发生)以及在接下来的14天内发生的事件。您只需将the20 the,name
和info
列(加上调试用的原始date_time
和weekly_day
列)添加回UNION中的4个查询中的每一个,并在e.event_time
(以及任何平局列)中添加ORDER BY子句您要添加)。
请对任何语法或特定于DBMS的语义错误有所帮助;我希望这个概念清楚(并且正确),即使由于不熟悉MySQL的细节而导致某些细节不正确。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。