Selecting a start line with where geom returns different geom - sql

I have a table with multilinestrings and I would like to find a line which starts at a certain point. I am using:
gis=> select * from (select gid, ST_StartPoint(ST_LineMerge((geom))) as start from aw_pipes) s where s.start = '0101000020E6100000D050E433E678D73F71F37608AF284A40' order by gid;
gid | start
------+----------------------------------------------------
1458 | 0101000020E6100000809BB933E678D73FE3D07608AF284A40
(1 row)
The problem here is the result has different geom. It is not what I asked for. It doesn't event contain the geom I was searching for.
gis=> select geom from aw_pipes where gid = 1458;
geom
--------------------------------------------------------------------------------------------------------------
0105000020E610000001000000010200000002000000809BB933E678D73FE3D07608AF284A40CDD4B35E4E7BD73F62DB7D83AD284A40
(1 row)
gis=> select ST_DumpPoints('0105000020E610000001000000010200000002000000809BB933E678D73FE3D07608AF284A40CDD4B35E4E7BD73F62DB7D83AD284A40');
st_dumppoints
--------------------------------------------------------------
("{1,1}",0101000020E6100000809BB933E678D73FE3D07608AF284A40)
("{1,2}",0101000020E6100000CDD4B35E4E7BD73F62DB7D83AD284A40)
(2 rows)
My postgis version is:
gis=> select PostGIS_Version ();
postgis_version
---------------------------------------
2.3 USE_GEOS=1 USE_PROJ=1 USE_STATS=1
Any idea what I am doing wrong or any suggestion what I may change in my query?

Comparing geometries using = might not lead to the result you would expect. Before PostGIS 2.4, the equality is based on the geometry bounding box, not on the vertices themselves, and likely truncate insignificant digits. Check this excellent article.
You could replace = by ST_Equals, which checks every vertices for exact spatial equality.
That being said, your expectations might be a bit too high. The distance between your geometry and the line starting point is 1.266e-005 m, so about 10 micrometers... most GIS user/software would consider the two points as being equal.

Related

Use bounding box from PostGIS in vanilla Postgres query

I have a db structure that is vanilla Postgres:
CREATE TABLE IF NOT EXISTS locations (
name text NOT NULL,
lat double precision NOT NULL,
lng double precision NOT NULL,
);
CREATE INDEX ON locations(lat,lng);
When I want to calculate all locations in a bounding box where I have the lower left and upper right corners I use the following query:
SELECT * FROM locations
WHERE lat >= min_lat AND
WHERE lat <= max_lat AND
WHERE lng >= min_lng AND
WHERE lng <= max_lng;
Now, I want to generate a bounding box given a point and use the bounding box result in the locations query. I'm using the following PostGIS query to generate a bounding box:
SELECT
ST_Extent(
ST_Envelope(
ST_Rotate(
ST_Buffer(
ST_GeomFromText('POINT (-87.6297982 41.8781136)',4326)::GEOGRAPHY,160934)::GEOMETRY,0)));
Result: BOX(-89.568160053866 40.4285062983089,-85.6903925527536 43.3273499289221)
However, I'm not sure how use the results from the PostGIS query bounding box into the vanilla lat / lng Postgres query in one call. Any ideas on how to merge the two? Preferably such that the index is preserved.
If you want to get the bbox coordinates as separated values you might wanna take a look at ST_XMax, ST_YMax, ST_XMin, ST_YMin. The following CTE, that embeds your query, should give you an idea:
WITH j (geom) AS (
SELECT
ST_Extent(ST_Envelope(
ST_Rotate(ST_Buffer(
ST_GeomFromText('POINT(-87.6297982 41.8781136)',4326)::GEOGRAPHY,160934)::GEOMETRY,0)))
)
SELECT
ST_XMax(geom),ST_YMax(geom),
ST_XMin(geom),ST_YMin(geom)
FROM j
st_xmax | st_ymax | st_xmin | st_ymin
-------------------+-----------------+-------------------+------------------
-85.6903925527536 | 43.327349928921 | -89.5681600538661 | 40.4285062983098
Side note: Storing geometry values as numbers might look straightforward but it is hardly ever the better choice - specially when dealing with polygons! So I would really suggest you to store these values as geometry or geography, which might seem complex at first a glance but definitely pays off on the long run.
This answer might shed a light on distance/containment queries involving polygons: Getting all Buildings in range of 5 miles from specified coordinates

PostGIS query to Select all Polygons from Polygon table having an intersecting geometry with one or more point in passed list of GeoCoordinates

