2012-08-09 54 views
31

我正在PL/pgSQL中編寫一個函數,並且正在尋找最簡單的方法來檢查行是否存在。
現在我正在選擇一個integerboolean,這實際上並不奏效。我對PL/pgSQL沒有足夠的經驗,還沒有足夠的知道這樣做的最佳方式。PL/pgSQL檢查行是否存在

這是我的一部分功能:

DECLARE person_exists boolean; 
BEGIN 

person_exists := FALSE; 

SELECT "person_id" INTO person_exists 
    FROM "people" p 
WHERE p.person_id = my_person_id 
LIMIT 1; 

IF person_exists THEN 
    -- Do something 
END IF; 

END; $$ LANGUAGE plpgsql; 

更新 - 我在做這樣的事情現在:

DECLARE person_exists integer; 
BEGIN 

person_exists := 0; 

SELECT count("person_id") INTO person_exists 
    FROM "people" p 
WHERE p.person_id = my_person_id 
LIMIT 1; 

IF person_exists < 1 THEN 
    -- Do something 
END IF; 

回答

90

更簡單,更短,更快:EXISTS

IF EXISTS (SELECT 1 FROM people WHERE person_id = my_person_id) THEN 
    -- do something 
END IF; 

的查詢規劃可以停止在發現的第一行 - 而不是count(),它會掃描所有匹配的行不管。與大桌子有所不同。對於一個獨特列的條件幾乎不重要 - 無論如何只有一行符合條件(並且有索引可以快速查找)。

在下面的評論中改進了來自@a_horse_with_no_name的輸入。

+0

好點! (雖然person_id可能是主鍵,所以它只會使用索引查找「掃描」單個表)。 – 2012-08-09 22:20:17

+0

@a_horse_with_no_name:截至目前(Postgres 9.1)'count()'* always *會觸發順序掃描。嘗試'用任何表'EXPLAIN ANALYZE SELECT count(id)from tbl'。更多關於[Postgres Wiki中的慢計數](http://wiki.postgresql.org/wiki/Slow_Counting)。 Postgres 9.2的新索引專用掃描應該可以改進,因爲它可以(提供一些條件)利用「count(id)」的索引掃描 - 儘管如此,我還沒有嘗試自己查看。 – 2012-08-09 22:27:08

+3

A帶條件的count(*)* *(特別是不在PK列上)將不會觸發順序掃描。 – 2012-08-09 22:32:14

2

使用count(*)

declare 
    cnt integer; 
begin 
    SELECT count(*) INTO cnt 
    FROM people 
    WHERE person_id = my_person_id; 

IF cnt > 0 THEN 
    -- Do something 
END IF; 

編輯(對於downvoter誰不宣讀的聲明和其他人誰可能會做類似的東西)

解決方案是只有有效的,因爲有柱(和列名where子句暗示,其主鍵 - 所以where子句非常有效)

由於該where子句,不需要使用LIMIT或其他方法來測試由其主鍵標識的行的存在。它一個有效的方法來測試這個。

+0

哈哈我添加了這個解決方案到我發佈的權利,因爲你發佈這個。 – nnyby 2012-08-09 21:44:09

+2

不要爲此使用COUNT - 這是性能問題 - 或者您必須使用派生表SELECT COUNT(*)FROM(SELECT * FROM people LIMIT 1)x – 2012-08-10 04:23:18

+1

@PavelStehule:即使當存在'where'條件時**主鍵**?我無法想象這可能會比你的陳述慢得多。兩種解決方案的執行計劃幾乎完全相同。 – 2012-08-10 06:15:01