Mysql
 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 , като 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_съдържа #3, #4 и #5

  • 1 st_съдържа #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, въпреки че не се вписва изцяло в кръга.

И да, вторият аргумент (0) за GeomFromText(text,srid) , не играе никаква роля, можете спокойно да го игнорирате. Взех го от някаква извадка и някак си остана в отговора ми. Пропуснах го в по-късните си редакции.

между другото phpMyAdmin поддръжката за пространствено разширение не е безупречна, но помага доста да видите какво има във вашата база данни. Помогна ми с тези изображения, които съм приложил.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Архивирайте MySQL база данни с CodeIgniter

  2. Сумиране на редове от различни условия в Mysql

  3. Проблем с Python:Не може да се намери vcvarsall.bat

  4. Използване на MySQLi от друг клас в PHP

  5. MySqlCommand().ExecuteReader().GetString() не работи