从MySQL

时间:2016-12-15 14:12:57

标签: mysql geolocation

#1,

我需要你的帮助!

假设我在MySQL中有一个看起来像这样的表:

-------------------------------------------------
 OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION
-------------------------------------------------
1|1|123456|2016-01-01 00:00:00|A
1|2|123456|2016-01-01 00:01:00|B
1|3|123456|2016-01-01 00:02:00|C
1|4|123456|2016-01-01 00:03:00|C
1|5|123456|2016-01-01 00:04:00|B
1|6|123456|2016-01-01 00:05:00|A
1|7|123456|2016-01-01 00:06:00|A
...
1|999|123456|2016-01-01 09:10:00|A
1|1000|123456|2016-01-01 09:11:00|A
1|1001|123456|2016-01-01 09:12:00|B
1|1002|123456|2016-01-01 09:13:00|C
1|1003|123456|2016-01-01 09:14:00|C
1|1004|123456|2016-01-01 09:15:00|B
...
  

请注意,表格架构已经完成,所以我可以解释一下   我想要完成的事情......

想象一下,从ENTRY_ID 6到999,LOCATION列是“A”。我申请的所有内容基本上都是1-6行,然后是1000行。第7行到第999行的所有内容都是不需要进一步处理的不必要数据。我正在努力做的是要么忽略这些行而不必将数据处理移动到我的应用程序中,或者更好的是删除它们。

我为此感到头疼,因为:

1)我不能按LOCATION排序然后只取第一个和最后一个条目,因为时间顺序对我的应用程序很重要而且会丢失 - 例如,如果我以这种方式处理这些数据,我会以第1行和第1000行结束,第6行丢失。

2)我宁愿不将这些数据的处理移到我的应用程序中,这些数据对我的要求是多余的,如果我可以避免它,就没有必要保留它。

鉴于上面的示例数据,一旦我有解决方案,我想要最终得到的结果是:

-------------------------------------------------
 OWNER_ID | ENTRY_ID | VEHICLE | TIME | LOCATION
-------------------------------------------------
1|1|123456|2016-01-01 00:00:00|A
1|2|123456|2016-01-01 00:01:00|B
1|3|123456|2016-01-01 00:02:00|C
1|4|123456|2016-01-01 00:03:00|C
1|5|123456|2016-01-01 00:04:00|B
1|6|123456|2016-01-01 00:05:00|A
1|1000|123456|2016-01-01 09:11:00|A
1|1001|123456|2016-01-01 09:12:00|B
1|1002|123456|2016-01-01 09:13:00|C
1|1003|123456|2016-01-01 09:14:00|C
1|1004|123456|2016-01-01 09:15:00|B
...

希望我在这里有意义,不要错过任何明显的东西!

  

@Aliester - 有没有办法确定一行不需要   从该行中包含的数据处理?

不幸的是没有。

  

@O。琼斯 - 听起来你希望确定最早和最早的   表中的最新时间戳,用于ENTRY_ID的每个不同值,   然后从匹配那些的表中检索详细信息行   时间戳。那是对的吗?您的ENTRY_ID值是否唯一?是吗   保证按升序排列?您的查询可以进行   如果这是真的便宜。如果您有时间,请编辑您的问题   澄清这些要点。

我正在尝试找到某个地点的到达时间,然后是该地点的出发时间。是的,ENTRY_ID是一个唯一的字段,但您不能认为先前的ENTRY_ID将等于较早的时间戳 - 传入的数据是从车辆上的GPS单元发送的,并且不一定按照它们发送到期的顺序处理网络限制。

1 个答案:

答案 0 :(得分:1)

这是在SQL中要解决的棘手问题,因为SQL是关于数据集的,而不是数据序列。它在MySQL中比较棘手,因为其他SQL变种具有合成的ROWNUM函数,而MySQL在2016年末还没有。

