Създаване на таблица с многоъгълна колона
Моля, имайте предвид, че за да използвате пространствени индекси, не можете да използвате 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 поддръжката за пространствено разширение не е безупречна, но помага доста да видите какво има във вашата база данни. Помогна ми с тези изображения, които съм приложил.