use*_*935 2 postgresql stored-procedures dynamic-sql plpgsql postgresql-8.3
我正在使用 PostgreSSQL 8.3。
我想执行这个查询:
select COALESCE(col_fr,col,'Unknown') from my_table where id = 'abc';
Run Code Online (Sandbox Code Playgroud)
故事中的扭曲是列名colum_fr
应该动态生成。my_table
对于不同的语言有不同的列。就像是:
id col col_ja col_fr
Run Code Online (Sandbox Code Playgroud)
我在水晶报告中使用此查询,我可以在其中传递语言的字符串参数:
select COALESCE(col_||{?parameter},col,'Unknown') from my_table where id = 'abc';
Run Code Online (Sandbox Code Playgroud)
如果{?language}
value 是,它将在内部转换为如下内容fr
:
select COALESCE(col_||'fr',col,'Unknown') from my_table where id = 'abc';
Run Code Online (Sandbox Code Playgroud)
这永远不会奏效。
我不想使用选择大小写,使其动态化。
作为替代解决方案,我还尝试创建一个存储过程:
CREATE OR REPLACE FUNCTION get_policy_name (
id text,
lang text,
def_value text
)
RETURNS SETOF record AS
$body$
DECLARE
sql text;
BEGIN
sql := 'SELECT COALESCE(col_'||quote_ident(lang)||',col,'||quote_literal(def_value)||')FROM my_table WHERE id ='||quote_literal(id);
RETURN QUERY EXECUTE sql
END;
$body$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
哪个应该返回单个记录。
它不工作。我错过了什么?PostgreSSQL 8.3 支持RETURN QUERY EXECUTE
吗?
RETURN QUERY EXECUTE
是在 Postgres 8.4 中引入的。
您的版本太旧了,现在不受支持。升级到更新的版本。
此外,结果中的动态列名很难获得。SQL 的一个原则是它想知道返回类型 - 包括名称 - 预先。
返回没有列定义列表的匿名记录仅适用于单个记录。否则,您必须在调用中提供列定义列表。他关于 SO 的问题的详细信息:
使用 PL/pgSQL 在 PostgreSQL 中返回多个字段作为记录
使用多态类型解决这个问题的方法有限。高级内容:
重构 PL/pgSQL 函数以返回各种 SELECT 查询的输出
顺便说一句,你的函数在现代 PL/pgSQL 中看起来像这样:
CREATE OR REPLACE FUNCTION get_policy_name (
_id int,
_lang text,
_def_value text
) RETURNS TABLE (col text) AS
$func$
BEGIN
RETURN QUERY EXECUTE
format('SELECT COALESCE(%I, col, $1)
FROM my_table WHERE id = $2'
, 'col_' || _lang)
USING _def_value, _id;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
称呼:
SELECT col AS col_fr FROM get_policy_name (1, 'fr', 'foo');
Run Code Online (Sandbox Code Playgroud)
在这里,我只是在调用中使用列别名来实现您想要的。比动态列名容易得多......