operator does not exist: geography <-> geography - postgresql

I've postgresql column with type
geography(Point,4326)
And I've inserted some rows to it using
POINT(LONG LAT)
That data have been inserted successfully and I can retrieve it with no problems, now I want to get the nearest entries to a specific point using the following query
SELECT "cafes".* FROM "cafes" ORDER BY "latlng" <-> (SELECT latlng FROM cafes WHERE id = '3') LIMIT 1
But I'm getting the following error
ERROR: operator does not exist: geography <-> geography
LINE 1: ...es".* FROM "cafes" ORDER BY "latlng" <-> (SELEC...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.

The <-> "distance between" operator applies to PostgreSQL geometric data types, not to the PostGIS geography data type. With the geography data type you can use the PostGIS function ST_Distance() and find the minimum value.
WITH this_cafe (latlng) AS (
SELECT latlng FROM cafes WHERE id = '3'
)
SELECT cafes.*, ST_Distance(cafes.latlng, this_cafe.latlng, 'false') AS dist
FROM cafes, this_cafe
ORDER BY dist ASC
LIMIT 1
Note that the third argument useSpheroid to the function is set to false which will make the function much faster. It is unlikely going to affect the result because cafes tend to lie close to each other.
This assumes that there is only 1 cafe with id = 3. If there could be more, then restrict the CTE to return just 1 row.

Related

How to fix 'BOOM! Could not generate outside point' error when using ST_Distance_Spheroid with different SRS in PostGIS

I am trying to calculate the nearest feature distance from a point using PostGIS ST_Distance_Spheroid function.
Case 1:
The point and the feature collection are in the same SRS and I am expecting the distance to be in meters.
Here is my query:
SELECT
name,
ST_DistanceSpheroid(geom, ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 'SPHEROID["WGS 84",6378137,298.257223563]' ) AS distance_m
FROM green_belt
ORDER BY geom <-> ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326)
LIMIT 1;
The above query is working as expected. Here is the result:
Case 2:
When the SRS are different for the point and the feature collection, I am using the below query:
SELECT
name,
ST_DistanceSpheroid(geom, ST_Transform(ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 27700), 'SPHEROID["WGS 84",6378137,298.257223563]' ) AS distance_m
FROM aonb
ORDER BY geom <-> ST_Transform(ST_GeomFromText('POINT(-2.0363502486833616 52.688988284010456)', 4326), 27700)
LIMIT 1;
But in this case, I am getting an error:
ERROR: BOOM! Could not generate outside point!
CONTEXT: SQL function "st_distance_spheroid" statement 2
SQL state: XX000
I even tried by transforming the coordinates and use it in the first query to get the distance:
SELECT
name,
ST_DistanceSpheroid(geom, ST_GeomFromText('POINT(357980.44 331724.97)', 27700), 'SPHEROID["Airy 1830",6377563.396,299.3249646]' ) AS distance_m
FROM aonb
ORDER BY geom <-> ST_GeomFromText('POINT(357980.44 331724.97)', 27700) LIMIT 1;
Even with this query, I got the same error
ERROR: BOOM! Could not generate outside point!
SQL state: XX000

Update table with query gives me this error: ERROR: more than one row returned by a subquery used as an expression

I am new on Postgresql
I have the table "admins_polygons" where I have the column "_geometry" which has WKT values on it and I need to convert that WKT to geometry values on other column from the same table.
I already created the geometry column but when I try to use UPDATE to fill the rows with a CAST it gives me this error:
ERROR: more than one row returned by a subquery used as an expression
SQL state: 21000
This is my code so far
SELECT AddGeometryColumn ('admins_polygons', 'polygons', 4326, 'POLYGON', 2)
SELECT admins_polygons._geometry
FROM admins_polygons
SELECT CAST (admins_polygons._geometry AS GEOMETRY)
FROM admins_polygons
UPDATE admins_polygons SET
polygons = (SELECT CAST (admins_polygons._geometry AS GEOMETRY)
FROM admins_polygons)
You need to qualify the subquery further, preferably with a uniquely-constrained column, such that it only returns a single record.
Thankfully, you've already created this with such a key, namely the srid of the geometry column:
UPDATE admins_polygons SET
polygons =
(SELECT CAST(admins_polygons._geometry AS GEOMETRY)
FROM admins_polygons WHERE srid = 4326) WHERE srid = 4326 ;
or, equivalently
UPDATE admins_polygons SET
polygons = CAST(admins_polygons._geometry AS GEOMETRY)
WHERE srid = 4326 ;
which ought to yield the single-row result you're looking for for use in the SET assignment.
Note you'll likely want to include the last WHERE condition as well if you only want this one record to be updated.

input geometry has unkown(0) geometry (Although st_transform is used)

