我正在尝试将50个日期时间范围的随机列表插入到MySQL数据库中。这些日期范围必须介于特定的开始日期和结束日期之间,并且它们必须相邻并按时间排序。
下面是我想在 2014-09-01 00:00:00 - 2014-10-12 23:59:59 :
start_time end_time
--------------------------------------------------------
2014-09-01 00:00:00 2014-09-01 02:45:12
2014-09-01 02:45:13 2014-09-01 04:12:33
2014-09-01 04:12:34 2014-09-02 12:12:20
....
2014-10-12 23:30:13 2014-10-12 23:59:59
我不确定这是否可以仅在MySQL中完成,或者我是否需要PHP脚本。生成日期之间的随机日期列表很好,它将随机性在50个条目之间平均分配,让我感到困惑。
这可以在MySQL中完成,如果可以,那么首选方法是什么?
修改 为了更好地解释我的问题,我有一个日期范围,我需要生成一个包含50个开始和结束日期的列表。我应该提到,就像我的例子一样,开始日期必须是在上一个结束日期之后的下一秒。
答案 0 :(得分:1)
您可以generate random dates using php添加一些功能来检查其他日期范围:
您必须加载内部日期范围:(我使用数组,但您将从数据库加载)
$ranges = array(
0 => array('start' => '2014-09-01 00:00:00', 'end' => '2014-09-01 02:45:12'),
1 => array('start' => '2014-09-01 02:45:13', 'end' => '2014-09-01 04:12:33'),
2 => array('start' => '2014-09-01 04:12:34', 'end' => '2014-09-02 12:12:20'),
3 => array('start' => '2014-10-12 23:30:13', 'end' => '2014-10-12 23:59:59')
);
检查日期的功能在$ ranges数组中:
function date_in_range($date_ranges,$rand_epoch){
foreach($date_ranges as $date){
$min_epoch = strtotime($date['start']);
$max_epoch = strtotime($date['end']);
if($rand_epoch >= $min_epoch && $rand_epoch <= $max_epoch){
return true;
}
}
return false;
}
修改函数以生成随机日期:
function rand_date($min_date, $max_date, $internal_ranges) {
/* Gets 2 dates as string, earlier and later date.
Returns date in between them.
*/
$min_epoch = strtotime($min_date);
$max_epoch = strtotime($max_date);
$rand_epoch = rand($min_epoch, $max_epoch);
// If date is not in internal range, get another random date again:
while(!date_in_range($internal_ranges,$rand_epoch)){
$rand_epoch = rand($min_epoch, $max_epoch);
}
return date('Y-m-d H:i:s', $rand_epoch);
}
// Testing
print rand_date('2014-09-01 00:00:00','2014-10-12 23:59:59',$ranges);
答案 1 :(得分:1)
是的,您可以在MySQL中执行此操作。 N个区间的一般算法是:
示例强>
Install these generator views,然后:
CREATE TABLE times (id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,begin_time DOUBLE NOT NULL,end_time DOUBLE NOT NULL DEFAULT 0);
INSERT INTO times (begin_time) SELECT @low bp UNION SELECT s.bp FROM (SELECT t.bp FROM (SELECT @low + FLOOR(RAND() * (@high-@low)) bp FROM generator_256 JOIN (SELECT @low := UNIX_TIMESTAMP('2014-09-01 00:00:00'), @high := UNIX_TIMESTAMP('2014-10-12 23:59:59')) init LIMIT 49) t ORDER by bp) s;
UPDATE times JOIN (SELECT curr.id, curr.begin_time, (SELECT next.begin_time-1 FROM times next WHERE next.id=curr.id+1) end_time FROM times curr) g ON g.id = times.id SET times.end_time = COALESCE(g.end_time, UNIX_TIMESTAMP('2014-10-12 23:59:59'));
SELECT FROM_UNIXTIME(begin_time), FROM_UNIXTIME(end_time) FROM times;
+---------------------------+-------------------------+
| FROM_UNIXTIME(begin_time) | FROM_UNIXTIME(end_time) |
+---------------------------+-------------------------+
| 2014-09-01 00:00:00 | 2014-09-02 13:32:45 |
| 2014-09-02 13:32:46 | 2014-09-03 07:57:24 |
| 2014-09-03 07:57:25 | 2014-09-04 17:34:01 |
| 2014-09-04 17:34:02 | 2014-09-04 19:46:25 |
| 2014-09-04 19:46:26 | 2014-09-05 17:44:48 |
...
| 2014-10-10 18:39:47 | 2014-10-11 05:11:13 |
| 2014-10-11 05:11:14 | 2014-10-11 11:27:29 |
| 2014-10-11 11:27:30 | 2014-10-12 13:03:02 |
| 2014-10-12 13:03:03 | 2014-10-12 17:55:54 |
| 2014-10-12 17:55:55 | 2014-10-12 19:11:11 |
| 2014-10-12 19:11:12 | 2014-10-12 23:59:59 |
+---------------------------+-------------------------+
50 rows in set (0.00 sec)
<强>解释强>
让我们一步一步地打破这些。要在MySQL中生成行,您必须使用generator view。每次请求时,生成器视图只会为您提供N行。例如,获得49行(N-1):
SELECT * FROM generator_256 LIMIT 49;
要在MySQL中的两个其他数字之间生成单个随机数,请使用随机数公式low + (RAND() * (high-low))
。这个公式与生成器视图相结合,为我们提供了步骤1所需的49个起点:
SELECT (@low + FLOOR(RAND() * (@high-@low))) AS bp FROM generator_256 LIMIT 49;
(我在这里使用会话变量来保持SQL简单。他们将在一点点成为查询的一部分。如果你想调试,请记住bp是时间戳,所以FROM_UNIXTIME( bp)将向您展示一种人性化的格式。)
现在,要对列表进行排序,请使用子查询:如果对生成的查询进行排序,则会在开始时间附近获得聚类的随机值。所以,主要完成第2步:
SELECT t.bp FROM (SELECT @low + FLOOR(RAND() * (@high-@low)) bp FROM generator_256 LIMIT 49) t ORDER by t.bp;
现在,它开始变得棘手。对于任何给定的行,我们希望以比下一行开始时间少一秒的时间填充结束时间。虽然有几种方法可以实现,但我认为最清楚的是使用目标表(或其副本)来存储我们生成的起点。 (注意我在这里初始化了@low和@high的值,并且包含了列表中的起始点):
CREATE TABLE times (id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,begin_time DOUBLE NOT NULL,end_time DOUBLE NOT NULL DEFAULT 0);
INSERT INTO times (begin_time) SELECT @low bp UNION SELECT s.bp FROM (SELECT t.bp FROM (SELECT @low + FLOOR(RAND() * (@high-@low)) bp FROM generator_256 JOIN (SELECT @low := UNIX_TIMESTAMP('2014-09-01 00:00:00'), @high := UNIX_TIMESTAMP('2014-10-12 23:59:59')) init LIMIT 49) t ORDER by bp) s;
最后,我们可以使用联合更新添加结束时间。
UPDATE times JOIN (SELECT curr.id, curr.begin_time, (SELECT next.begin_time-1 FROM times next WHERE next.id=curr.id+1) end_time FROM times curr) g ON g.id = times.id SET times.end_time = COALESCE(g.end_time, UNIX_TIMESTAMP('2014-10-12 23:59:59'));
在我的例子中,我没有做过两件事:
INTERVAL
运算符添加这些约束。