这里需要两组数据的并集。

  1. 数据库的行集,紧接在之前,位置发生变化。
  2. 位置更改后的行集。
  3. 要实现这一点,您需要从一个子查询开始,该子查询生成所有行,按VEHICLE排序TIME,行号。 (http://sqlfiddle.com/#!9/6c3bc7/2/0)请注意,Sql Fiddle中的示例数据与您的示例数据不同。

           SELECT (@rowa := @rowa + 1) rownum,
                   loc.*
              FROM loc
              JOIN (SELECT @rowa := 0) init
             ORDER BY VEHICLE, TIME
    

    然后,您需要自联接该子查询,使用ON子句排除同一位置的连续行,并在更改位置之前获取行。比较连续行由ON ... b.rownum = a.rownum+1完成。那就是这个查询。 (http://sqlfiddle.com/#!9/6c3bc7/1/0

    SELECT a.*
    FROM (
                SELECT (@rowa := @rowa + 1) rownum,
                       loc.*
                  FROM loc
                  JOIN (SELECT @rowa := 0) init
                 ORDER BY VEHICLE, TIME
    ) a 
     JOIN (
                 SELECT (@rowb := @rowb + 1) rownum,
                       loc.*
                  FROM loc
                  JOIN (SELECT @rowb := 0) init
                 ORDER BY VEHICLE, TIME
     ) b   ON a.VEHICLE = b.VEHICLE
          AND b.rownum = a.rownum + 1
          AND a.location <> b.location
    

    此子查询的一个变体,您说SELECT b.*,在位置更改后立即获取行(http://sqlfiddle.com/#!9/6c3bc7/3/0

    最后,您采用这两个查询的setwise UNION,对其进行适当排序,然后删除重复连续位置的行集。请注意,这在MySQL中非常冗长,因为用于生成行号的讨厌的@rowa := @rowa + 1 hack必须在子查询的每个副本中使用不同的变量(@rowa@rowb等) 。 (http://sqlfiddle.com/#!9/6c3bc7/4/0

    SELECT a.*
      FROM (
            SELECT (@rowa := @rowa + 1) rownum,
                   loc.*
              FROM loc
              JOIN (SELECT @rowa := 0) init
             ORDER BY VEHICLE, TIME
    ) a 
     JOIN (
             SELECT (@rowb := @rowb + 1) rownum,
                   loc.*
              FROM loc
              JOIN (SELECT @rowb := 0) init
             ORDER BY VEHICLE, TIME
     ) b ON a.VEHICLE = b.VEHICLE AND b.rownum = a.rownum + 1  AND a.location <> b.location
    
     UNION
    
     SELECT d.*
      FROM (
            SELECT (@rowc := @rowc + 1) rownum,
                   loc.*
              FROM loc
              JOIN (SELECT @rowc := 0) init
             ORDER BY VEHICLE, TIME
    ) c 
     JOIN (
             SELECT (@rowd := @rowd + 1) rownum,
                   loc.*
              FROM loc
              JOIN (SELECT @rowd := 0) init
             ORDER BY VEHICLE, TIME
     ) d ON c.VEHICLE = d.VEHICLE AND c.rownum = d.rownum - 1  AND c.location <> d.location
     order by VEHICLE, TIME
    

    而且,在下一代MySQL中,现在在MariaDB 10.2中提供测试版,这要容易得多。新一代作为公用表表达式和行编号。

     with loc as
         (
                SELECT  ROW_NUMBER() OVER (PARTITION BY VEHICLE ORDER BY time) rownum,
                       loc.*
                  FROM loc
    )
    
    select a.* 
     from loc a
     join loc b ON a.VEHICLE = b.VEHICLE
               AND b.rownum = a.rownum + 1
               AND a.location <> b.location
     union 
    select b.* 
     from loc a
     join loc b ON a.VEHICLE = b.VEHICLE
               AND b.rownum = a.rownum + 1
               AND a.location <> b.location
    order by vehicle, time