How to create geoalchemy expression for a point geometry? - postgresql

I have a table with lat and long, i don't want to store geometry.
Instead i am storing lat and longs.
How to create point based queries using position expression? basically it should return point.
Which should be converted to SQL expression like ".....ST_Point(home.latitude, home.longitude)....."
There is no func.ST_Point in geoalchemy ? or am i missing something ?
if i dont write expression obviously i get
"sqlalchemy.exc.InternalError: (InternalError) parse error - invalid geometry
HINT: "POINT(Ve" <-- parse error at position 8 within geometry"
Code:
class Home(Base):
__tablename__ = 'vehicle_path'
id = Column(BigInteger, primary_key=True)
latitude = Column(Float)
longitude = Column(Float)
#hybrid_property
def position(self):
return WKTElement(
''.join(['POINT(', str(self.longitude),' ', str(self.latitude), ')']), 4326)
#position.expression
def position(cls):
return <???what to return???>
I am using sqlalchemy, Geoalchmey2 with postgis, postgres, pyramid.

It sounds like you are looking for WKTElement http://geoalchemy-2.readthedocs.org/en/latest/elements.html#geoalchemy2.elements.WKTElement There is an ST_MakePoint(x,y) function in Postgis, but not in Geoalchemy it would seem. As a matter of interest, why would you want to store latitude and longitude instead of a geometry (or Point in your case). You can easily recover the latitude and longitude from the geometry using ST_X(geom), ST_Y(geom), but more importantly you can put a spatial index on a geometry column, which will perform much better than two separate non-spatial columns for any kind of spatial queries.

Related

Indexing issue in postgres

It is impossible to speed up the database due to indexing.
I create a table:
CREATE TABLE IF NOT EXISTS coordinate( Id serial primary key,
Lat DECIMAL(9,6),
Lon DECIMAL(9,6));
After that I add indexing:
CREATE INDEX indeLat ON coordinate(Lat);
CREATE INDEX indeLon ON coordinate(Lon);
Then the table is filled in:
INSERT INTO coordinate (Lat, Lon) VALUES(48.685444, 44.474254);
Fill in 100k random coordinates.
Now I need to return all coordinates that are included in a radius of N km from a given coordinate.
SELECT id, Lat, Lon
FROM coordinate
WHERE acos(sin(radians(48.704578))*sin(radians(Lat)) + cos(radians(48.704578))*cos(radians(Lat))*cos(radians(Lon)-radians(44.507112))) * 6371 < 50;
The test execution time is approximately 0.2 seconds, and if you do not do CREATE INDEX, the time does not change. I suspect that there is an error in the request, maybe you need to rebuild it somehow?
I'm sorry for my english
An index can only be used if the indexed expression is exactly what you have on the non-constant side of the operator. That is obviously not the case here.
For operations like this, you need to use the PostGIS extension. Then you can define a table like:
CREATE TABLE coordinate (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
p geography NOT NULL
);
and query like this:
SELECT id, p
FROM coordinate
WHERE ST_DWithin(p, 'POINT(48.704578 44.507112)'::geography, 50);
This index would speed up the query:
CREATE INDEX ON coordinate USING gist (p);

Create new column with coordinates from centroids using st_transform in PostGIS / PostgreSQL

I have geometry data that I'm trying to transform to lon lat and store in a new column. I have created a new column called 'coordinates' and written the following query:
UPDATE places_centroids
SET coordinates = st_y(st_transform(new_centroid, 4326)) AS lat,
st_x(st_transform(new_centroid, 4326)) AS lon;
But it returns: ERROR: ERROR: syntax error at or near
LINE 2: ...coordinates = st_y(st_transform(new_centroid, 4326)) AS lat,
However, it works fine when i writing the query with a select statement:
SELECT st_y(st_transform(new_centroid, 4326)) AS lat,
st_x(st_transform(new_centroid, 4326)) AS lon
FROM places_centroids;
Can anyone see what's wrong with my query?
You can create two columns, lat and lng for example of type double precision and do this:
UPDATE places_centroids
SET lat = st_y(st_transform(new_centroid, 4326)),
lng= st_x(st_transform(new_centroid, 4326));
or define coordinates as the native point type:
UPDATE places_centroids
SET coordinates = point(st_y(st_transform(new_centroid, 4326)),
st_x(st_transform(new_centroid, 4326)));
I personally prefer to store in two columns.
Best regards,
Bjarni

How to make a GIS query on PostgreSQL without use ST_X("Position4326") function

I have written this geographical query:
SELECT
ST_X("Position4326") AS lon,
ST_Y("Position4326") AS lat,
"Values"[4] AS ppe,
"Values"[5] AS speed
FROM
(
SELECT
*
FROM
"SingleData"
UNION ALL
SELECT
*
FROM
"SingleDataOld"
) AS d
WHERE
"Values"[5] > 0
and its work.
But I would like to select a specific area in the database, e.g.:
Lat_min = 43.77;
Lat_max = 43.88;
Lon_min = 12.95;
Lon_max = 13.05;
to reduce the time of working.
It is possible do this without use ST_X and ST_Y function? Or, better: I would like use a WHERE clause, but the format of geographical data are Position4326, an alphanumeric string that I do not know how manipulate.
The format of position4326 could be of geometry type or geography type. Postgis offer a big range of functions which you can use to limit the result data improve the performance.
I.e. use can the function ST_MakeEnvelope and the && operator:
WHERE ...
AND Position4326 && ST_MakeEnvelope(xmin, ymin, xmax, ymax, srid);
in latitude/longitude terms, the arguments are so:
ST_MakeEnvelope(long_min, lat_min, long_max, lat_max, srid);
Because you column is named Position4326, I guess you should use srid = 4326.
ST_MakeEnvelope(12.95, 43.77, 13.05, 43.88, 4326);
Also ensure that you have a spatial index on the column Position4326:
CREATE INDEX Position4326_gix ON your_table USING GIST (Position4326);

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)

PostgreSQL select query to extract latitude and longitude from a point

What SELECT query should be used to extract latitude and longitude from a point?
I cannot use PostGIS.
Example point (point type value) stored in the database:
my_point
--------------
(50.850,4.383)
Expected result after executing the query:
lat | lng
---------------
50.850 | 4.383
The query below works fine but it does not look efficient.
SELECT
split_part(trim(my_point::text, '()'), ',', 1)::float AS lat,
split_part(trim(my_point::text, '()'), ',', 2)::float AS lng
FROM my_table;
Always Read The Fine Manuals
It is possible to access the two component numbers of a point as though the point were an array with indexes 0 and 1. For example, if t.p is a point column then SELECT p[0] FROM t retrieves the X coordinate and UPDATE t SET p1 = ... changes the Y coordinate. In the same way, a value of type box or lseg can be treated as an array of two point values.
Another option would be:
SELECT
ST_X(point) as longitude,
ST_Y(point) as latitude
FROM your_table_name