mysql - Oracle圆距离搜索: missing results

标签 mysql oracle oracle11g

编辑:(如果您想查看旧问题,请参阅此问题的底部)

在您的帮助下,我修改了我的声明:

SELECT *
  FROM (
          SELECT 
                dest.ZC_ZIP, 
                dest.ZC_LOCATION_NAME,
                ACOS(
                    SIN(RADIANS(src.ZC_LAT)) * SIN(RADIANS(dest.ZC_LAT)) 
                    + COS(RADIANS(src.ZC_LAT)) * COS(RADIANS(dest.ZC_LAT))
                    * COS(RADIANS(src.ZC_LON) - RADIANS(dest.ZC_LON))
                    ) * 6371 AS DISTANCE
          FROM USER.ZC_COORDINATES dest
          CROSS JOIN USER.ZC_COORDINATES src
          WHERE src.ZC_ID = 
                (SELECT 
                        ZC_ID
                        FROM USER.ZC_COORDINATES
                        WHERE ZC_ZIP = '64289'
                        GROUP BY ZC_ID
                )
                AND
                (dest.ZC_ID <> src.ZC_ID OR dest.ZC_ID = src.ZC_ID)
      )
  HAVING DISTANCE <= 25 /* km */
  ORDER BY DISTANCE;

此后我收到错误:“Radians”是无效标识符。

原因:Oracle 实现了该功能(MySQL 实现了!)。

所以我搜索并找到了这段代码并使用它:

CREATE OR REPLACE FUNCTION calc_distance(pLat1 NUMBER, pLon1 NUMBER, pLat2 NUMBER, pLon2 NUMBER)
 RETURN NUMBER IS

-- r is the spherical radius of earth in Kilometers 
cSpherRad CONSTANT NUMBER := 6371;

-- The spherical radius of earth in miles is 3956
a        NUMBER;
vLat     NUMBER;
vLat1Rad NUMBER;
vLat2Rad NUMBER;
vLon     NUMBER;
vLon1Rad NUMBER;
vLon2Rad NUMBER;

BEGIN
  /*
  Most computers require the arguments of trigonometric functions to be
  expressed in radians. To convert lon1, lat1 and lon2,lat2 from
  degrees,minutes, seconds to radians, first convert them to decimal
  degrees. To convert decimal degrees to radians, multiply the number
  of degrees by pi/180 = 0.017453293 radians/degrees.
  */

  vLat1Rad := pLat1 * 0.017453293;
  vLat2Rad := pLat2 * 0.017453293;
  vLon1Rad := pLon1 * 0.017453293;
  vLon2Rad := pLon2 * 0.017453293;

  vLon := vLon2Rad - vLon1Rad;
  vLat := vLat2Rad - vLat1Rad;

  a := POWER(SIN(vLat/2),2) + COS(vLat1Rad) * COS(vLat2Rad) * POWER(SIN(vLon/2),2);

  /*
  The intermediate result c is the great circle distance in radians.
  Inverse trigonometric functions return results expressed in radians.
  To express c in decimal degrees, multiply the number of radians by
   180/pi = 57.295780 degrees/radian.
  The great circle distance d will be in the same units as r.
  */

  RETURN ROUND(cSpherRad * 2 * ATAN2(SQRT(a), SQRT(1-a)),1);
EXCEPTION
  WHEN OTHERS THEN
    RETURN 999;
END calc_distance;
/

编译成功。

现在正确的修改没有分组错误:

SELECT *
  FROM (
          SELECT 
                dest.ZC_ZIP AS ZIP, 
                dest.ZC_LOCATION_NAME AS LOCNAME,
                calc_distance(src.ZC_LAT, src.ZC_LON, dest.ZC_LAT, dest.ZC_LON) AS DISTANCE
          FROM BASE.ZC_COORDINATES dest
          CROSS JOIN BASE.ZC_COORDINATES src
          WHERE src.ZC_ID = 
                (SELECT 
                        ZC_ID
                        FROM BASE.ZC_COORDINATES
                        WHERE ZC_ZIP = '64289'
                        GROUP BY ZC_ID
                )
                AND
                (dest.ZC_ID <> src.ZC_ID OR dest.ZC_ID = src.ZC_ID)
      )
  HAVING DISTANCE <= 25 /* km */
  GROUP BY ZIP, LOCNAME, DISTANCE;
  --ORDER BY DISTANCE;

现在有什么问题吗?

好的,在我的旧本地 MySQL 系统上,我得到这些 sql 结果(正确的解决方案):

zc_zip  zc_location_name  distance     
64291   Darmstadt         0 
64297   Darmstadt         0 
64289   Darmstadt         0 
64283   Darmstadt         0 
64285   Darmstadt         0 
64295   Darmstadt         0 
64293   Darmstadt         0 
64287   Darmstadt         0 
64347   Griesheim, Hessen 5.385545333978872 
64331   Weiterstadt       5.671376373674798 
64367   M├╝hltal, Hessen  6.992565870106159 
64319   Pfungstadt        7.7621346384241585 
64380   Roßdorf bei Darmstadt 8.134881711148836 
64372   Ober-Ramstadt     8.421977582053422 
64390   Erzhausen, Hessen 9.419234655429722 
64572   B├╝ttelborn       9.739076077060767 
64409   Messel            9.962635340560048 
63329   Egelsbach, Hessen 11.274247321555363 
64342   Seeheim-Jugenheim 11.743554066395413 
64560   Riedstadt         12.135040456984065 
64404   Bickenbach        12.597317271640899 
64521   Groß-Gerau       12.637599535794854 
64397   Modautal          13.260629389533909 
64846   Groß-Zimmern     13.270265030251164 
63225   Langen (Hessen)   13.745513110307494 