I have a polygons table in Postgres (using PostGIS extension) named polygon having two fields (geom, id).
If I want to query the id of the polygon which intersects with the geometry of input geo-coordinate then I can do it with the below query.
SELECT id, geom
FROM polygon
WHERE ST_Intersects(polygon.%s, ST_GeometryFromText(POINT(latitude logitude), 4326));
But now I have a use case where I am getting a lot of geo-coordinates in request(~60k), now I am breaking this into lists of 1k Geo-coordinate each and querying the id of the polygon intersecting with each geo-coordinate.
I am struggling with how to write. a query for this, or if anyone has a better solution for this please suggest.
Keep in mind that the right order of coordinate pairs is lon, lat, so creating a point with lat, lon in your query will return wrong results. Your query also misses the single quotes ' around the WKT coordinate, e.g. 'POINT(1 2)'.
That all being said, you could simply paginate your result sets using ORDER BY, LIMIT and OFFSET, e.g.
Getting the first 1000 records
SELECT id, geom FROM polygon
WHERE ST_Intersects(geom, 'SRID=4326;POINT(1 2)')
ORDER BY id
LIMIT 1000 OFFSET 0;
By changing the OFFSET value you are able to retrieve the next pages.
LIMIT 1000 OFFSET 1000;
and so on ..
LIMIT 1000 OFFSET 2000;
EDIT: One way to apply this query using multiple input points is to use a CTE / subquery (see comments), e.g.
WITH j(g) AS (
VALUES
('SRID=4326;POINT(1 1)'),
('SRID=4326;POINT(1 2)')
-- ... add as many geometries as you want
)
SELECT id, geom FROM polygon, j
WHERE ST_Intersects(geom, g::geometry)

How to get the intersection length of touching geometries with ST_Touches

I am trying to develop a query in Postgis, where it can solve this problem:
I have a geometry and I wanna know which of the polygons that touches it, there is the highest contact area of this geometry. After I recognize this polygon I will take its value in a specific column and put this value in the same column but in my geometry.
Someone know how can I do that? I am a new user in postgresql/postgis.
As pointed out by #JGH in the comments, the overlapping area will be zero if you use ST_Touches alone. What you can do is to filter out only the geometries that do touch your reference geometry and then use ST_Intersection to get the intersection area, so that you can finally calculate the length of the intersection with ST_Length.
Data Sample
The geometry values depicted above are inside the CTE:
WITH j (id,geom) AS (
VALUES
(1,'POLYGON((-4.64 54.19,-4.59 54.19,-4.59 54.17,-4.64 54.17,-4.64 54.19))'),
(2,'POLYGON((-4.59 54.19,-4.56 54.19,-4.56 54.17,-4.59 54.17,-4.59 54.19))'),
(3,'LINESTRING(-4.65 54.19,-4.57 54.21)'),
(4,'POLYGON((-4.66 54.21,-4.60 54.21,-4.60 54.20,-4.66 54.20,-4.66 54.21))'),
(5,'POINT(-4.57 54.20)')
)
SELECT
id,
ST_Length(
ST_Intersection(
geom,
'POLYGON((-4.62 54.22,-4.58 54.22,-4.58 54.19,
-4.62 54.19,-4.62 54.22))')) AS touch_length
FROM j
WHERE
ST_Touches(
geom,
'POLYGON((-4.62 54.22,-4.58 54.22,-4.58 54.19,
-4.62 54.19,-4.62 54.22))')
ORDER BY touch_length DESC
LIMIT 1;
id | touch_length
----+---------------------
1 | 0.03000000000000025
(1 Zeile)

Need polygon intersect counts with buffered polygon neighbors FOR EACH polygon

I'm trying to find whether its possible in purely SQL to generate a table with the number of intersects each polygon in a layer has with its corresponding neighboring polygons(buffered) in a buffered version of the layer.
A rough and flawed version is the following:
For each value in list:
SELECT
Count(*)
INTO
intersectcounts
FROM
parcels,parcelsbuffered
WHERE
parcels.apn = value AND ST_INTERSECT(parcels.geom,parcelsbuffered.geom)
Here the geom is the polygon
I need as result like
intersectscount table
APN COUNT
100 3
101 87
...
...
I could use python loop and modify the query string with a different value in the WHERE clause but I dont think this will have good performance - there are thousands of parcels(polygons)
SELECT parcels.apn, count(*) as intersectcounts
FROM parcels
JOIN parcelsbuffered
ON ST_INTERSECT(parcels.geom, parcelsbuffered.geom)
GROUP BY parcels.apn
You probably want include some validation to remove the parcel intersect with his own buffered version like
(count(*) - 1) as intersectcounts
or
WHERE parcerls.apn <> parcelsbuffered.apn

Finding the pair of points whose distance from each other is maximal

I have a very small database which includes 6 points, with those columns id, the_geom, descr. And my aim to write a PL/pgSQL function which finds the the pair of points whose distance from each other is maximal. As an output, I would like to show the id or descr of two points and also the distance between them.
I have tried to do a function with returns table but setof text would be better solution?
You may try something like a cross join to find all combinations, then order by the difference. If your table name was foo something similar to:
SELECT set1.id, set2.id, abs(set1.the_geom - set2.the_geom) --- May want to use earth_distance extension ehre
FROM foo set1, foo set2
WHERE set1.id != set2.id
ORDER BY 3 DESC;
And if you need earth distance to calculate the distance itself - http://www.postgresql.org/docs/9.3/static/earthdistance.html