Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak mogę obsłużyć zapytania dotyczące nakładania się wielokątów MySQL?

Skrzypce SQL

Utwórz tabelę z kolumną wielokątną

Pamiętaj, że aby użyć indeksów przestrzennych, nie możesz użyć InnoDB. Możesz użyć geometrii bez indeksów przestrzennych, ale wydajność spada jak zwykle.

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;

Wstaw 3 kwadraty i trójkąt

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

Zaznacz wszystko, co przecina mały kwadrat w lewym dolnym rogu (fioletowy kwadrat #1)

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

Wybierz wszystko, co przecina trójkąt, od lewego dolnego do prawego dolnego narożnika do prawego górnego rogu) (kwadraty #1 i #2 oraz trójkąt #4.)

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

Zaznacza wszystko w kwadracie, co znajduje się poza naszym obrazem (nic)

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

Edytuj nr 1:

Ponownie przeczytałem pytanie i myślę, że masz trochę zamieszane relacje przestrzenne. Jeśli chcesz znaleźć wszystko, co mieści się w całości w kwadracie (wielokąt), musisz użyć opcji Contains/ST_Contains. Zobacz funkcje przestrzenne w dokumentacji MySQL aby dowiedzieć się, która funkcja spełnia Twoje zadanie. Zwróć uwagę na następującą różnicę między funkcjami ST/MBR:

Wybiera wszystko, co znajduje się w całości w kwadracie (nr 0 od dołu) (kwadraty #1, #2, trójkąt #4)

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

Zaznacza wszystko, co znajduje się w całości w kwadracie (nr 0 od dołu) i nie ma wspólnych krawędzi (kwadrat #2, trójkąt #4)

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

Edytuj nr 2:

Bardzo fajny dodatek od @StephanB (skrzypce SQL )

Zaznacz dowolne nakładające się obiekty

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
;

(pamiętaj, że powinieneś usunąć AND s1.id < s2.id jeśli pracujesz z CONTAINS , jako CONTAINS(a,b) <> CONTAINS(b,a) while Intersects(a,b) = Intersects(b,a) )

Na poniższym obrazku (lista nie jest wyczerpująca):

  • 2 przecięcia #6.

  • 6 przecina #2

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

  • 1 przecina #0, #5

  • 0 zawiera #1, #3, #4 i #5 (#1, #3, #4 i #5 mieszczą się w #0)

  • 1 zawiera #5 (#5 mieści się w #1)

  • 0 st_zawiera #3, #4 i #5

  • 1 st_zawiera #5

Edycja nr 3:Wyszukiwanie według odległości/Praca w kręgach (z)

MySQL nie obsługuje bezpośrednio okręgu jako geometrii, ale możesz użyć funkcji przestrzennej Buffer(geometry,distance) obejść to. Co Buffer() robi, tworzy bufor tej odległości wokół geometrii. Jeśli zaczniesz od punktu geometrycznego, bufor jest rzeczywiście okręgiem.

Możesz zobaczyć, co właściwie robi bufor, wywołując po prostu:

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

(wynik jest dość długi, więc nie będę go tutaj zamieszczać) W rzeczywistości tworzy wielokąt, który reprezentuje bufor - w tym przypadku (i mojej MariaDB) wynikiem jest wielokąt o długości 126 punktów, który przybliża okrąg. Z takim wielokątem możesz pracować tak, jak z każdym innym wielokątem. Więc nie powinno być żadnych spadków wydajności.

Więc jeśli chcesz zaznaczyć wszystkie wielokąty, które wpadają w okrąg możesz wypłukać i powtórzyć poprzedni przykład (zostanie wyświetlony tylko kwadrat #3)

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

Zaznacz wszystkie wielokąty przecinające się z okręgiem

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

Pracując z kształtami innymi niż prostokąty, powinieneś użyć ST_* Funkcje. Funkcje bez ST_ użyj prostokąta ograniczającego. Zatem w poprzednim przykładzie zaznaczono trójkąt #4, mimo że nie znajduje się on w okręgu.

Jako Buffer() tworzy dość duże wielokąty, na pewno nastąpi spadek wydajności w porównaniu z użyciem ST_Distance() metoda. Niestety nie potrafię tego określić ilościowo. Będziesz musiał przeprowadzić analizę porównawczą.

Innym sposobem znajdowania obiektów według odległości jest użycie ST_Distance() funkcjonować.

Wybierz wszystkie elementy z tabeli i oblicz ich odległość od punktu POINT(6 15)

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

Możesz użyć ST_Distance w WHERE również klauzulę.

Zaznacz wszystkie elementy, których odległość od POINT(0 0) jest mniejsza lub równa 10 (wybiera #1, #2 i #3)

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

Chociaż odległość jest obliczana od najbliższego punktu do najbliższego punktu. Uczynienie go podobnym do ST_Intersect . Tak więc powyższy przykład wybierze #2, mimo że nie mieści się w całości w okręgu.

I tak, drugi argument (0) dla GeomFromText(text,srid) , nie odgrywa żadnej roli, można to spokojnie zignorować. Wziąłem to z jakiejś próbki i utknąłem w mojej odpowiedzi. Pominąłem to w moich późniejszych edycjach.

przy okazji phpMyAdmin obsługa rozszerzenia przestrzennego nie jest bezbłędna, ale pomaga całkiem sporo zobaczyć, co znajduje się w Twojej bazie danych. Pomógł mi z załączonymi obrazami.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Różnica w miesiącach między datami w MySQL

  2. Sortowanie SQL nie odbywa się według instrukcji, zawsze używa klucza podstawowego

  3. Policz ile razy wartość pojawia się w danej kolumnie w MySQL

  4. Indeks daty i godziny Mysql nie działa podczas używania „lubię to”

  5. Uzyskiwanie dokładnego czasu wykonania instrukcji MySQL