sql >> データベース >  >> RDS >> Mysql

MySQLポリゴンオーバーラップクエリを処理するにはどうすればよいですか?

    SQLフィドル

    ポリゴン列を使用してテーブルを作成する

    空間インデックスを使用するには、InnoDBを使用できないことに注意してください。空間インデックスなしでジオメトリを使用することはできますが、パフォーマンスは通常どおり低下します。

    CREATE TABLE IF NOT EXISTS `spatial` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `poly` geometry NOT NULL,
      UNIQUE KEY `id` (`id`),
      SPATIAL INDEX `poly` (`poly`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
    

    3つの正方形と三角形を挿入します

    INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((0 0,10 0,10 10,0 10,0 0))',0));
    INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((10 50,50 50,50 10,10 10,10 50))',0));
    INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((1 15,5 15,5 11,1 11,1 15))',0));
    INSERT INTO `spatial` (`poly`) VALUES (GeomFromText('POLYGON((11 5,15 5,15 1,11 5))',0));
    

    左下隅の小さな正方形と交差するものをすべて選択します (紫色の正方形#1)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Intersects(`poly`,
                GEOMFROMTEXT('POLYGON((0 0,2 0,2 2,0 2,0 0))', 0 )
            )
    ;
    

    左下から右下隅、右上隅まで、三角形と交差するものをすべて選択してください) (正方形#1と#2および三角形#4)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Intersects(`poly`,
                GEOMFROMTEXT('POLYGON((0 0,50 50,50 0,0 0))', 0 )
            )
    ;
    

    画像の外側にある正方形のすべてを選択します (なし)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Intersects(`poly`,
                GEOMFROMTEXT('POLYGON((100 100,200 100,200 200,100 200,100 100))', 0 )
            )
    ;
    

    編集#1:

    質問を読み直しましたが、空間的な関係が少し混乱していると思います。正方形(ポリゴン)の内側にぴったり収まるものをすべて見つけたい場合は、Contains/ST_Containsを使用する必要があります。 MySQLドキュメントの空間関数 を参照してください。 ST/MBR機能の次の違いに注意してください。

    完全に正方形の内側にあるものをすべて選択します(下から#0) (正方形#1、#2、三角形#4)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            Contains(
              GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
              `poly`
            )
    ;
    

    完全に正方形の内側(下から#0)にあり、エッジを共有しないすべてのものを選択します (正方形#2、三角形#4)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Contains(
              GEOMFROMTEXT('POLYGON((0 0,20 0,20 20,0 20,0 0))', 0 ),
              `poly`
            )
    ;
    

    編集#2:

    @StephanBからの非常に素晴らしい追加(SQLフィドル

    重複するオブジェクトを選択します

    SELECT s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)
    FROM  `spatial` s1, `spatial` s2
        WHERE 
            ST_Intersects(s1.poly, s2.poly)
        AND s1.id < s2.id
    ;
    

    AND s1.id < s2.idを削除する必要があることに注意してください CONTAINSを使用している場合 、as CONTAINS(a,b) <> CONTAINS(b,a) 一方、Intersects(a,b) = Intersects(b,a)

    次の図(網羅的ではないリスト):

    • 2は#6と交差します。

    • 6は#2と交差します

    • 0は#1、#2、#3、#4、#5と交差します

    • 1は#0、#5と交差します

    • 0には#1、#3、#4、および#5が含まれます(#1、#3、#4、および#5は#0内にあります)

    • 1には#5が含まれています(#5は#1内にあります)

    • 0 st_contains#3、#4、および#5

    • 1 st_contains#5

    編集#3:距離による検索/サークル内での作業

    MySQLは、ジオメトリとして円を直接サポートしていませんが、空間関数Buffer(geometry,distance)を使用できます。 それを回避する。 Buffer()とは は、ジオメトリの周りに上記の距離のバッファを作成しています。ジオメトリポイントから始める場合、バッファは確かに円です。

    次のコマンドを呼び出すだけで、バッファが実際に何をするかを確認できます:

    SELECT ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3))
    

    (結果は非常に長いので、ここには投稿しません)実際には、バッファーを表すポリゴンが作成されます。この場合(および私のMariaDB)の結果は、円に近接する126ポイントのポリゴンです。このようなポリゴンを使用すると、他のポリゴンと同じように作業できます。したがって、パフォーマンスの低下はありません。

    したがって、円に分類されるすべてのポリゴンを選択したい場合 すすぎ、前の例を繰り返すことができます(これは正方形#3だけを見つけます)

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Contains(
              Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
              `poly`
            )
    ;
    

    円と交差するすべてのポリゴンを選択します

    SELECT id,AsText(poly) FROM  `spatial` 
        WHERE 
            ST_Intersects(
              Buffer(GEOMFROMTEXT('POINT(6 15)'), 10),
              `poly`
            )
    ;
    

    長方形とは異なる形状で作業する場合は、ST_*を使用する必要があります 関数。 ST_のない関数 境界矩形を使用します。したがって、前の例では、三角形が円の中になくても、三角形#4を選択します。

    Buffer()として 非常に大きなポリゴンを作成する場合、ST_Distance()を使用するよりもパフォーマンスが低下することは間違いありません。 方法。残念ながら、それを定量化することはできません。ベンチマークを行う必要があります。

    距離でオブジェクトを検索する別の方法は、ST_Distance()を使用することです。 働き。

    テーブルからすべての要素を選択し、ポイントPOINT(6 15)からの距離を計算します

    SELECT id, AsText(`poly`), 
        ST_Distance(poly, GeomFromText('POINT(6 15)')) 
        FROM `spatial`
    ;
    

    ST_Distanceを使用できます WHERE 条項も同様です。

    POINT(0 0)からの距離が10以下のすべての要素を選択します (#1、#2、#3を選択)

    SELECT id, AsText(`poly`), 
        ST_Distance(poly, GeomFromText('POINT(6 15)')) 
        FROM `spatial`
        WHERE ST_Distance(poly, GeomFromText('POINT(6 15)')) <= 10
    ;
    

    距離は最も近い点から最も近い点まで計算されますが。 ST_Intersectに似せて 。したがって、上記の例では、完全に円の内側に収まらない場合でも、#2を選択します。

    はい、GeomFromText(text,srid)の2番目の引数(0) 、何の役割も果たしません。無視しても問題ありません。私はいくつかのサンプルからそれを拾い上げました、そしてそれは私の答えにちょっと立ち往生しています。後の編集で省略しました。

    ところで。 phpMyAdmin 空間拡張のサポートは完璧ではありませんが、データベースに何があるかを確認するのにかなり役立ちます。添付したこれらの画像を手伝ってくれました。




    1. 従業員の詳細を印刷するPL/SQLプログラム

    2. MariaDBで英数字以外の文字のみを含む行を返す2つの方法

    3. CakePHP 3-LocalStringFormatで日付を解析して、SQL形式を修正し、検証を修正します

    4. 必須フィールドに結果がありません