5

我需要找到 0 到 16 之间的缺失数字。

我的桌子是这样的:

CarId    FromCity_Id    ToCity_Id    Ran_Date    RunId
1001        0              2        01-08-2013     1
1001        5              9        02-08-2013     2
1001        11             16       03-08-2013     3
1002        0              11       02-08-2013     4
1002        11             16       08-08-2013     5

我需要找出:

在过去的三个月里now(),汽车没有在哪些城市之间行驶过。

例如,在上述记录中:

  • 1001 号车在 02-05 和 09-11 之间没有运行
  • 1002 号车已完全运行(即在 0-11 和 11-16 之间)

总而言之,我需要生成一个查询,显示过去 3 个月内汽车未运行的部分,并显示上次运行日期。

请问如何进行这样的查询。如果有任何存储过程,请告知。

4

4 回答 4

2

神救救我。这使用了双相关子查询、系统中可能不存在的表以及过多的咖啡因。但是,嘿,它有效。

对了,这就去。

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 的第一行更改为CarID0-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的所有号码列表,其中CarID1001忙。我们可以用 a 反转该集合,当我们在它的时候,关联(再次)与,这样我们就可以获得所有这样的 ID。NOT EXISTSCarId

然后过滤不适合的行很容易:

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 BYa和 a的简单相加GROUP CONCAT给出了您在此答案顶部获得的漂亮结果。

对于给您带来的不便,我深表歉意。

于 2013-09-09T15:34:57.420 回答
0

这是想法。创建所有汽车和所有号码的列表。然后,返回数据未涵盖的所有组合。这很难,因为每辆车都有不止一排。

这是一种方法:

select cars.CarId, n.n
from (select distinct CarId from t) cars cross join
     (select 0 as n union all select 1 union all select 2 union all select 3 union all
      select 4 union all select 5 union all select 6 union all select 7 union all
      select 8 union all select 9 union all select 10 union all select 11 union all
      select 12 union all select 13 union all select 14 union all select 15 union all
      select 16
     ) n
where t.ran_date >= now() - interval 90 day and
      not exists (select 1
                  from t t2
                  where t2.ran_date >= now() - interval 90 day and
                        t2.CarId = cars.CarId and
                        n.n not between t2.FromCity_id and t2.ToCity_id
                 );
于 2013-09-09T15:17:21.940 回答
0
select * from carstable where CarId not in 
(select distinct CarId from ranRecordTable where DATEDIFF(NOW(), Ran_Date) <= 90)

希望这可以帮助。

于 2013-09-09T14:43:14.523 回答
0

SQL小提琴

MySQL 5.5.32 架构设置

CREATE TABLE Table1
    (`CarId` int, `FromCity_Id` int, `ToCity_Id` int, `Ran_Date` datetime, `RunId` int)
;

INSERT INTO Table1
    (`CarId`, `FromCity_Id`, `ToCity_Id`, `Ran_Date`, `RunId`)
VALUES
    (1001, 0, 2, '2013-08-01 00:00:00', 1),
    (1001, 5, 9, '2013-08-02 00:00:00', 2),
    (1001, 11, 16, '2013-08-03 00:00:00', 3),
    (1002, 0, 11, '2013-08-02 00:00:00', 4),
    (1002, 11, 16, '2013-08-08 00:00:00', 5)
;

查询 1

SELECT r1.CarId,r1.ToCity_Id as Missing_From, r2.FromCity_Id as Missing_To,
       max(t.Ran_Date) as Last_Run_Date 
FROM (
SELECT @i1:=@i1+1 AS rownum, t.*
FROM Table1 as t, (SELECT @i1:=0) as foo
ORDER BY CarId, Ran_Date) as r1
INNER JOIN (
SELECT @i2:=@i2+1 AS rownum, t.*
FROM Table1 as t, (SELECT @i2:=0) as foo
ORDER BY CarId, Ran_Date) as r2 ON r1.CarId = r2.CarId AND 
                                   r1.ToCity_Id != r2.FromCity_Id AND
                                   r2.rownum = (r1.rownum + 1)
INNER JOIN Table1 as t ON r1.CarId = t.CarId
WHERE r1.Ran_Date >= now() - interval 90 day           
GROUP BY r1.CarId, r1.ToCity_Id, r2.FromCity_Id

结果

| CARID | MISSING_FROM | MISSING_TO |                 LAST_RUN_DATE |
|-------|--------------|------------|-------------------------------|
|  1001 |            2 |          5 | August, 03 2013 00:00:00+0000 |
|  1001 |            9 |         11 | August, 03 2013 00:00:00+0000 |
于 2013-09-09T16:26:07.770 回答