2010-01-20 178 views
6

我想在PL/PgSQL中编写一个函数,它必须使用它作为参数接收的表。PL/pgSQL中的EXECUTE ... USING语句不适用于记录类型?

我在函数定义中使用EXECUTE..INTO..USING语句来构建动态查询(这是我知道这样做的唯一方法),但是...我遇到了RECORD数据类型的问题。

让我们考虑以下(非常简化)的例子。

-- A table with some values. 
DROP TABLE IF EXISTS table1; 
CREATE TABLE table1 (
    code INT, 
    descr TEXT 
); 

INSERT INTO table1 VALUES ('1','a'); 
INSERT INTO table1 VALUES ('2','b'); 


-- The function code. 
DROP FUNCTION IF EXISTS foo (TEXT); 
CREATE FUNCTION foo (tbl_name TEXT) RETURNS VOID AS $$ 
DECLARE 
    r RECORD; 
    d TEXT; 
BEGIN 
    FOR r IN 
    EXECUTE 'SELECT * FROM ' || tbl_name 
    LOOP 
    --SELECT r.descr INTO d; --IT WORK 
    EXECUTE 'SELECT ($1)' || '.descr' INTO d USING r; --IT DOES NOT WORK 
    RAISE NOTICE '%', d; 
END LOOP; 

END; 
$$ LANGUAGE plpgsql STRICT; 

-- Call foo function on table1 
SELECT foo('table1'); 

它输出以下错误:

ERROR: could not identify column "descr" in record data type

虽然我使用的语法似乎是有效的给我。我不能使用静态选择(在示例中注释),因为我想要引用列名称。

因此..有人知道上面的代码有什么问题吗?

回答

7

这是真的。你不能在PL/pgSQL空间外使用类型记录。

RECORD值仅在plpgsql中有效。

你可以做

EXECUTE 'SELECT $1.descr' INTO d USING r::text::xx; 
+0

您的代码不起作用。 – Hobbes 2010-01-21 08:03:26

+3

好的,很抱歉,显然你的代码是用'table1'代替'xx'的。但那样我不能dinumically指定表名称。所以正确的答案是:“EXECUTE'SELECT $ 1 :: text :: table1.descr'INTO d USING r;”。非常感谢! – Hobbes 2010-01-21 08:34:41

3

$1应该是||里面,像|| $1 ||,并给予适当的空间,然后它会工作。

BEGIN 

EXECUTE ' delete from ' || quote_ident($1) || ' where condition '; 

END; 
+0

问题在于如何以_reflective_方式(按名称,使用字符串连接)获取RECORD字段。 – botchniaque 2015-10-16 09:08:50