Mar*_*ngs 19 mysql innodb select
我有一个带有列的 InnoDB 表“idtimes”(MySQL 5.0.22-log)
`id` int(11) NOT NULL,
`time` int(20) NOT NULL, [...]
Run Code Online (Sandbox Code Playgroud)
使用复合唯一键
UNIQUE KEY `id_time` (`id`,`time`)
Run Code Online (Sandbox Code Playgroud)
所以每个 id 可以有多个时间戳,每个时间戳可以有多个 id。
我正在尝试设置一个查询,在其中获取所有条目以及每个条目的下一个更大时间(如果存在),因此它应该返回,例如:
+-----+------------+------------+
| id | time | nexttime |
+-----+------------+------------+
| 155 | 1300000000 | 1311111111 |
| 155 | 1311111111 | 1322222222 |
| 155 | 1322222222 | NULL |
| 156 | 1312345678 | 1318765432 |
| 156 | 1318765432 | NULL |
+-----+------------+------------+
Run Code Online (Sandbox Code Playgroud)
现在我到目前为止:
SELECT l.id, l.time, r.time FROM
idtimes AS l LEFT JOIN idtimes AS r ON l.id = r.id
WHERE l.time < r.time ORDER BY l.id ASC, l.time ASC;
Run Code Online (Sandbox Code Playgroud)
但当然这会返回 r.time > l.time 的所有行,而不仅仅是第一行......
我想我需要一个像
SELECT outer.id, outer.time,
(SELECT time FROM idtimes WHERE id = outer.id AND time > outer.time
ORDER BY time ASC LIMIT 1)
FROM idtimes AS outer ORDER BY outer.id ASC, outer.time ASC;
Run Code Online (Sandbox Code Playgroud)
但我不知道如何引用当前时间(我知道以上不是有效的 SQL)。
如何使用单个查询执行此操作(我不希望使用依赖于一次单行遍历表并记住最后一个值的 @variables)?
Erw*_*out 20
执行 JOIN 是您可能需要的一件事。
SELECT l.id, l.time, r.time FROM
idtimes AS l LEFT JOIN idtimes AS r ON l.id = r.id
Run Code Online (Sandbox Code Playgroud)
我想外连接是故意的,你想得到空值。稍后再谈。
WHERE l.time < r.time ORDER BY l.id ASC, l.time ASC;
Run Code Online (Sandbox Code Playgroud)
你只想要r。具有高于 l.time 的最低 (MIN) 时间的行。那就是您需要子查询的地方。
WHERE r.time = (SELECT MIN(time) FROM idtimes r2 where r2.id = l.id AND r2.time > l.time)
Run Code Online (Sandbox Code Playgroud)
现在到空值。如果“没有下一个更高的时间”,那么 SELECT MIN() 将评估为 null(或更糟),并且它本身永远不会等于任何东西,因此您的 WHERE 子句将永远不会得到满足,并且“最高时间”对于每个 ID,永远不会出现在结果集中。
您可以通过消除 JOIN 并将标量子查询移动到 SELECT 列表中来解决它:
SELECT id, time,
(SELECT MIN(time) FROM idtimes sub
WHERE sub.id = main.id AND sub.time > main.time) as nxttime
FROM idtimes AS main
Run Code Online (Sandbox Code Playgroud)
小智 7
我总是避免在SELECT块中或在FROM,因为它使代码“更脏”,有时效率较低。
我认为更优雅的方法是:
\n您可以使用idtimesJOIN表与其自身之间来执行此操作,将连接限制为相同的id和大于时间的时间当前行时间的
您应该使用LEFT JOIN以避免排除没有时间的行当前行之一的行。
SELECT\n i1.id,\n i1.time AS time,\n i2.time AS greater_time\nFROM\n idtimes AS i1\n LEFT JOIN idtimes AS i2 ON i1.id = i2.id AND i2.time > i1.time\nRun Code Online (Sandbox Code Playgroud)\n正如您所提到的,问题是您有多行next_time大于time。
\n+-----+------------+--------------+\n| id | time | greater_time |\n+-----+------------+--------------+\n| 155 | 1300000000 | 1311111111 |\n| 155 | 1300000000 | 1322222222 |\n| 155 | 1311111111 | 1322222222 |\n| 155 | 1322222222 | NULL |\n| 156 | 1312345678 | 1318765432 |\n| 156 | 1318765432 | NULL |\n+-----+------------+--------------+\nRun Code Online (Sandbox Code Playgroud)\n过滤所有这些无用行的最佳方法是找出该id的time(大于)和Greater_time(小于)之间是否存在时间。
\nSELECT\n i1.id,\n i1.time AS time,\n i2.time AS next_time,\n i3.time AS intrudor_time\nFROM\n idtimes AS i1\n LEFT JOIN idtimes AS i2 ON i1.id = i2.id AND i2.time > i1.time\n LEFT JOIN idtimes AS i3 ON i2.id = i3.id AND i3.time > i1.time AND i3.time < i2.time\nRun Code Online (Sandbox Code Playgroud)\nops,我们仍然有一个错误的 next_time!
\n+-----+------------+--------------+---------------+\n| id | time | next_time | intrudor_time |\n+-----+------------+--------------+---------------+\n| 155 | 1300000000 | 1311111111 | NULL |\n| 155 | 1300000000 | 1322222222 | 1311111111 |\n| 155 | 1311111111 | 1322222222 | NULL |\n| 155 | 1322222222 | NULL | NULL |\n| 156 | 1312345678 | 1318765432 | NULL |\n| 156 | 1318765432 | NULL | NULL |\n+-----+------------+--------------+---------------+\nRun Code Online (Sandbox Code Playgroud)\n只需过滤发生此事件的行,添加WHERE下面的约束
WHERE\n i3.time IS NULL\nRun Code Online (Sandbox Code Playgroud)\n瞧\xc3\xa0,我们有我们需要的了!
\n+-----+------------+--------------+---------------+\n| id | time | next_time | intrudor_time |\n+-----+------------+--------------+---------------+\n| 155 | 1300000000 | 1311111111 | NULL |\n| 155 | 1311111111 | 1322222222 | NULL |\n| 155 | 1322222222 | NULL | NULL |\n| 156 | 1312345678 | 1318765432 | NULL |\n| 156 | 1318765432 | NULL | NULL |\n+-----+------------+--------------+---------------+\nRun Code Online (Sandbox Code Playgroud)\n我希望四年后你仍然需要答案!
\n