在SQL查询中查找缺少的数字

时间:2013-09-09 14:33:13

标签: mysql

我需要找到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()之后的过去三个月中,汽车尚未运行的城市之间。

例如,在上面的记录中:

  • Car 1001未在02-05& 09-11
  • 汽车1002已完全运行(即在0-11和11-16之间)

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

请如何进行此类查询。如果有任何存储过程,请告知。

4 个答案:

答案 0 :(得分: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;

生成(将CarID 1002的第一行更改为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 忙碌的所有数字的列表。我们可以使用NOT EXISTS反转该集合,当我们处理它时,将{再次)与CarId相关联,这样我们就可以获得所有这些ID。

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

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 BYGROUP CONCAT可以获得您在此答案顶部获得的漂亮结果。

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

答案 1 :(得分:0)

select * from carstable where CarId not in 
(select distinct CarId from ranRecordTable where DATEDIFF(NOW(), Ran_Date) <= 90)

希望这有帮助。

答案 2 :(得分: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
                 );

答案 3 :(得分:0)

SQL Fiddle

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

<强> Results

| 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 |