MySQL用户定义函数用于纬度经度语法

3
我创建了一个MySQL函数,用于确定一组纬度和经度坐标是否在另一组纬度和经度坐标的某个范围内。但是,该函数给出了语法错误,因此我无法测试其是否正常工作。希望能够帮助我找出错误的原因。以下是该函数及其描述:
该函数通过传递起始纬度/经度坐标来运行。数据库包含包含纬度、经度和范围(分别)的targa、targb和targc行。数据库中的targ列指定是否应检查该行的纬度/经度范围。
CREATE FUNCTION inrange(
 lat1 decimal(11, 7), 
 lon1 decimal(11, 7))
 READS SQL DATA
 RETURNS INT(1)
BEGIN
 DECLARE distance decimal(18, 10);

 SET distance = ACOS(SIN(lat1)*SIN(targ2)+COS(lat1)*COS(targ2)*COS(targ3-lon1))*6371;

 IF distance <= targ4 THEN 
  RETURN 1;
 END IF;

 RETURN 0;
END$$

mysql 给我的错误是:
1064 - 你的 SQL 语法有误;请检查与你的 MySQL 服务器版本相对应的手册,以获取正确的语法使用方法,位于第 4 行附近的 'READS SQL DATA RETURNS INT(1) BEGIN DECLARE distance decimal(18, 10)'
我似乎无法解决这个错误。
此外,如果有人来到这篇文章寻找这样的 mysql 函数,我还有另一篇相关的帖子: MySQL Function to Determine Zip Code Proximity / Range 我非常感谢其他作者提供的函数(它为这个函数提供了灵感),但我需要更紧凑的东西。因此,问题中的函数。
编辑:以下代码是可用且正常工作的。只需记得将分隔符设置为 $$. 再次感谢所有人的帮助。
工作代码:
CREATE FUNCTION inrange(
    lat1 decimal(11, 7), 
    long1 decimal(11, 7),
    lat2 decimal(11, 7),
    long2 decimal(11, 7),
    rng decimal(18, 10))
    RETURNS INT(1)
BEGIN
    DECLARE distance decimal(18, 10);

    SET lat1 = lat1 * PI() / 180.0,
       long1 = long1 * PI() / 180.0,
       lat2 = lat2 * PI() / 180.0,
       long2 = long2 * PI() / 180.0;

    SET distance = ACOS(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(long2-long1))*6371;

    IF distance <= rng THEN 
        RETURN 1;
    END IF;

    RETURN 0;
END$$

你只传入了两个参数 - targ2、targ3和targ4从哪里来的? - OMG Ponies
targ,targ2,targ3和targ4是数据库中的列名。 - user396404
2个回答

3

您的 RETURNS 和 READS SQL DATA 的顺序颠倒了。应该先写 RETURNS:

CREATE FUNCTION inrange(
    lat1 decimal(11, 7), 
    lon1 decimal(11, 7))
    RETURNS INT(1)
    READS SQL DATA
BEGIN

编辑:此外,您在评论中提到了数据库中的列。不仅您的函数不知道这些列属于哪个表,而且通常情况下,您不应该从函数内部引用列。相反,应向您的函数添加参数:

CREATE FUNCTION inrange(
    lat1 decimal(11, 7), 
    long1 decimal(11, 7),
    lat2 decimal(11, 7),
    long2 decimal(11, 7),
    rng decimal(18, 10))
    RETURNS INT(1)
BEGIN
    DECLARE distance decimal(18, 10);

    SET distance = ACOS(SIN(lat1)*SIN(lat2)+COS(lat1)*COS(lat2)*COS(long2-long1))*6371;

    IF distance <= rng THEN 
        RETURN 1;
    END IF;

    RETURN 0;
END$$

然后,在您的查询中,您可以将列名传递给该函数。

(免责声明:请确保我在正确的位置放置了经纬度。我认为我已经这样做了。)


我尝试了这个和mischechter帖子中写的确切代码。现在我得到了错误:1064-您的SQL语法有误;请检查与您的MySQL服务器版本相对应的手册,以获取正确的语法使用方法,在第7行附近。 - user396404
只是为了确保..使用上面的代码,我会这样使用:inrange(120,70,targb,targc,targd)然后它会知道从表格中使用适当的列吗? - user396404
如果targb和targc是您的第二个纬度/经度,而targd是范围,那么是的。 - Jeff Mattfield
哈哈,我在mysql中仍然遇到相同的错误。抱歉,我对sql udfs还很陌生。我正在使用phpmyadmin输入函数。 - user396404
哎呀,我真傻。 “Range”是一个保留字。像我在答案中所做的那样,把它替换为“rng”。 - Jeff Mattfield
显示剩余2条评论

1

从您包含的过程中,看起来您的定界符已设置为$$

如果是这样,请尝试以下操作:

CREATE FUNCTION inrange(
 lat1 decimal(11, 7), 
 lon1 decimal(11, 7))
 RETURNS INT(1)
 READS SQL DATA
BEGIN
 DECLARE distance decimal(18, 10);

 SET distance = ACOS(SIN(lat1)*SIN(targ2)+COS(lat1)*COS(targ2)*COS(targ3-lon1))*6371;

 IF distance <= targ4 THEN 
  RETURN 1;
 END IF;

 RETURN 0;
END$$

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接