简体   繁体   中英

Postgresql Postgis SQL Complex Join (not necessarily GIS related however)

Sorry about the lack-lustre title, but it's hard to describe...

Lets, just say I have two tables (cad and cad_polygon)...

cad and cad_polygon share the same column that relates to one-another (cad_pid)...

cad has these columns: cad_pid, jrsdctn_id

while, cad_polygon has these columns: cad_pid, ogc_fid, wkb_geometry

Now, the below query I have working (half the day trying) selects a parcel based on degree from a long,lat co-ord, from that significantly smaller subset of polygons, it finds their distance in metres from the given long,lat co-ord, then displays only polygons who's centroid is within 500m of the long,lat co-ord.

SELECT SUBQUERY.cad_pid, SUBQUERY.ogc_fid, SUBQUERY.dist_meters,
    SUBQUERY.wkb_geometry FROM (
    SELECT cad_pid, ogc_fid,
    CAST(ST_Distance_Sphere(
        ST_Centroid(wkb_geometry),
            ST_GeomFromText(
                'POINT(00.0000 -00.0000)',
            900914)
        ) AS numeric
    ) AS dist_meters, wkb_geometry
    FROM cad_polygon
    WHERE ST_DWithin(
        ST_Centroid(wkb_geometry),
        ST_GeomFromText(
            'POINT(00.0000 -00.0000)',
        900914),
    0.01)
    ORDER BY dist_meters ASC
) AS SUBQUERY
WHERE SUBQUERY.dist_meters < 500;

I want to add to this and using the list that this query spits out, join my other table (cad) so I can give the additional column "jrsdctn_id" for each resulting row... ie:

Sample data would be: cad:

cad_pid | jrsdctn_id
0001    | abc123
0002    | def456
0003    | dhk778
0004    | dsk730


cad_polygon:

cad_pid | ogc_fid | wkb_geometry
0001    | ht0101  | 67686687601010000200063D7987FF15ASD1518541DAW
0002    | hz4561  | 435453457601010000200063D7987FF15ASDFW4GF8DE4
0003    | yv0301  | 2626WD687601010000200063D7987FF15ASD1WE851D4D
0004    | vt9701  | D484DW4D8441D8W1C684V63D7987FF15ASD1D7DW4848D

Expected results:

cad_pid | jtsdctn_id | ogc_fid | dist_meters | wkb_geometry
0002    | def456     | hz4561  | 192.769     | 43545...
0004    | dsk730     | vt9701  | 342.548     | D484D...

If some sql wizard out there can help would be great!

A bit late, and the accepted answer is absolutely correct about the JOIN , of course, but this actually is significantly GIS related, and it's awareness ultimately makes things easier for you:

You seem to be either using a custom CRS or ogr2ogr (or any GDAL/OGR function) didn't find a matching SRID/projection in PostGIS' spatial_ref_sys table; any PostGIS function using LonLat's as input for spherical/shperoidal algebra, however, will always assume your coordinates are in EPSG:4326 (WGS84).

If your LonLat's do not exactly match with those of WGS84, the results will be off!

Now, PostGIS also has the geography type, which again assumes EPSG:4326 coordinates, that will, if used with those functions, implicitly use meter as units and will be calculated on the WGS84 spheroid if used with the default ST_Distance parameters (more precise but slightly slower than with use_spheroid := false , which will calculate distance based on a sphere instead).

With this in mind, your query can be expressed as:

WITH
  pt AS (
    SELECT ST_Transform(ST_SetSRID(ST_MakePoint(0, 0), 900914), 4326)::geography AS geog
  ),

  ctr AS (
    SELECT *,
           ST_Transform(ST_Centroid(wkt_geometry), 4326)::geography AS geog
    FROM cad_polygon
  )

SELECT ctr.cad_pid,
       cad.jtsdctn_id,
       ctr.ogr_fid,
       ST_Distance(ctr.geog, pt.geog) AS distance_meter,
       ctr.wkt_geometry
FROM ctr
JOIN cad
  ON ctr.cad_pid = cad.cad_pid
WHERE ST_DWithin(ctr.geog, pt.geog, 500)
ORDER BY distance_meter ASC;

Note the use of CTEs to avoid transformation/casting for each processed row, and to make things more structured.

I just couldn't let this go...

You could use a JOIN

    SELECT SUBQUERY.cad_pid, SUBQUERY.ogc_fid, SUBQUERY.dist_meters,
        SUBQUERY.wkb_geometry, SUBQUERY.jrsdctn_id FROM (
        SELECT cad_pid, ogc_fid,
        CAST(ST_Distance_Sphere(
            ST_Centroid(wkb_geometry),
                ST_GeomFromText(
                    'POINT(00.0000 -00.0000)',
                900914)
            ) AS numeric
        ) AS dist_meters, wkb_geometry, cad.jrsdctn_id
        FROM cad_polygon
        INNER JOIN cad on cad.cad_pid = cad_polygon.cad_pid

        WHERE ST_DWithin(
            ST_Centroid(wkb_geometry),
            ST_GeomFromText(
                'POINT(00.0000 -00.0000)',
            900914),
        0.01)
        ORDER BY dist_meters ASC
    ) AS SUBQUERY
    WHERE SUBQUERY.dist_meters < 500;

or better add the join in the outer

SELECT SUBQUERY.cad_pid
        , SUBQUERY.ogc_fid
        , SUBQUERY.dist_meters,
        SUBQUERY.wkb_geometry, cad.jrsdctn_id 
    FROM (
        SELECT cad_polygon.cad_pid, ogc_fid,
        CAST(ST_Distance_Sphere(
            ST_Centroid(wkb_geometry),
                ST_GeomFromText(
                    'POINT(00.0000 -00.0000)',
                900914)
            ) AS numeric
        ) AS dist_meters
        , wkb_geometry
        FROM cad_polygon
        WHERE ST_DWithin(
            ST_Centroid(wkb_geometry),
            ST_GeomFromText(
                'POINT(00.0000 -00.0000)',
            900914),
        0.01)
        ORDER BY dist_meters ASC
    ) AS SUBQUERY
    INNER JOIN cad on cad.cad_pid = SUBQUERY.cad_pid
    WHERE SUBQUERY.dist_meters < 500;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM