Vì vậy, đây là giải pháp cho phần đầu tiên của vấn đề ...
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 |
+-----------+---------+-------+
Đối với phần còn lại của vấn đề, một cái gì đó như sau sẽ hoạt động.
Tôi có một hàm trong cơ sở dữ liệu của mình được gọi là geo_distance_km. Nó trông giống như thế này và tiết kiệm việc nhập công thức hasrsine mỗi lần:
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 ;
Chúng ta có thể kết hợp điều đó với những gì chúng ta đã có ...
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 |
+-----------+------+---------+
Tôi không hiểu bạn xử lý những khoảng cách năm chồng lên nhau như thế nào, nhưng điều này sẽ giúp bạn tiến gần đến những gì bạn đang theo đuổi.