按时间间隔对时间间隔进行分组

时间:2015-07-19 09:26:07

标签: php mysql sql doctrine-orm

假设我已经给出startTimeendTime,并且这些间隔是半小时。例如startTime=8:00endTime=12:00所以可能的时间是8:00, 8:30, 9:00, 9:30, 10:00, 10:30, 11:00, 11:30, 12:00

现在我有一系列动作,其中包含我的动作发生的时间段。每行都有rowStartTime和rowEndTime。 它们的类型为TIME

我想要实现的是按时间返回GROUPed结果,并在该特定时间内发生行数。

演示数据

name    rowStarTime  rowEndTime
--------------------------------
action1  6:00        10:00
action2  9:00        13:00
action3  10:00       11:30
action4  12:00       13:00
action5  11:30       15:00

预期结果

Time      Action count    (actions in that time, this is just comment)
---------------------------------------------------------------------
8:00      1               //1
8:30      1               //1
9:00      2               //1, 2
9:30      2               //1, 2
10:00     3               //1, 2, 3
10:30     2               //2, 3
11:00     2               //2, 3
11:30     3               //2, 3, 5
12:00     4               //2, 4, 5

我想在数据库级别(使用SQL)上充分利用它。它可行吗?或者我必须得到一些PHP的帮助(我使用的是Doctrine DQL,但我可以使用许多特殊的SQL函数https://github.com/orocrm/doctrine-extensions& https://github.com/beberlei/DoctrineExtensions)?

我只能为rowStartTime实现这一目标,而不是整个时期:

SELECT `rowStartTime` AS sclr_0, COUNT(o.id) AS sclr_1 
FROM orders o 
GROUP BY sclr_0

(如果仅在startTimeendTime之间选择时间会使其变得困难,那么它不是核心,可以省略此条件)

3 个答案:

答案 0 :(得分:2)

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(name    VARCHAR(12) NOT NULL PRIMARY KEY
,start_time TIME NOT NULL
,end_time TIME NOT NULL
);

INSERT INTO my_table VALUES
('action1', '6:00:00','10:00:00'),
('action2', '9:00:00','13:00:00'),
('action3','10:00:00','11:30:00'),
('action4','12:00:00','13:00:00'),
('action5','11:30:00','15:00:00');

SELECT * FROM my_table;
+---------+------------+----------+
| name    | start_time | end_time |
+---------+------------+----------+
| action1 | 06:00:00   | 10:00:00 |
| action2 | 09:00:00   | 13:00:00 |
| action3 | 10:00:00   | 11:30:00 |
| action4 | 12:00:00   | 13:00:00 |
| action5 | 11:30:00   | 15:00:00 |
+---------+------------+----------+

SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+

SELECT SEC_TO_TIME(1800*(i2.i*10+i1.i)) time 
     , COUNT(*) total
     , GROUP_CONCAT(x.name) actions
  FROM ints i1
 CROSS  
  JOIN ints i2 
  LEFT
  JOIN my_table x
    ON SEC_TO_TIME(1800*(i2.i*10+i1.i)) BETWEEN x.start_time AND x.end_time
 WHERE SEC_TO_TIME(1800*(i2.i*10+i1.i)) BETWEEN '08:00:00' AND '12:00:00'
 GROUP 
    BY time;
+----------+-------+-------------------------+
| time     | total | actions                 |
+----------+-------+-------------------------+
| 08:00:00 |     1 | action1                 |
| 08:30:00 |     1 | action1                 |
| 09:00:00 |     2 | action1,action2         |
| 09:30:00 |     2 | action1,action2         |
| 10:00:00 |     3 | action1,action2,action3 |
| 10:30:00 |     2 | action2,action3         |
| 11:00:00 |     2 | action2,action3         |
| 11:30:00 |     3 | action2,action3,action5 |
| 12:00:00 |     3 | action2,action4,action5 |
+----------+-------+-------------------------+

答案 1 :(得分:1)

创建行动表

CREATE TABLE actions (a VARCHAR(50), start TIME, end TIME);
INSERT INTO actions (a,start,end) VALUES 
('action 1', '6:00', '10:00'),
('action 2', '9:00', '13:00'),
('action 3', '10:00', '11:30'),
('action 4', '12:00', '13:00'),
('action 5', '11:30', '15:00');

创建时间表

CREATE TABLE times (t TIME);
INSERT INTO times (t) VALUES 
('5:00'), ('5:30'), 
('6:00'), ('6:30'), 
('7:00'), ('7:30'), 
('8:00'), ('8:30'), 
('9:00'), ('9:30'), 
('10:00'), ('10:30'), 
('11:00'), ('11:30'),
('12:00'), ('12:30'),
('13:00'), ('13:30'),
('14:00'), ('14:30'),
('15:00'), ('15:30');

按时间选择

SELECT
times.t as t, 
count(CASE WHEN actions.a IS NOT NULL THEN 1 ELSE NULL END) as c
FROM times
LEFT JOIN actions ON actions.start <= times.t AND actions.end >= times.t
GROUP BY times.t

结果

t           c
05:00:00    0
05:30:00    0
06:00:00    1
06:30:00    1
07:00:00    1
07:30:00    1
08:00:00    1
08:30:00    1
09:00:00    2
09:30:00    2
10:00:00    3
10:30:00    2
11:00:00    2
11:30:00    3
12:00:00    3
12:30:00    3
13:00:00    3
13:30:00    1
14:00:00    1
14:30:00    1
15:00:00    1
15:30:00    0

答案 2 :(得分:1)

使用时间间隔创建临时表并使用

Time, count, actions
06:00:00, 1, action1
06:30:00, 1, action1
07:00:00, 1, action1
07:30:00, 1, action1
08:00:00, 1, action1
08:30:00, 1, action1
09:00:00, 2, action1,action2
09:30:00, 2, action1,action2
10:00:00, 3, action1,action2,action3
10:30:00, 2, action2,action3
11:00:00, 2, action2,action3
11:30:00, 3, action2,action3,action5
12:00:00, 3, action2,action4,action5

如您所见,结果

中不包括没有操作的时间
public List<String> getAllPosts() {
    pdb = this.getReadableDatabase();
    List<String> postsList = new ArrayList<>();

    String columns[] = {pid, post};
    Cursor cursor = pdb.query(TABLE_NAME, columns, null, null, null, null, null);
    cursor.moveToFirst();
    Log.d("Cursor in pdb", DatabaseUtils.dumpCursorToString(cursor));
    while(!cursor.isAfterLast()) {
        int postIndex = cursor.getColumnIndex(post);
        String post = cursor.getString(postIndex);
        postsList.add(post);
        cursor.moveToNext();
    }
    cursor.close();
    return postsList;
}