web-dev-qa-db-fra.com

Problème Obtenir des zips dans le rayon via mysql

J'ai une table de codes postaux qui inclut le Centre Lat, GNL pour chaque code postal. Je l'utilise pour obtenir une liste de codes postaux dans un rayon de mile donné de tout point arbitraire.

Cela m'est venu que, juste parce que le point central d'un zip n'est pas dans un rayon donné, ne signifie pas que le zip lui-même n'est pas dans le rayon.

J'ai utilisé mes compétences d'art super avancées pour illustrer le point ici:

enter image description here

  • Les blobs à rayures verts représentent des codes postaux A, B et C.

  • Les taches rouges sont les centres géographiques de chaque code postal

  • Le point fuchsia est l'emplacement cible et ..

  • Le cercle bleu buminy est un rayon de 1 mile de l'emplacement cible

Si j'exécute une requête pour tous les codes zip dans un rayon de 1 mile à partir du macule rose, seuls les codes postaux B et C seront retournés comme le point central pour Zip A ne se situe pas dans le rayon d'un mile, même si le rose se macule. est clairement dans le code postal A.

SELECT *,
        p.distance_unit
                 * DEGREES(ACOS(COS(RADIANS(p.latpoint))
                 * COS(RADIANS(z.y))
                 * COS(RADIANS(p.longpoint) - RADIANS(z.x))
                 + SIN(RADIANS(p.latpoint))
                 * SIN(RADIANS(z.y)))) AS dist
  FROM standard_Zip AS z
  JOIN (   /* these are the query parameters */
        SELECT  $lat  AS latpoint,  $lng AS longpoint,
                $miles AS radius,      69 AS distance_unit
    ) AS p ON 1=1
  WHERE z.y
     BETWEEN p.latpoint  - (p.radius / p.distance_unit)
         AND p.latpoint  + (p.radius / p.distance_unit)
    AND z.x
     BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
         AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
  ORDER BY dist

Comment diable dois-je écrire une requête qui comprendra Zip A dans les résultats?

J'ai accès à spatial/géométrie pour chaque code postal que je peux ajouter à la table si nécessaire, mais je ne sais pas comment je l'utiliserais à cet effet dans MySQL.


Edit : J'ai passé une journée à lire les documents Oracle et MySQL pour des données spatiales et réussi à réussir convertir mes données spatiales en MySQL . Comment puis-je écrire une requête similaire qui utilise la colonne de géométrie au lieu du lat and Long? J'utilise des données 2D .. La géométrie est uniquement des polygones et des multiolygons ..

Je pense que je me suis trompé ..

select
  *
from
  (
    select
      MIN(st_distance(geom, POINT(-82.765136, 28.0914015))) * 69 as miles,
      Zip
    from
      Zip_spatial
    group by
      Zip
    order by
      miles asc
  ) d
where
  d.miles < 5

Je laisserai la prime ouverte pour l'instant au cas où quelqu'un a une solution meilleure et plus efficace.

À partir de indexation et interrogation des données spatiales dans Oracle dans le Guide du développeur de spatial Oracle® 11G, version 2 (11.2):

Querifier les données spatiales

Spatie utilise un modèle de requête à deux niveaux avec des opérations de filtrage primaire et secondaire pour résoudre les requêtes spatiales et les jointures spatiales. Le terme à deux niveaux indique que deux opérations distinctes sont effectuées pour résoudre les requêtes. Si les deux opérations sont effectuées, l'ensemble de résultats exact est renvoyé.

Vous ne pouvez pas ajouter un nom de lien de base de données (DLLINK) au nom d'une table spatiale dans une requête si un indice spatial est défini sur cette table.

Quere spatiale

Dans un indice spatial r-arbre, chaque géométrie est représentée par son rectangle de liaison minimum (MBR). Considérons la couche suivante contenant plusieurs objets de la figure1. Chaque objet est étiqueté avec son nom de géométrie (Geom_1 pour la chaîne de ligne, Geom_2 pour le polygone à quatre côtés, Geom_3 pour le polygone triangulaire et Geom_4 pour l'ellipse), et le MBR autour de chaque objet est représenté par une ligne pointillée.

Figure1 Geometries with MBRs

Description de "Figure1 Geométries avec MBRS"

Une requête spatiale typique consiste à demander tous les objets qui se trouvent dans une fenêtre de requête, c'est-à-dire une clôture ou une fenêtre définie. Une fenêtre de requête dynamique fait référence à une zone rectangulaire non définie dans la base de données, mais qui doit être définie avant qu'elle ne soit utilisée. La figure2 montre les mêmes géométries que sur la figure1, mais ajoute une fenêtre de requête représentée par la boîte à lignes en pointillés.

Figure2 Layer with a Query Window

Description de "Figure2 Couche avec une fenêtre de requête"

Sur la figure 2, la fenêtre de requête couvre des parties des géométries Geom_1 et Geom_2, ainsi que la partie du MBR pour Geom_3 mais aucune de la géométrie de Geom_3 réelle. La fenêtre de requête ne couvre aucune partie de la géométrie Geom_4 ou de son MBR.

Opérateur de filtre principal

L'opérateur SDO_FILTER met en œuvre la partie de filtrage principale du processus en deux étapes impliqué dans le modèle de traitement de la requête spatiale Oracle. Le filtre principal utilise les données d'index pour déterminer uniquement si un ensemble de paires d'objets candidats peut interagir. Plus précisément, le filtre principal vérifie si les MBRS des objets candidats interagissent, non pas si les objets eux-mêmes interagissent. La syntaxe de l'opérateur SDO_FILTER est la suivante:

SDO_FILTER(geometry1 SDO_GEOMETRY, geometry2 SDO_GEOMETRY, param VARCHAR2)

Dans la syntaxe précédente:

  • geometry1 est une colonne de type SDO_GEOMETRYRY dans une table. Cette colonne doit être indexée spatiale.

  • geometry2 est un objet de type SDO_GEOMETRYRY. Cet objet peut ou peut ne pas provenir d'une table. Si cela provient d'une table, elle peut ou non être indexée spatialement.

  • param est une chaîne optionnelle de type varchar2. Il peut spécifier des mots-clés MIN_RESOLUTION et MAX_RESOLUTION.

Les exemples suivants effectuent une opération de filtrage primaire uniquement (sans fonctionnement de filtre secondaire). Ils retourneront toutes les géométries illustrées à la figure2 qui ont un MBR qui interagit avec la fenêtre de la requête. Le résultat des exemples suivants sont les géométries Geom_1, Geom_2 et Geom_3.

Exemple1 effectue une opération de filtre primaire sans insérer la fenêtre de requête dans une table. La fenêtre sera indexée en mémoire et la performance sera très bonne.

Exemple1 filtre principal avec une fenêtre de requête temporaire

SELECT A.Feature_ID FROM TARGET A  WHERE sdo_filter(A.shape, SDO_geometry(2003,NULL,NULL,
                                       SDO_elem_info_array(1,1003,3),
                                       SDO_ordinate_array(x1,y1, x2,y2))
                           ) = 'TRUE';   

Dans l'exemple1, (x1, y1) et (x2, y2) sont les coins inférieurs gauche et droite de la fenêtre de requête.

7
l.lijith

Toute tentative d'inclure une volonté inclut probablement D, E, F, G. Le problème ne peut pas être résolu sans avoir un chemin exact définissant chaque zone de code postal.

Trouvez une telle base de données, puis de construire un index SPATIAL à l'aide de tels polygones arbitraires.

5
Rick James

Vous le faites mal. Tout d'abord, si possible, utilisez PostGis - qui est le principal RDMBS avec une solution spatiale.

Ensuite, vous voulez suivre ces étapes.

  1. Tirez sur les ZCTA (zones de tabulation de code postal) du jeu de données Tiger du recensement . Les codes postaux ne sont pas réellement connus pour certains. Officiellement, les codes postaux sont destinés à une utilisation interne par l'USPS uniquement. Parce que tout le monde les utilise, y compris le gouvernement, la deuxième source la plus faisant autorité est devenue les fichiers de formes de ZCTA.
  2. Importer ces fichiers de formes dans votre base de données, avec PostgreSQL, vous pouvez facilement utiliser shp2pgsql
  3. Indexez la géométrie que vous avez importée.

    CREATE INDEX ON census_zcta USING Gist (geog);
    ANALYZE census_zcta;
    
  4. Exécutez une requête de points d'intérêt (POI) contre les fichiers de formes. Le point d'intérêt dans votre cas est les cordons d'entrée, cela ressemblera à ceci,

    SELECT *
    FROM census_zcta AS zcta
      WHERE ST_Intersects( zcta, ST_MakePoint(long,lat)::geog );
    

ℹ 1609.344 mètres = 1 mile

Mysql

Avec mysql tu auras

  1. Utilisez OGR2OGR pour produire des relevés d'insertion MySQL pour le fichier de formes de recensement.
  2. Utilisez MBRIntersects Pour utiliser l'index spatial. La requête de fin devrait ressembler à quelque chose comme

    SELECT *
    FROM zcta
    WHERE MBRIntersects( geom, Point(long,lat) )
      AND ST_Intersects ( geom, Point(long,lat) );
    
3
Evan Carroll

Découvrez ce jeu de données à partir de GreatData.com (Notez que cela n'est pas open source, mais un service payant).

Ils utilisent la densité de population au lieu du centre de zip.

Et comment utiliser le type de données spatiales SQL Server pour obtenir des résultats corrects rapides.

J'espère que cela t'aides.

1
Matt McDonald