如何构造此Oracle SQL查询?

如何构造此Oracle SQL查询?,sql,oracle,Sql,Oracle,我正在Oracle中编写一个sql查询,类似于: SELECT * FROM ( SELECT testid, max(decode(name, 'longitude', stringvalue, NULL)) as longitude, max(decode(name, 'latitude', stringvalue, NULL)) as latitude FROM test_av

我正在Oracle中编写一个sql查询,类似于:

 SELECT *
   FROM ( SELECT testid,
                 max(decode(name, 'longitude', stringvalue, NULL)) as longitude,  
                 max(decode(name, 'latitude', stringvalue, NULL)) as latitude
            FROM test_av 
           GROUP  BY testid
        ) av
  INNER JOIN ( 
                  SELECT id,
                          ((ACOS(
                                 SIN(16.15074 * 3.141592653 / 180) 
                                 * SIN(latitude * 3.141592653 / 180) 
                                 + COS(16.15074 * 3.141592653 / 180) 
                                 * COS(latitude * 3.141592653 / 180)
                                 * COS((-22.74426 - longitude)*3.141592653 / 180)
                          )*6373)) as distance
                    FROM test 

        ) t ON t.id = av.testid
  WHERE t.distance <= 100 
SELECT *
   FROM ( SELECT testid,
                 max(decode(name, 'longitude', stringvalue, NULL)) as longitude,  
                 max(decode(name, 'latitude', stringvalue, NULL)) as latitude
            FROM test_av av
           GROUP  BY testid
        ) av,
  TABLE ( CAST (MULTISET( 
                  SELECT id,
                          ((ACOS(
                                 SIN(16.15074 * 3.141592653 / 180) 
                                 * SIN(latitude * 3.141592653 / 180) 
                                 + COS(16.15074 * 3.141592653 / 180) 
                                 * COS(latitude * 3.141592653 / 180)
                                 * COS((-22.74426 - longitude)*3.141592653 / 180)
                          )*6373)) as distance
                    FROM test ti
                    WHERE ti.id = av.testid
                    )
        )) t  
  WHERE t.distance <= 100 
当我执行此查询时,Oracle会说“经度无效标识符”。我试图访问子查询别名,但查询失败


如何将一个子查询的“别名”访问到另一个子查询?

如果我正确理解了您要做的事情,您实际上不需要内部联接,因为您没有从测试中获取任何尚未在测试中的真实信息。所以,你可以写:

SELECT *
  FROM ( SELECT id,
                longitude,
                latitude,
                ((ACOS( SIN(16.15074 * 3.141592653 / 180)
                        * SIN(latitude * 3.141592653 / 180)
                        + COS(16.15074 * 3.141592653 / 180)
                        * COS(latitude * 3.141592653 / 180)
                        * COS((-22.74426 - longitude) * 3.141592653 / 180)
                )*6373)) AS distance
           FROM ( SELECT testid AS id,
                         max(decode(name, 'longitude', stringvalue, NULL)) as longitude,
                         max(decode(name, 'latitude', stringvalue, NULL)) as latitude
                    FROM test_av
                   GROUP
                      BY testid
                )
       )
 WHERE distance <= 100
;

如果你想明确地确保你只得到测试中存在的记录——也就是说,如果你在测试中有没有父项的记录,并且你想过滤掉这些记录——那么你可以在最里面的子查询中处理它,在你的FROM测试之后。

嗯,我是SQL Server专家,而不是Oracle专家,但我认为你想要这样的东西:

 SELECT *
   FROM ( SELECT testid,
                 max(decode(name, 'longitude', stringvalue, NULL)) as longitude,  
                 max(decode(name, 'latitude', stringvalue, NULL)) as latitude
            FROM test_av 
           GROUP  BY testid
        ) av
  INNER JOIN ( 
                  SELECT id,
                          ((ACOS(
                                 SIN(16.15074 * 3.141592653 / 180) 
                                 * SIN(latitude * 3.141592653 / 180) 
                                 + COS(16.15074 * 3.141592653 / 180) 
                                 * COS(latitude * 3.141592653 / 180)
                                 * COS((-22.74426 - longitude)*3.141592653 / 180)
                          )*6373)) as distance
                    FROM test 

        ) t ON t.id = av.testid
  WHERE t.distance <= 100 
SELECT *
   FROM ( SELECT testid,
                 max(decode(name, 'longitude', stringvalue, NULL)) as longitude,  
                 max(decode(name, 'latitude', stringvalue, NULL)) as latitude
            FROM test_av av
           GROUP  BY testid
        ) av,
  TABLE ( CAST (MULTISET( 
                  SELECT id,
                          ((ACOS(
                                 SIN(16.15074 * 3.141592653 / 180) 
                                 * SIN(latitude * 3.141592653 / 180) 
                                 + COS(16.15074 * 3.141592653 / 180) 
                                 * COS(latitude * 3.141592653 / 180)
                                 * COS((-22.74426 - longitude)*3.141592653 / 180)
                          )*6373)) as distance
                    FROM test ti
                    WHERE ti.id = av.testid
                    )
        )) t  
  WHERE t.distance <= 100 

你需要检查整个CASTMULTISET。。我对这件事一无所知,只知道在过去的一个项目中,有人给了我一些黑魔法,让SQL Server交叉应用查询在Oracle上工作。

你问过如何将一个子查询的别名访问到另一个子查询。。。快速浏览一下,这是通过使用两个模拟表来实现的一种方法。您可以像下面这样使用select语句。不确定这是否是您的最佳解决方案,但应该让您走上正确的轨道

SELECT testav.*, testt.*
FROM 
    ( SELECT av.testid as id,
         max(decode(av.name, 'longitude', stringvalue, NULL)) as longitude,  
         max(decode(av.name, 'latitude', stringvalue, NULL)) as latitude
      FROM test_av av
      GROUP BY av.testid
    ) testav,
    (SELECT  t.id as id,
             ((ACOS(
                 SIN(16.15074 * 3.141592653 / 180) 
               * SIN(t.latitude * 3.141592653 / 180) 
               + COS(16.15074 * 3.141592653 / 180) 
               * COS(t.latitude * 3.141592653 / 180)
               * COS((-22.74426 - t.longitude)*3.141592653 / 180)
                  )*6373)) as distance
     FROM test t
    ) testt
WHERE testav.id = testt.id
and testt.distance <= 100
子查询的另一种方法是为纬度和经度两列添加两个选择,并通过别名引用外部查询。这看起来性能很差,但Oracle在这种类型查询方面做得很好。单列选择不需要任何组。我会考虑返回空字符串而不是null,除非您需要它。我不确定甲骨文是否会喜欢在else情况下使用空值。我想这样对你一定有用

SELECT id,
          ACOS(..snipped details..)*6373) as distance,
          (SELECT max(decode(av.name, 'longitude', stringvalue, NULL)) 
           FROM test_av
           WHERE test_av.testid = av.id) as longitude,  
          (SELECT max(decode(av.name, 'latitude', stringvalue, NULL)) 
           FROM test_av
           WHERE test_av.testid = av.id) as latitude
      FROM test_av av
      WHERE av.distance <= 100

