这是我要完成的任务:
查找给定位置最近的可用车辆。
我有一个vehicle
的表和一个location
的表,如下所示:
CREATE TABLE location
(location_id numeric(8,0) UNIQUE NOT NULL,
address varchar(100),
latitude float,
longitude float,
PRIMARY KEY(location_id)
);
CREATE TABLE vehicle
(license_plate char(6) UNIQUE NOT NULL,
make varchar(30) NOT NULL,
model varchar(30) NOT NULL,
year numeric(4,0) NOT NULL CHECK(year>1990),
state char(2) NOT NULL,
capacity int NOT NULL,
last_location numeric(8,0) DEFAULT NULL,
FOREIGN KEY(last_location) REFERENCES location(location_id) ON DELETE
CASCADE ON UPDATE CASCADE,
PRIMARY KEY(license_plate)
);
我编写了一个查询,该查询调用一个函数来遍历vehicle
表,计算给定位置的距离,并以最小距离返回汽车的license_plate
。
SELECT @locationA := 11111111;
SET @loc_lat = (SELECT latitude FROM location WHERE location_id =
@locationA);
SET @loc_long = (SELECT longitude FROM location WHERE location_id =
@locationA);
SELECT license_plate, make, model FROM vehicle
WHERE license_plate = find_car(@loc_lat, @loc_long);
DELIMITER $$
CREATE FUNCTION find_car(loc_lat float, loc_long float) RETURNS char
BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DECLARE CUR_DIST float DEFAULT 1000000000;
DECLARE car_lat NUMERIC;
DECLARE car_long NUMERIC;
DECLARE dist float;
DECLARE closest_car char(6);
DECLARE car_temp char(6);
DECLARE loc_temp numeric;
DECLARE car_cursor CURSOR FOR SELECT license_plate, last_location FROM
vehicle;
OPEN car_cursor;
car_loop: LOOP
FETCH car_cursor INTO car_temp, loc_temp;
SET car_lat = (SELECT latitude FROM location WHERE location_id =
loc_temp);
SET car_long = (SELECT longitude FROM location WHERE location_id =
loc_temp);
SET dist = (SELECT ST_Distance_Sphere(
point(loc_lat, loc_long),
point(car_lat, car_long)
) * .000621371192);
IF dist < CUR_DIST THEN
SET closest_car = car_temp;
SET CUR_DIST = dist;
END IF;
END LOOP;
CLOSE car_cursor;
RETURN(closest_car);
END $$
DELIMITER ;
现在,它什么也不会返回,我也不知道为什么。我对SQL还是很陌生,所以在此先感谢您!
答案 0 :(得分:0)
我的建议是首先尝试一种基于集合的方法,并查看其效果。
Some good insights on why found here。
一般策略:对于每个location_id
,找到下一个最接近的location_id
一些特定策略:
GETDISTANCE
函数(在下面找到代码)location_id
表的自连接计算所有location
值之间的距离这是一个用于自动联接到location
表和“过头”条件的入门脚本...
SELECT l1.location_id as l1_location_id
,l1.latitude as l1_latitude
,l1.longitude as l1_longitude
,l2.location_id as l2_location_id
,l2.latitude as l2_latitude
,l2.longitude as l2_longitude
,GETDISTANCE(l1.latitude, l1.longitude, l2.latitude, l2.longitude) as l1_12_distance
FROM location AS l1
JOIN location AS l2 ON l1.location_id <> l2.location_id
WHERE GETDISTANCE(l1.latitude, l1.longitude, l2.latitude, l2.longitude) <= 1000; -- JJAUSSI: arbitrary "too far"
这是jpgunter's GETDISTANCE函数...
DELIMITER $$
/*
Takes two latitudes and longitudes in degrees. You could comment out the conversion if you want to pass as radians.
Calculate the distance in miles, change the radius to the earth's radius in km to get km.
*/
DROP FUNCTION IF EXISTS GETDISTANCE$$
CREATE FUNCTION GETDISTANCE
(deg_lat1 FLOAT, deg_lng1 FLOAT, deg_lat2 FLOAT, deg_lng2 FLOAT)
RETURNS FLOAT
DETERMINISTIC
BEGIN
DECLARE distance FLOAT;
DECLARE delta_lat FLOAT;
DECLARE delta_lng FLOAT;
DECLARE lat1 FLOAT;
DECLARE lat2 FLOAT;
DECLARE a FLOAT;
SET distance = 0;
/*Convert degrees to radians and get the variables I need.*/
SET delta_lat = radians(deg_lat2 - deg_lat1);
SET delta_lng = radians(deg_lng2 - deg_lng1);
SET lat1 = radians(deg_lat1);
SET lat2 = radians(deg_lat2);
/*Formula found here: http://www.movable-type.co.uk/scripts/latlong.html*/
SET a = sin(delta_lat/2.0) * sin(delta_lat/2.0) + sin(delta_lng/2.0) * sin(delta_lng/2.0) * cos(lat1) * cos(lat2);
SET distance = 3956.6 * 2 * atan2(sqrt(a), sqrt(1-a));
RETURN distance;
END$$
DELIMITER ;
您可能要考虑修改字段名称year
,因为它是reserved word。
您可能会发现,如果/当数据库扩展时,这些名称太笼统了:
location
address
latitude
longitude
但是,我不知道您的数据库。表和字段名称可能完全适合您的需求。希望这会有所帮助!