如何在HAVING子句中使用函数的输出?

时间:2015-07-10 19:34:42

标签: sql postgresql postgresql-9.4

从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过滤掉行,则会收到此错误:

  

错误:列&#34; dist&#34;不存在   第1行:... *,GCDist(0,0,lat,lon)AS dist from ads HAVING dist&lt; 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上的输出表类似于以下内容:

id | lat | lon | dist
---+-----+-----+------
1  |10000|10000|157.43

2 个答案:

答案 0 :(得分:3)

由于您没有使用group by,因此首先没有用(和错误),在这种情况下您应该使用where子句。

要访问where子句中的列别名,您需要将查询包装在派生表中:

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;

另见:

答案 1 :(得分:1)

  

是否可以在PostgresSQL 9.4中使用查询的HAVING子句中的函数输出?如果是这样,怎么样?

是,与WHERE子句相同。请参阅a-horse-no-name所示的两个解决方案中的第二个。