添加最后评论。由于计算中使用了经度和纬度值,因此第二个查询不会得到OP想要的结果。这是嵌套查询的一个示例,但不是OP问题的解决方案。抱歉,如果它误导了任何人。

decode不是一个有效的内置函数AFAIK,这不是调用名为decode的UDF的有效语法。那么这是怎么回事?@rbaryyoung:这是一个完全有效的内置函数;看见decodename,'经度',stringvalue,NULL约为?相当于name='longide'然后是stringvalue END.Oops抱歉的情况。感到困惑,以为是SQL Server。我的错…为什么Haversine子查询嵌套了两次?这似乎是多余的,因为外部连接没有做任何事情?正如其他人提到的,一个问题是内部连接你不需要它。只需在Oracle中使用where t.id=av.id进行连接,在使用别名时要保持一致,并在整个过程中使用别名。非常感谢您的回复。此查询也失败了,Oracle说“FROM keyword not found where expected”,我提供了一些测试数据,可能会让您感兴趣you@user964147:好主意;这让我很快发现了我的错误。显然Oracle不喜欢SELECT*。。。出于某种原因。无论如何,我现在已经修复了我的查询:-你能把你的信寄出去吗query@user964147:是的。我修正了我的查询,我的意思是我编辑了我的答案,给出了一个有效的查询。仅供参考-巴里,你的想法是正确的,只是不需要显式地将第二个select转换为表。在Oracle中,您不需要将select强制转换为表,如果您用括号将select括起来并给它一个别名,Oracle会将其视为表。因此,您可以删除表强制转换和结束参数。我认为alias引用将以您拥有的方式很好地工作。