这是我从预言机系统得到的:

ZIP     LOCNAME     DISTANCE
64293   Darmstadt   0
64283   Darmstadt   0
64295   Darmstadt   0
64285   Darmstadt   0
64297   Darmstadt   0
64287   Darmstadt   0
64289   Darmstadt   0
64291   Darmstadt   0

您看,缺少一些结果。 我认为问题出在oracle语句中的“GROUP BY”行,这是必需的。 所以我无法删除这一行。但我怎样才能得到其他结果呢?我真的很困惑:(

<小时/>

(老问题)

目前,我为我的员工编写了一个循环邮政编码搜索。 我的工具正在我的 MySQL 数据库(本地)上运行。

现在我将 OpenGeoDB 迁移到我们的 Oracle 数据库(成功),并希望运行我的 sql 语句,该语句在我的本地 MySQL 数据库上完美运行。

完整的错误消息:

ORA-00904: "DISTANCE": invalid indentifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:
Error in line: 20 col: 7

我的SQL语句:

SELECT 
    dest.zc_zip, 
    dest.zc_location_name,
    ACOS(
        SIN(RADIANS(src.zc_lat)) * SIN(RADIANS(dest.zc_lat)) 
        + COS(RADIANS(src.zc_lat)) * COS(RADIANS(dest.zc_lat))
        * COS(RADIANS(src.zc_lon) - RADIANS(dest.zc_lon))
    ) * 6371 as distance
FROM USER.ZC_COORDINATES dest
CROSS JOIN USER.ZC_COORDINATES src
WHERE src.zc_id =
    (
    SELECT zc_id
    FROM USER.zip_coordinates
    WHERE zc_zip = '64289' /* Platzhalter fuer PLZ */
    GROUP BY zc_zip
    )

AND (dest.zc_id <> src.zc_id OR dest.zc_id = src.zc_id)
HAVING distance <= 25 /* km */
ORDER BY distance;

我该如何解决这个问题?: 我用完整的数学计算切换了“距离”一词,但在此之后,Oracle 调用无效标识符“弧度”

这就是我的问题,因为我不知道如何解决这个问题。

有人有解决这个问题的想法吗?

谢谢。

最佳答案

Oracle 不允许您在以下 ORDER BY 中使用在 SELECT 列表中计算的列。以下是合理的解决方法:

SELECT *
  FROM (SELECT dest.ZC_ZIP, 
               dest.ZC_LOCATION_NAME,
               ACOS(SIN(RADIANS(src.ZC_LAT)) * SIN(RADIANS(dest.ZC_LAT)) 
                    + COS(RADIANS(src.ZC_LAT)) * COS(RADIANS(dest.ZC_LAT))
                    * COS(RADIANS(src.ZC_LON) - RADIANS(dest.ZC_LON))
                    ) * 6371 AS DISTANCE
          FROM USER.ZC_COORDINATES dest
          CROSS JOIN USER.ZC_COORDINATES src
          WHERE src.ZC_ID = (SELECT ZC_ID
                               FROM USER.ZIP_COORDINATES
                               WHERE ZC_ZIP = '64289'
                               GROUP BY ZC_ZIP) AND
                (dest.ZC_ID <> src.ZC_ID OR
                 dest.ZC_ID = src.ZC_ID))
  HAVING DISTANCE <= 25 /* km */
  ORDER BY DISTANCE;

Oracle 也不提供将度数转换为弧度的函数,但添加您自己的函数很容易:

CREATE OR REPLACE FUNCTION RADIANS(nDegrees IN NUMBER) RETURN NUMBER DETERMINISTIC IS
BEGIN
  -- radians = degrees / (180 / pi)
  -- RETURN nDegrees / (180 / ACOS(-1));  -- but 180/pi is a constant, so...
  RETURN nDegrees / 57.29577951308232087679815481410517033235;
END RADIANS;

分享并享受。

关于mysql - Oracle圆距离搜索: missing results,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24937868/

相关文章:

php - 如何在mysql查询中添加数组变量参数?(PHP)

mysql - 在 Mysql Workbench 中,Synchronize Model with Database 在哪里

php - 用 2 维数组数据填充 MySQL 表

PHP-PDO try/catch 插入动态 html 链接

java - Hibernate:将字符串属性映射到 CLOB 列

sql - Oracle SQL 在包含数据时将列类型从 number 更改为 varchar2

Oracle触发器清除旧记录

sql - 复制记录以填补日期之间的空白

database - 我们可以根据两列对 oracle 数据库进行分区吗

sql - Oracle 中完全外连接的奇怪行为 - 如何解释?