如果infowindow
字段存在,我需要创建一个检查给定表的函数。如果它存在,则该函数必须返回select * from table
但如果不存在,则必须返回另一个id
字段:
CREATE OR REPLACE FUNCTION getxo_ocx_cincu_preparar_infowindow(
guretabla character varying)
RETURNS TABLE AS
$BODY$
DECLARE
tabla ALIAS FOR $1;
BEGIN
IF EXISTS (SELECT 1
FROM pg_namespace n
JOIN pg_class c ON c.relnamespace = n.oid
JOIN pg_attribute a ON a.attrelid = c.oid
WHERE n.nspname = current_schema() -- default to current schema
AND c.relname = tabla
AND a.attname = 'infowindow'
AND NOT a.attisdropped)
THEN
RETURN QUERY EXECUTE 'SELECT * from ' ||tabla ;
ELSE
RETURN QUERY EXECUTE 'SELECT *, ID:' || id::text ||' as infowindow
from ' ||tabla ;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
如果我使用RETURNS SETOF RECORDS
,当我选择函数时,我需要指定列,我不知道。如果我使用RETURNS TABLE
我也需要指定字段,所以我不知道该怎么做。
答案 0 :(得分:20)
这很难解决,因为SQL要求在通话时知道返回类型 此外,plpgsql函数需要具有明确定义的返回类型。
如果您选择返回匿名记录,则会获得您定义的内容:匿名记录。 Postgres不知道里面是什么。因此,列定义列表 required 可以分解类型。
根据具体要求,有各种变通方法。如果您有任何方式知道在呼叫时的返回类型,我建议多态类型,如本答案最后一章(“各种完整的表类型”)所述:
Refactor a PL/pgSQL function to return the output of various SELECT queries
但这并不包括在函数内的运行时向返回类型添加另一列。那是不可能的。我会重新考虑整个方法。
至于您当前的方法,我能想到的最接近的事情是临时表(or a cursor),您在单个事务中的第二次调用中查询强>
您的代码中有几个其他问题。见下面的注释。
CREATE OR REPLACE FUNCTION f_tbl_plus_infowindow (_tbl regclass) -- regclass!
RETURNS void AS -- no direct return type
$func$
DECLARE
-- appending _tmp for temp table
_tmp text := quote_ident(_tbl::text || '_tmp');
BEGIN
-- Create temp table only for duration of transaction
EXECUTE format(
'CREATE TEMP TABLE %s ON COMMIT DROP AS TABLE %s LIMIT 0', _tmp, _tbl);
IF EXISTS (
SELECT 1
FROM pg_attribute a
WHERE a.attrelid = _tbl
AND a.attname = 'infowindow'
AND a.attisdropped = FALSE)
THEN
EXECUTE format('INSERT INTO %s SELECT * FROM %s', _tmp, _tbl);
ELSE
-- This is assuming a NOT NULL column named "id"!
EXECUTE format($x$
ALTER TABLE %1$s ADD COLUMN infowindow text;
INSERT INTO %1$s
SELECT *, 'ID: ' || id::text
FROM %2$s $x$
,_tmp, _tbl);
END IF;
END
$func$ LANGUAGE plpgsql;
电话必须在一次交易中。您可能必须开始显式交易,具体取决于您的客户。
BEGIN;
SELECT f_tbl_plus_infowindow ('tbl');
SELECT * FROM tbl_tmp; -- do something with the returned rows
ROLLBACK; -- or COMMIT, does not matter here
<强> SQL Fiddle. 强>
或者,您可以在会话期间让临时表生效。但是要注意在重复呼叫中命名冲突。
使用参数名称代替outdated ALIAS
command。
要实际“默认”当前架构,请使用我显示的更简单的查询。使用regclass
会自动执行此操作。详细说明:
此外,这还可以避免原始代码中的非标准(或恶意格式错误)表名的语法错误和可能的 SQL注入。
ELSE
子句中的代码根本不起作用。
TABLE tbl;
基本上是SELECT * FROM tbl;
的缩写。