Egi*_*idi 13 postgresql polymorphism return-type dynamic-sql plpgsql
我需要创建一个函数,检查给定的表是否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;
Run Code Online (Sandbox Code Playgroud)
如果我使用RETURNS SETOF RECORDS,当我选择函数时,我需要指定列,我不知道.如果我使用RETURNS TABLE我也需要指定字段,所以我不知道该怎么做.
Erw*_*ter 21
这很难解决,因为SQL要求在调用时知道返回类型.
此外,plpgsql函数需要具有良好定义的返回类型.
如果您选择返回匿名记录,则会得到您定义的内容:匿名记录.Postgres不知道里面是什么.因此,一个字段定义列表需要分解的类型.
根据具体要求,有各种变通方法.如果您有任何方式在调用时知道返回类型,我建议在本答案的最后一章("各种完整的表类型")中概述的多态类型:
重构PL/pgSQL函数以返回各种SELECT查询的输出
但这并不包括在函数内的运行时向返回类型添加另一列.那是不可能的.我会重新考虑整个方法.
至于你目前的做法,我能想到的最接近的将是一个临时表(或光标),您在查询第二个电话一内单个事务.
您的代码中还有其他一些问题.见下面的注释.
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;
Run Code Online (Sandbox Code Playgroud)
呼叫必须在单个事务中.您可能必须根据您的客户启动显式交易.
BEGIN;
SELECT f_tbl_plus_infowindow ('tbl');
SELECT * FROM tbl_tmp; -- do something with the returned rows
ROLLBACK; -- or COMMIT, does not matter here
Run Code Online (Sandbox Code Playgroud)
或者,您可以在会话期间让临时表生效.但是要注意使用重复调用来命名冲突.
使用参数名称而不是过时的ALIAS命令.
要实际"默认"到当前架构,请使用我显示的更简单的查询.使用regclass自动完成技巧.细节:
此外,这还可以避免语法错误以及原始代码中非标准(或恶意格式错误)表名的SQL注入.
你的ELSE条款中的代码根本不起作用.
TABLE tbl;基本上是短暂的SELECT * FROM tbl;.
| 归档时间: |
|
| 查看次数: |
13763 次 |
| 最近记录: |