2015-12-01 32 views
6

如何將存儲在記錄類型變量中的查詢結果用於同一存儲函數中的另一個查詢?我使用Postgres 9.4.4。如何在plpgsql中使用記錄類型變量?

有了這樣的表:

create table test (id int, tags text[]); 
insert into test values (1,'{a,b,c}'), 
         (2,'{c,d,e}'); 

我寫了一個函數(簡體)象下面這樣:

CREATE OR REPLACE FUNCTION func(_tbl regclass) 
RETURNS TABLE (t TEXT[], e TEXT[]) 
LANGUAGE plpgsql AS $$ 
DECLARE 
    t RECORD; 
    c INT; 
BEGIN 
    EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t; 
    SELECT count(*) FROM t INTO c; 
    RAISE NOTICE '% results', c; 
    SELECT * FROM t; 
END 
$$; 

...但沒有奏效:

select func('test'); 
ERROR: 42P01: relation "t" does not exist 
LINE 1: SELECT count(*) FROM t 
          ^
QUERY: SELECT count(*) FROM t 
CONTEXT: PL/pgSQL function func(regclass) line 7 at SQL statement 
LOCATION: parserOpenTable, parse_relation.c:986 

回答

15

核心誤區:一個record變量包含一個單個行(或者是NULL),而不是一個表(一個衆所周知的類型的0-n行)。在Postgres或PL/pgSQL中有沒有「表變量」。根據任務的不同,有不同的選擇:

因此,你不能分配行到record類型變量。在此聲明:

EXECUTE format('SELECT id, tags FROM %s', _tbl) INTO t; 

... Postgres的分配只有第一排和丟棄其餘部分。由於「第一個」在你的查詢中沒有很好的定義,你最終會得到一個任意選擇。顯然是由於一開始就提到的誤解。

A record變量也不能代替SQL查詢中的表。這是錯誤的主要原因,您可以獲得:

關係「T」不存在

這應該是現在很清楚,那count(*)將沒有任何意義,首先,因爲t只是一個記錄/行 - 除了無論如何也是不可能的。

最後(即使其餘的工作),您的返回類型似乎是錯誤的: (t TEXT[], e TEXT[]) 。由於您將id, tags選爲t,因此您希望返回類似(id int, e TEXT[])的內容。

你正在嘗試做會像這樣工作

CREATE OR REPLACE FUNCTION func(_tbl regclass) 
    RETURNS TABLE (id int, e text[]) AS 
$func$ 
DECLARE 
    _ct int; 
BEGIN 
    EXECUTE format(
     'CREATE TEMP TABLE tmp ON COMMIT DROP AS 
     SELECT id, tags FROM %s' 
    , _tbl); 

    GET DIAGNOSTICS _ct = ROW_COUNT; -- cheaper than another count(*) 

    -- ANALYZE tmp; -- if you are going to run multiple queries 

    RAISE NOTICE '% results', _ct; 

    RETURN QUERY TABLE tmp; 
END 
$func$ LANGUAGE plpgsql; 

呼叫(注意語法!)

SELECT * FROM func('test'); 

相關:

概念只是一個證明。在選擇整個表格時,您只需使用底層表格。在現實中,你必須在查詢一些WHERE條款等

小心潛伏的類型不匹配的,count()回報bigint,你不能將它賦值給一個變量integer。需要演員:count(*)::int

但是我換成完全,它的便宜EXECUTE後執行這一權利:

GET DIAGNOSTICS _ct = ROW_COUNT; 

Details in the manual.

爲什麼ANALYZE


旁白:熱膨脹係數在普通的SQL往往可以做的工作:

+0

太感謝你了,歐文,對種類和詳細的答案。現在,我的理由非常清楚。我將用CTE來達到這個目的。 –

相關問題