神救救我。这使用了双相关子查询、系统中可能不存在的表以及过多的咖啡因。但是,嘿,它有效。
对了,这就去。
SELECT CarId, GROUP_CONCAT(DISTINCT missing) missing
FROM MyTable r,
(SELECT @a := @a + 1 missing
FROM mysql.help_relation, (SELECT @a := -1) t
WHERE @a < 16 ) y
WHERE NOT EXISTS
(SELECT r.CarID FROM MyTable m
WHERE y.missing BETWEEN FromCity_Id AND ToCity_Id
AND r.carid = m.carid)
GROUP BY CarID;
产生(将 1002 的第一行更改为CarID
0-9 以打开 10 并为我们提供更好的测试数据):
+-------+---------+
| CarId | missing |
+-------+---------+
| 1001 | 3,4,10 |
| 1002 | 10 |
+-------+---------+
2 rows in set (0.00 sec)
这一切是如何运作的?
首先......内部查询为我们提供了一个从 0 到 16 的数字列表:
(SELECT @a := @a + 1 missing
FROM mysql.help_relation, (SELECT @a := -1) t
WHERE @a < 16 ) y
它通过从 -1 开始,然后显示在某个牺牲表中的每一行的该数字加 1 的结果来实现这一点。我正在使用mysql.help_relation
它,因为它有超过一千行,并且大多数基本系统都有它。YMMV。
然后我们交叉加入MyTable
:
SELECT CarId, ...
FROM MyTable r,
(...) y
这为我们提供了所有可能的行组合,因此我们将每个 CarId 和 To/From ID 与 1-16 中的每个数字混合。
过滤...
这就是有趣的地方。我们需要找到与数字不匹配的行,我们需要根据CarID
. 这种事情会做到(只要y.missing
存在,当我们关联子查询时就会这样做):
SELECT m.CarID FROM MyTable m
WHERE y.missing BETWEEN FromCity_Id AND ToCity_Id
AND m.CarID = 1001;
请记住:y.missing
设置为 1-16 之间的数字,与MyTable
. 这为我们提供了 1-16的所有号码列表,其中CarID
1001忙。我们可以用 a 反转该集合,当我们在它的时候,关联(再次)与,这样我们就可以获得所有这样的 ID。NOT EXISTS
CarId
然后过滤不适合的行很容易:
SELECT CarId, ...
FROM MyTable r,
(...) y
WHERE NOT EXISTS
(SELECT r.CarID FROM MyTable m
WHERE y.missing BETWEEN FromCity_Id AND ToCity_Id
AND r.carid = m.carid)
输出
为了给出合理的结果(尝试 1),我们可以得到不同的组合。这是那个版本:
SELECT DISTINCT CarId, missing
FROM MyTable r,
(SELECT @a := @a + 1 missing
FROM mysql.help_relation, (SELECT @a := -1) t
WHERE @a < 16 ) y
WHERE NOT EXISTS
(SELECT r.CarID FROM MyTable m
WHERE y.missing BETWEEN FromCity_Id AND ToCity_Id
AND r.carid = m.carid);
这给出了:
+-------+---------+
| CarId | missing |
+-------+---------+
| 1001 | 3 |
| 1001 | 4 |
| 1001 | 10 |
| 1002 | 10 |
+-------+---------+
4 rows in set (0.01 sec)
GROUP BY
a和 a的简单相加GROUP CONCAT
给出了您在此答案顶部获得的漂亮结果。
对于给您带来的不便,我深表歉意。