Mysql
 sql >> Base de données >  >> RDS >> Mysql

Requête pour calculer la somme de la distance (longitude, latitude) dans des lignes consécutives dans Mysql

Voici donc une solution à la première partie du problème...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table
(id     INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,user_name   VARCHAR(12) NOT NULL
,date             DATE NOT NULL
,LAT        DECIMAL(5,3) NOT NULL
,LON DECIMAL (5,2) NOT NULL
);

INSERT INTO my_table VALUES
( 1,'maria','2005-01-01',51.555 ,5.014),
( 2,'maria','2005-01-01',51.437 ,5.474),
( 3,'peter','2005-02-03',51.437 ,5.474),
( 4,'john' ,'2005-02-03',51.858 ,5.864),
( 5,'maria','2005-02-04',51.858 ,5.864),
( 6,'john' ,'2005-02-03',51.437 ,5.474),
( 7,'john' ,'2006-02-04',0      ,0),
( 8,'john' ,'2006-02-04',51.858 ,5.864),
( 9,'john' ,'2006-02-04',51.858 ,5.864),
(10,'john' ,'2006-02-04',51.437 ,5.474);


SELECT x.user_name
     , x.id from_id
     , MIN(y.id) to_id
  FROM my_table x
  JOIN my_table y
    ON y.user_name = x.user_name
   AND y.id > x.id
 WHERE (y.lat <> 0 AND y.lon <> 0)
   AND (x.lat <> 0 AND x.lon <> 0)
 GROUP 
    BY x.id;

+-----------+---------+-------+
| user_name | from_id | to_id |
+-----------+---------+-------+
| maria     |       1 |     2 |
| maria     |       2 |     5 |
| john      |       4 |     6 |
| john      |       6 |     8 |
| john      |       8 |     9 |
| john      |       9 |    10 |
+-----------+---------+-------+

Pour le reste du problème, quelque chose comme ce qui suit devrait fonctionner.

J'ai une fonction dans ma base de données appelée geo_distance_km. Il ressemble à ceci et évite de taper la formule haversine à chaque fois :

delimiter //
create DEFINER = CURRENT_USER function geo_distance_km (lat1 double, lon1 double, lat2 double, lon2 double) returns double
 begin
   declare R int DEFAULT 6372.8;
   declare phi1 double;
   declare phi2 double;
   declare d_phi double;
   declare d_lambda double;
   declare a double;
   declare c double;
   declare d double;
   set phi1 = radians(lat1);
   set phi2 = radians(lat2);
   set d_phi = radians(lat2-lat1);
   set d_lambda = radians(lon2-lon1);
   set a = sin(d_phi/2) * sin(d_phi/2) +
         cos(phi1) * cos(phi2) *
         sin(d_lambda/2) * sin(d_lambda/2);
   set c = 2 * atan2(sqrt(a), sqrt(1-a));
   set d = R * c;
   return d;
   end;
//
delimiter ;

Nous pouvons combiner cela avec ce que nous avons déjà...

SELECT user_name
     , YEAR(date) year
     , COALESCE(SUM(distance),0) total
  FROM 
     ( SELECT a.*
            , b.lat to_lat
            , b.lon to_lon
            , ROUND(geo_distance_km(from_lat,from_lon,b.lat,b.lon),3) distance
         FROM
            ( SELECT x.user_name
                   , x.date
                   , x.id from_id
                   , x.lat from_lat
                   , x.lon from_lon
                   , MIN(y.id) to_id
                FROM my_table x
                LEFT
                JOIN my_table y
                  ON y.user_name = x.user_name
                 AND y.id > x.id
                 AND (y.lat <> 0 OR y.lon <> 0)
                 WHERE (x.lat <> 0 AND x.lon <> 0)
               GROUP
                  BY x.id
            ) a
         LEFT
         JOIN my_table b
           ON b.id = a.to_id
     ) n
 GROUP
    BY user_name
     , year;

+-----------+------+---------+
| user_name | year | total   |
+-----------+------+---------+
| john      | 2005 | 108.024 |
| john      | 2006 |  54.012 |
| maria     | 2005 |  88.464 |
| peter     | 2005 |   0.000 |
+-----------+------+---------+

Je ne comprends pas très bien comment vous gérez les distances qui se chevauchent, mais cela devrait vous rapprocher de ce que vous recherchez.