sql >> Database teknologi >  >> RDS >> Mysql

Hvordan kan jeg håndtere MySQL polygon overlapningsforespørgsler?

SQL violin

Opret tabel med polygonkolonne

Bemærk venligst, at for at bruge rumlige indekser, kan du ikke bruge InnoDB. Du kan bruge geometrien uden rumlige indekser, men ydeevnen forringes som normalt.

OPRET TABEL, HVIS IKKE FINDER `spatial` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `poly` geometri NOT NULL, UNIQUE KEY `id` (`id`), SPATIAL INDEX `poly` (`poly`)) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

Få 3 firkanter og en trekant indsat

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

Vælg alt, der skærer en lille firkant i nederste venstre hjørne (lilla firkant #1)

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

Vælg alt, der skærer trekanten fra nederste venstre til nederste højre hjørne til øverste højre hjørne) (firkanter #1 og #2 og trekant #4.)

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

Vælger alt i kvadrat, der er uden for vores billede (intet)

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

Rediger nr. 1:

Jeg genlæste spørgsmålet, og jeg tror, ​​du har de rumlige forhold lidt forvirret. Hvis det, du vil, er at finde alt, der passer helt inde i en firkant (polygon), så skal du bruge Contains/ST_Contains. Se venligst rumlige funktioner i MySQL-dokumentationen for at finde ud af, hvilken funktion der gør jobbet for dig. Bemærk venligst følgende forskel mellem ST/MBR-funktioner:

Vælger alt, der er helt inde i en firkant (#0 nedefra) (firkanter #1, #2, trekant #4)

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

Vælger alt, der er helt inde i en firkant (#0 nedefra) og deler ingen kanter (firkant #2, trekant #4)

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

Rediger #2:

Meget flot tilføjelse fra @StephanB (SQL violin )

Vælg eventuelle overlappende objekter

VÆLG s1.id,AsText(s1.poly), s2.id, AsText(s2.poly)FRA `spatial` s1, `spatial` s2 WHERE ST_Skærer(s1.poly, s2.poly) OG s1.id  

(bare bemærk, at du skal fjerne AND s1.id hvis du arbejder med CONTAINS , som CONTAINS(a,b) <> CONTAINS(b,a) mens Skærer(a,b) =Skærer(b,a) )

På det følgende billede (ikke-udtømmende liste):

  • 2 skærer #6.

  • 6 skærer #2

  • 0 skærer #1, #2, #3, #4, #5

  • 1 skærer #0, #5

  • 0 indeholder #1, #3, #4 og #5 (#1, #3, #4 og #5 er inden for #0)

  • 1 indeholder #5 (#5 er inden for #1)

  • 0 st_indeholder #3, #4 og #5

  • 1 st_indeholder #5

Rediger #3:Søgning efter afstand/Arbejde i (med) cirkler

MySQL understøtter ikke direkte cirkel som en geometri, men du kan bruge rumlig funktion Buffer(geometri,afstand) at arbejde uden om det. Hvad Buffer() gør, er at skabe en buffer af nævnte afstand omkring geometri. Hvis du starter med geometripunkt, er bufferen faktisk en cirkel.

Du kan se, hvad buffer rent faktisk gør ved blot at kalde:

VÆLG ASTEXT(BUFFER(GEOMFROMTEXT('POINT(5 5)'),3)) 

(Resultatet er ret langt, så jeg vil ikke poste det her) Det opretter faktisk polygon, som repræsenterer bufferen - i dette tilfælde (og min MariaDB) er resultatet en 126-punkts polygon, som nærmer sig en cirkel. Med sådan en polygon kan du arbejde, som du ville arbejde med enhver anden polygon. Så der bør ikke være nogen præstationsstraf.

Så hvis du vil vælge alle polygoner, der falder ind i en cirkel du kan skylle og gentage forrige eksempel (dette finder kun firkanten #3)

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

Vælg alle polygoner, der skærer en cirkel

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

Når du arbejder med former, der er forskellige fra rektangler, skal du bruge ST_* funktioner. Fungerer uden ST_ brug et afgrænsende rektangel. Så det forrige eksempel vælger trekanten #4, selvom den ikke er i cirklen.

Som Buffer() skaber ret store polygoner, vil der helt sikkert være en præstationsstraf over at bruge ST_Distance() metode. Jeg kan desværre ikke sætte tal på det. Du bliver nødt til at lave nogle benchmarking.

En anden måde at finde objekter efter afstand er at bruge ST_Distance() fungere.

Vælg alle elementer fra tabellen og udregn deres afstand fra punktet PUNKT(6 15)

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

Du kan bruge ST_Distance i Hvor klausul også.

Vælg alle elementer, hvis afstand fra POINT(0 0) er mindre eller lig med 10 (vælger #1, #2 og #3)

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

Selvom afstanden er beregnet fra nærmeste punkt til nærmeste punkt. Gør det ligner ST_Intersect . Så ovenstående eksempel vil vælge #2, selvom det ikke passer helt inde i cirklen.

Og ja, det andet argument (0) for GeomFromText(text,srid) , ikke spiller nogen rolle, kan du roligt ignorere det. Jeg har hentet det fra en prøve, og det sad lidt fast i mit svar. Jeg har udeladt det i mine senere redigeringer.

btw. phpMyAdmin understøttelse af rumlig udvidelse er ikke fejlfri, men det hjælper en del at se, hvad der er i din database. Hjælp mig med disse billeder, jeg har vedhæftet.




  1. Sikkerhedskopier en SQLite-database

  2. Laravel join med 3 borde

  3. SQL Server - opret forbindelse med Windows-godkendelse

  4. SQL Server streng til dato konvertering