web-dev-qa-db-ja.com

Oracleの1 = 1の同じテーブルからのサブクエリの結合

郵便番号、緯度と経度の表があります。半径と緯度と経度を受け取り、必要な半径内のすべての郵便番号を返す作業クエリがあります。

        SELECT Zip.zip,
                ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(:clng, :clat, NULL), NULL, NULL)), (
                            SELECT geom
                            FROM standard_Zip
                            WHERE Zip = Zip.zip
                            ), 0.005) / 1609.34, 2) AS dist
            FROM standard_Zip zip
            WHERE Zip.zip IN (
                    SELECT DISTINCT (Zip) AS Zip
                    FROM standard_Zip c
                    WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON(:clng, :clat, :r, 5)) = 'TRUE'
                        AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON(:clng, :clat, :r, 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE'
                    )
            ORDER BY DIST

Latとlongはすでにテーブルにあるので、最初に個別のルックアップを実行する代わりに、Zipコードをクエリの入力として提供したいのですが、これは永久に停止するようです。

SELECT 
    Zip.zip,
    ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(inp.lng, inp.lat, NULL), NULL, NULL)), (SELECT geom FROM standard_Zip WHERE Zip = Zip.zip), 0.005) / 1609.34, 2) AS dist,
    inp.lat,
    inp.lng
FROM standard_Zip zip
LEFT JOIN (SELECT x as lng, y as lat from standard_Zip where Zip = :Zip) inp on 1=1
WHERE Zip.zip IN (
        SELECT DISTINCT (Zip) AS Zip
        FROM standard_Zip c
        WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5)) = 'TRUE'
            AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE'
        )
ORDER BY DIST

何が悪いのですか?


MguerraTorres 素晴らしいCTEを使用することをお勧めします。これが私が試したものです:

WITH inp as (SELECT x as lng, y as lat from standard_Zip where Zip = :Zip)
SELECT 
    Zip.zip,
    ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(inp.lng, inp.lat, NULL), NULL, NULL)), (SELECT geom FROM standard_Zip WHERE Zip = Zip.zip), 0.005) / 1609.34, 2) AS dist,
    inp.lat,
    inp.lng
FROM standard_Zip zip
WHERE Zip.zip IN (
        SELECT DISTINCT (Zip) AS Zip
        FROM standard_Zip c
        WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5)) = 'TRUE'
            AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE'
        )
ORDER BY DIST

問題は、Oracleがinp.lngは無効な識別子です。どうして?

「inp」クエリにクロス結合していますが、その結果をwhere句のメインのwhere句のサブクエリに使用しています。事実上、サブクエリはZipテーブルのすべての行に対して1回実行されます。少し遅くなります。

これに関してPL/SQLで実現できることについては、私は少し錆びているので、純粋なSQLでは次のように書くことができます。

SELECT 
  Zip.zip,
  ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(inp.lng, inp.lat, NULL), NULL, NULL)), (SELECT geom FROM standard_Zip WHERE Zip = Zip.zip), 0.005) / 1609.34, 2) AS dist,
  inp.lat,
  inp.lng
FROM standard_Zip zip
WHERE Zip.zip IN (
    SELECT DISTINCT (Zip) AS Zip
    FROM standard_Zip c
    WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON((SELECT x as lng from standard_Zip where Zip = :Zip),
                                                     (SELECT y as lat from standard_Zip where Zip = :Zip),
                                                     (:r * 1609.34), 5)) = 'TRUE'
        AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON((SELECT x as lng from standard_Zip where Zip = :Zip),
                                                       (SELECT y as lat from standard_Zip where Zip = :Zip),
                                                       (:r * 1609.34), 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE'
    )
ORDER BY DIST

もう少し速いかもしれません。基本的には、元の作業クエリとほぼ同じように動作するはずです。

1
Jerb

私はそれがこれであるべきだと思います:

SELECT 
    Zip.zip,
    ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(inp.lng, inp.lat, NULL), NULL, NULL)), (SELECT geom FROM standard_Zip WHERE Zip = Zip.zip), 0.005) / 1609.34, 2) AS dist,
    inp.lat,
    inp.lng
FROM standard_Zip zip
   CROSS JOIN (SELECT x as lng, y as lat from standard_Zip where Zip = :Zip) inp
WHERE Zip.zip IN (
        SELECT Zip
        FROM standard_Zip c
        WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5)) = 'TRUE'
            AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON(inp.lng, inp.lat, (:r * 1609.34), 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE'
        )
ORDER BY DIST;
1

CTEを使用して試すことができます。

WITH CTE_Zip 
AS
(SELECT DISTINCT (Zip) AS Zip
                FROM standard_Zip c
                WHERE SDO_FILTER(c.geom, SDO_UTIL.CIRCLE_POLYGON(:clng, :clat, :r, 5)) = 'TRUE'
                    AND SDO_RELATE(c.geom, SDO_UTIL.CIRCLE_POLYGON(:clng, :clat, :r, 5), 'mask=ANYINTERACT querytype = WINDOW') = 'TRUE')

次に、結合する標準テーブルと同じようにCTE_Zipテーブルを使用します。または、WHERE EXISTS/WHERE NOT EXISTSを使用することもできます。

  SELECT Zip.zip,
            ROUND(SDO_GEOM.SDO_DISTANCE((MDSYS.SDO_GEOMETRY(2001, 4326, MDSYS.SDO_POINT_TYPE(:clng, :clat, NULL), NULL, NULL)), (
                        SELECT geom
                        FROM standard_Zip
                        WHERE Zip = Zip.zip
                        ), 0.005) / 1609.34, 2) AS dist
        FROM standard_Zip zip
        INNER JOIN CTE_Zip 
            ON Zip.zip = CTE_Zip.zip
        ORDER BY DIST
1
MguerraTorres