I have 2 tables:
A table with 3 fields:
id (text)
geom (geometry)
select ST_SRID(geom)
from A
where geom is not null
result: 32636
B table with 2 fields:
name (text)
geom (geometry)
select ST_SRID(geom)
from B
where geom is not null
result: 0
A.geom contains polygons
B.geom contains points
I want to get all the distances between A.id, A.geom and B.geom.
I tried with:
select id, st_distance(a.geom, ST_Transform(b.geom, 32636)) as dist
from A as a, B as b
where a.geom is not null
group by id, a.geom, b.geom
order by dist desc
But I'm getting error:
"input geom has unkown(0) SRID"
How can it be if I'm using ST_Transform ?
How can I fix it ?
The error message is talking about the SRID of the argument to ST_Transform, which is 0. The message means that the function has no idea in which coordinate system the point is, so it cannot transform it to another coordinate system.
The documentation says:
ST_Transform is often confused with ST_SetSRID. ST_Transform actually changes the coordinates of a geometry from one spatial reference system to another, while ST_SetSRID() simply changes the SRID identifier of the geometry.
That seems to be the case here.
You should probably use ST_SetSRID to interpret b.geom in SRID 32636.

Postgis nearest coordinates

I'm trying to make a REST service that returns a list of places ordered by distance from the user coordinate. I found this query using postgis:
SELECT *
FROM your_table
ORDER BY your_table.geom <-> "your location..."
LIMIT 5;
But I'm not able to apply this to my actual database. I have a table that contains these columns:
title, address, description, latitude, longitude
all these values as Strings.
I'll be very happy if someone help me. Thx!
I dont know why, but ORDER BY <-> isnt exact. Sometime the closest link is on the 3rd position. So I get 101 element and then use distance to selected the closest one.
CREATE OR REPLACE FUNCTION map.get_near_link(
x numeric,
y numeric)
RETURNS TABLE(Link_ID int, distance int) AS
$BODY$
DECLARE
strPoint text;
BEGIN
strPoint = 'POINT('|| X || ' ' || Y || ')';
With CTE AS (
SELECT Link_ID,
TRUNC(ST_Distance(ST_GeomFromText(strPoint,4326), geom )*100000)::integer as distance
FROM map.vzla_seg S
ORDER BY
geom <-> ST_GeomFromText(strPoint, 4326)
LIMIT 101
)
SELECT *
FROM CTE
ORDER BY distance
LIMIT 5
In order to use PostGIS you have to enable the extension in the database. Ideally, you just run the CREATE EXTENSION postgis; command and it works. NOTE form the install page: DO NOT INSTALL it in the database called postgres. For more information visit the site.
Adding a geometry column (spatial data can be stored in this type of columns) to your table:
SELECT AddGeometryColumn(
'your_schema',
'your_table',
'geom', -- name of the column
4326, -- SRID, for GPS coordinates you can use this, for more information https://en.wikipedia.org/wiki/Spatial_reference_system
'POINT', -- type of geometry eg. POINT, POLYGON etc.
2 -- number of dimension (2 xy - 3 xyz)
);
UPDATE yourtable t SET t.geom = ST_SetSRID(ST_MakePoint(t.x, t.y), 4326)
-- the x and y is the latitude and longitude
Now you can use spatial queries on your table like this:
SELECT
*
FROM
your_table
ORDER BY
your_table.geom <-> ST_SetSRID(ST_MakePoint(x, y), 4326)
LIMIT 5;
NOTE: as others mentioned, below PostgreSQL 9.5 <-> isn't always reliable.

Selecting and ordering by distance with GeoAlchemy2. Bad ST_AsBinary wrap

I'm trying to select and order stores by their distance to a point with GeoAlchemy2 / PostGIS but for some reason I keep getting an error.
It seems GeoAlchemy2 wraps things with ST_AsBinary, but when I try to select the distance it tries to wrap the result of the distance calculation. I have no idea how to fix this.
I use this ORM query.
distance = (
Store.coordinates.cast(Geometry)
.distance_centroid(query_centroid)
.label('distance')
)
stores = stores.order_by(distance).add_columns(distance)
The model.
class Store(db.Model):
__tablename__ = 'stores'
store_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
address_details = db.Column(db.String)
coordinates = db.Column(Geography('POINT'))
The error I get.
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) function st_asbinary(double precision) does not exist
LINE 1: ...Binary(stores.coordinates) AS stores_coordinates, ST_AsBinar...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
[SQL: 'SELECT stores.store_id AS stores_store_id,
stores.name AS stores_name,
stores.address_details AS stores_address_details,
ST_AsBinary(stores.coordinates) AS stores_coordinates,
ST_AsBinary(CAST(stores.coordinates AS geometry(GEOMETRY,-1)) <-> ST_GeomFromEWKT(%(param_1)s)) AS distance
FROM stores ORDER BY distance']13 -46.730347)'}]
[parameters: {'param_1': 'POINT(-23.3569
The problem is precisely in this part...
ST_AsBinary(
CAST(stores.coordinates AS geometry(GEOMETRY,-1))
<->
ST_GeomFromEWKT(%(param_1)s)
) AS distance
Notice how ST_AsBinary wraps the distance between the two points instead of wrapping just the geom, for example? (I'm not sure it should wrap the geom in this case, either)
Can anyone help? I just want to know how far things are.
An average user at freenode answered it for me.
GeoAlchemy2 will convert columns of type Geometry if they are in the select statement. Even though the result of the distance expression is a double, and not a Geometry, GeoAlchemy2 isn't smart enough to figure that out.
The column needs to be explicit cast in the ORM.
The fixed query:
distance = (
Store.coordinates.cast(Geometry)
.distance_centroid(query_centroid)
.cast(db.Float)
.label('distance')
)
stores = stores.order_by(distance).add_columns(distance)