Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bagaimana saya bisa menangani kueri tumpang tindih poligon MySQL?

SQL fiddle

Buat tabel dengan kolom poligon

Harap dicatat, bahwa untuk menggunakan indeks spasial, Anda tidak dapat menggunakan InnoDB. Anda dapat menggunakan geometri tanpa indeks spasial, tetapi kinerja menurun seperti biasa.

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;

Masukkan 3 kotak dan segitiga

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));

Pilih semua yang berpotongan dengan kotak kecil di sudut kiri bawah (kotak ungu #1)

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

Pilih semua yang berpotongan segitiga mulai dari kiri bawah hingga sudut kanan bawah hingga sudut kanan atas) (kotak #1 dan #2 dan segitiga #4.)

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

Memilih segala sesuatu dalam kotak yang berada di luar gambar kita (tidak ada)

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

Edit #1:

Saya membaca ulang pertanyaannya dan saya pikir Anda memiliki hubungan spasial yang sedikit bingung. Jika yang Anda inginkan adalah menemukan semua yang cocok sepenuhnya di dalam kotak (poligon), maka Anda perlu menggunakan Mengandung/ST_Contains. Silakan lihat fungsi spasial dalam dokumentasi MySQL untuk mengetahui fungsi mana yang bekerja untuk Anda. Harap perhatikan perbedaan berikut antara fungsi ST/MBR:

Memilih semua yang ada di dalam kotak (#0 dari bawah) (kotak #1, #2, segitiga #4)

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

Memilih semua yang benar-benar berada di dalam persegi (#0 dari bawah) dan tidak membagi tepi (persegi #2, segitiga #4)

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

Sunting #2:

Tambahan yang sangat bagus dari @StephanB (SQL fiddle )

Pilih objek yang tumpang tindih

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
;

(perhatikan saja, bahwa Anda harus menghapus AND s1.id < s2.id jika Anda bekerja dengan CONTAINS , sebagai CONTAINS(a,b) <> CONTAINS(b,a) while Intersects(a,b) = Intersects(b,a) )

Pada gambar berikut (daftar tidak lengkap):

  • 2 berpotongan #6.

  • 6 berpotongan #2

  • 0 berpotongan #1, #2, #3, #4, #5

  • 1 berpotongan #0, #5

  • 0 berisi #1, #3, #4 dan #5 (#1, #3, #4 dan #5 berada dalam #0)

  • 1 berisi #5 (#5 ada di dalam #1)

  • 0 st_contains #3, #4 dan #5

  • 1 st_contains #5

Edit #3:Mencari berdasarkan jarak/Bekerja di (dengan) lingkaran

MySQL tidak secara langsung mendukung lingkaran sebagai geometri, tetapi Anda dapat menggunakan fungsi spasial Buffer(geometry,distance) untuk bekerja di sekitarnya. Apa Buffer() tidak, adalah menciptakan penyangga jarak tersebut di sekitar geometri. Jika Anda mulai dengan titik geometri, buffernya memang lingkaran.

Anda dapat melihat apa yang sebenarnya dilakukan buffer dengan hanya memanggil:

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

(hasilnya cukup panjang, jadi saya tidak akan mempostingnya di sini) Ini sebenarnya membuat poligon yang mewakili buffer - dalam hal ini (dan MariaDB saya) hasilnya adalah poligon 126 titik, yang kira-kira lingkaran. Dengan poligon seperti itu Anda dapat bekerja seperti Anda bekerja dengan poligon lainnya. Jadi seharusnya tidak ada penalti kinerja.

Jadi jika Anda ingin memilih semua poligon yang termasuk dalam lingkaran Anda dapat membilas dan mengulangi contoh sebelumnya (ini hanya akan menemukan kotak #3)

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

Pilih semua poligon yang berpotongan dengan lingkaran

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

Saat bekerja dengan bentuk yang berbeda dari persegi panjang, Anda harus menggunakan ST_* fungsi. Fungsi tanpa ST_ menggunakan persegi panjang pembatas. Jadi contoh sebelumnya memilih segitiga #4 meskipun tidak berada di dalam lingkaran.

Sebagai Buffer() membuat poligon yang cukup besar, pasti akan ada penalti kinerja jika menggunakan ST_Distance() metode. Sayangnya saya tidak bisa menghitungnya. Anda harus melakukan beberapa benchmarking.

Cara lain untuk menemukan objek berdasarkan jarak adalah menggunakan ST_Distance() fungsi.

Pilih semua elemen dari tabel dan hitung jaraknya dari titik POINT(6 15)

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

Anda dapat menggunakan ST_Distance di WHERE klausa juga.

Pilih semua elemen yang jaraknya dari POINT(0 0) kurang atau sama dengan 10 (pilih #1, #2 dan #3)

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

Padahal jarak dihitung dari titik terdekat ke titik terdekat. Membuatnya mirip dengan ST_Intersect . Jadi contoh di atas akan memilih #2 meskipun tidak sepenuhnya muat di dalam lingkaran.

Dan ya, argumen kedua (0) untuk GeomFromText(text,srid) , tidak memainkan peran apa pun, Anda dapat mengabaikannya dengan aman. Saya telah mengambilnya dari beberapa sampel dan itu terjebak dalam jawaban saya. Saya telah meninggalkannya di suntingan saya nanti.

Omong-omong. phpMyAdmin dukungan untuk ekstensi spasial tidak sempurna, tetapi cukup membantu untuk melihat apa yang ada di database Anda. Membantu saya dengan gambar yang saya lampirkan ini.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apakah mungkin menggunakan perintah tipe LOAD DATA INFILE untuk MEMPERBARUI baris di db?

  2. Cara membuat daftar drop-down berjenjang menggunakan mysql dan php

  3. PILIH Data dari beberapa tabel?

  4. Mengapa STRAIGHT_JOIN meningkatkan kueri ini secara drastis, dan apa artinya jika ditulis setelah kata kunci SELECT?

  5. Bagaimana cara mengubah jenis mesin penyimpanan di MySQL?