如何在 HAVING 子句中使用函数的输出?
How can I use a function's output in HAVING clause?
从 MySQL 5.5 转换到 PostgreSQL 9.4 时,我遇到了以下查询的问题:
SELECT *, GCDist(?, ?, lat, lon) AS dist
FROM ads
HAVING dist < radius
ORDER BY date_created DESC
LIMIT ?;
其中 GCDist
计算两点之间的大圆距离。
没有 HAVING
子句,查询在 Postgres 上工作正常,但如果我想过滤掉带有 dist > radius
的行,我会收到此错误:
ERROR: column "dist" does not exist
LINE 1: ...*, GCDist(0, 0, lat, lon) AS dist FROM ads HAVING dist < 100...
是否可以在 PostgresSQL 9.4 的查询的 HAVING
子句中使用函数的输出?如果是,怎么做?
提前感谢您的任何提示。
重现错误的方法如下:
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;
MySQL 上的输出 table 类似于以下内容:
id | lat | lon | dist
---+-----+-----+------
1 |10000|10000|157.43
首先 having 是无用的(而且是错误的),因为您没有使用 group by
,在这种情况下您应该使用 where
子句。
要访问 where
子句中的列别名,您需要将查询包装在派生的 table:
select *
from (
SELECT *,
GCDist(0, 0, lat, lon) AS dist
FROM test
) t
where dist < 200;
或者只是重复表达
SELECT *, GCDist(0, 0, lat, lon) AS dist
FROM test
WHERE GCDist(0, 0, lat, lon) < 200;
另见此处:
- Using an Alias column in the where clause in Postgresql
- Logical Processing Order or SQL Standard in WHERE clause
Is it possible to use the output of a function in the HAVING clause of a query in PostgresSQL 9.4? If so, how?
是的,与 WHERE 子句中的相同。请参阅 a-horse-with-no-name 显示的两个解决方案中的第二个。
从 MySQL 5.5 转换到 PostgreSQL 9.4 时,我遇到了以下查询的问题:
SELECT *, GCDist(?, ?, lat, lon) AS dist
FROM ads
HAVING dist < radius
ORDER BY date_created DESC
LIMIT ?;
其中 GCDist
计算两点之间的大圆距离。
没有 HAVING
子句,查询在 Postgres 上工作正常,但如果我想过滤掉带有 dist > radius
的行,我会收到此错误:
ERROR: column "dist" does not exist
LINE 1: ...*, GCDist(0, 0, lat, lon) AS dist FROM ads HAVING dist < 100...
是否可以在 PostgresSQL 9.4 的查询的 HAVING
子句中使用函数的输出?如果是,怎么做?
提前感谢您的任何提示。
重现错误的方法如下:
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;
MySQL 上的输出 table 类似于以下内容:
id | lat | lon | dist
---+-----+-----+------
1 |10000|10000|157.43
首先 having 是无用的(而且是错误的),因为您没有使用 group by
,在这种情况下您应该使用 where
子句。
要访问 where
子句中的列别名,您需要将查询包装在派生的 table:
select *
from (
SELECT *,
GCDist(0, 0, lat, lon) AS dist
FROM test
) t
where dist < 200;
或者只是重复表达
SELECT *, GCDist(0, 0, lat, lon) AS dist
FROM test
WHERE GCDist(0, 0, lat, lon) < 200;
另见此处:
- Using an Alias column in the where clause in Postgresql
- Logical Processing Order or SQL Standard in WHERE clause
Is it possible to use the output of a function in the HAVING clause of a query in PostgresSQL 9.4? If so, how?
是的,与 WHERE 子句中的相同。请参阅 a-horse-with-no-name 显示的两个解决方案中的第二个。