While converting from MySQL 5.5 to PostgreSQL 9.4, I've had problems with this query:
SELECT *, GCDist(?, ?, lat, lon) AS dist
FROM ads
HAVING dist < radius
ORDER BY date_created DESC
LIMIT ?;
where GCDist
computes the great-circle distance between two points.
Without the HAVING
clause, the query works fine on the Postgres, but if I want to filter out the rows with dist > radius
I receive this error:
ERROR: column "dist" does not exist
LINE 1: ...*, GCDist(0, 0, lat, lon) AS dist FROM ads HAVING dist < 100...
Is it possible to use the output of a function in the HAVING
clause of a query in PostgresSQL 9.4? If so, how?
Thank you in advance for any hint.
Here's how to reproduce the error:
CREATE FUNCTION GCDist (
_lat1 FLOAT, -- Scaled Degrees north for one point
_lon1 FLOAT, -- Scaled Degrees west for one point
_lat2 FLOAT, -- other point
_lon2 FLOAT
) RETURNS FLOAT
IMMUTABLE AS
$$
-- Hardcoded constant:
DECLARE
_deg2km FLOAT DEFAULT 0.0111325;
_deg2rad FLOAT DEFAULT PI()/1800000; -- For scaled by 1e4 to MEDIUMINT
_rlat1 FLOAT DEFAULT _deg2rad * _lat1;
_rlat2 FLOAT DEFAULT _deg2rad * _lat2;
-- compute as if earth's radius = 1.0
_rlond FLOAT DEFAULT _deg2rad * (_lon1 - _lon2);
_m FLOAT DEFAULT COS(_rlat2);
_x FLOAT DEFAULT COS(_rlat1) - _m * COS(_rlond);
_y FLOAT DEFAULT _m * SIN(_rlond);
_z FLOAT DEFAULT SIN(_rlat1) - SIN(_rlat2);
_n FLOAT DEFAULT SQRT(_x * _x + _y * _y + _z * _z);
BEGIN
RETURN _deg2km * 2 * ASIN(_n / 2) / _deg2rad; -- again--scaled degrees
END;
$$
LANGUAGE plpgsql;
CREATE TABLE test (id SERIAL PRIMARY KEY, lat INTEGER NOT NULL, lon INTEGER NOT NULL);
INSERT INTO test (id, lat, lon) VALUES (DEFAULT, 10000, 10000);
INSERT INTO test (id, lat, lon) VALUES (DEFAULT, 20000, 20000);
INSERT INTO test (id, lat, lon) VALUES (DEFAULT, 50000, 50000);
SELECT *, GCDist(0, 0, lat, lon) AS dist FROM test HAVING dist < 200;
The output table on MySQL would be similar to the following:
id | lat | lon | dist
---+-----+-----+------
1 |10000|10000|157.43