2015-07-10 75 views
0

雖然從MySQL 5.5轉換到PostgreSQL 9.4,我有問題,與此查詢:如何在HAVING子句中使用函數的輸出?

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...

是否可以使用函數的輸出在PostgreSQL 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 

回答

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; 

參見這裏:

+0

那麼,從我理解的情況來看,在MySQL中,區別在於執行順序(WHERE在函數執行之前選擇,而HAVING選擇之後),所以HAVING是唯一的方法。 關於你的第一個建議,是不是子查詢「昂貴」?我的意思是,爲什麼數據庫管理系統應該爲這個計算創建另一個表格,何時它可以簡單地附加這些值? (我不知道如何優化查詢,但基於語法,它似乎更慢) 關於你的第二個建議,'GCDist'會執行兩次嗎?因爲如果是這樣,我不能使用它。這個功能已經很慢了。 –

+0

@CarloVespa,你有沒有試過a_horse_with_no_name的解決方案?檢查執行時間。你會感到驚訝,因爲優化器比你想象的要好。 –

+0

@EmacsUser是的,我目前正在使用他的第一個解決方案。我知道優化器是好的,但對我來說,看起來很尷尬,所以你需要兩個'SELECT'來做這麼簡單的事情。 –

1

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子句。看到「無名無名」所示的兩種解決方案中的第二種。