如何在postgres中执行存储过程的字符串结果
How to execute a string result of a stored procedure in postgres
我创建了以下存储过程,它基本上接收表名和前缀。该函数然后查找共享此前缀和 returns 的所有列作为 'select' 查询命令 ('myoneliner') 的输出。
如下:
CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS text AS $myoneliner$
declare
myoneliner text;
BEGIN
SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable
INTO myoneliner
FROM (
SELECT array(
SELECT DISTINCT quote_ident(column_name::text)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
order by quote_ident
)::text cols
) sub;
RETURN myoneliner;
END;
$myoneliner$ LANGUAGE plpgsql;
致电:
select mytext('dkj_p_k27ac','enri');
作为运行此存储过程及其后的 'select' 的结果,我在数据输出 window 中得到以下输出(全部在一个单元格中,名为 "mytext text"):
'SELECT enrich_d_dkj_p_k27ac,enrich_lr_dkj_p_k27ac,enrich_r_dkj_p_k27ac
FROM dkj_p_k27ac'
我希望基本上能够将收到的输出命令行作为输出并执行它。换句话说,我希望能够并执行我的存储过程的输出。
我该怎么做?
我尝试了以下方法:
CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS SETOF RECORD AS $$
declare
smalltext text;
myoneliner text;
BEGIN
SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable
INTO myoneliner
FROM (
SELECT array(
SELECT DISTINCT quote_ident(column_name::text)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
order by quote_ident
)::text cols
) sub;
smalltext=lower(myoneliner);
raise notice '%','my additional text '||smalltext;
RETURN QUERY EXECUTE smalltext;
END;
$$ LANGUAGE plpgsql;
调用函数:
SELECT * from mytext('dkj_p_k27ac','enri');
但是我收到以下错误消息,请问我应该更改什么才能执行它?:
ERROR: a column definition list is required for functions returning "record"
LINE 26: SELECT * from mytext('dkj_p_k27ac','enri');
********** Error **********
ERROR: a column definition list is required for functions returning "record"
SQL state: 42601
Character: 728
你的第一个问题是通过使用动态 SQL 和 EXECUTE
解决的,就像克雷格建议的那样。
但兔子洞更深:
CREATE OR REPLACE FUNCTION myresult(mytable text, myprefix text)
RETURNS SETOF RECORD AS
$func$
DECLARE
<strike>smalltext text;</strike>
myoneliner text;
BEGIN
SELECT INTO myoneliner
'SELECT '
|| string_agg(quote_ident(column_name::text), ',' ORDER BY column_name)
|| ' FROM ' || quote_ident(mytable)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
AND table_schema = 'public'; -- schema name; might be another param
<strike>smalltext := lower(myoneliner);</strike> -- nonsense
RAISE NOTICE 'My additional text: %', myoneliner;
RETURN QUERY EXECUTE myoneliner;
END
$func$ LANGUAGE plpgsql;
要点
不要将整个语句转换为小写。列名可能用大写字母双引号引起来,在这种情况下区分大小写(没有双关语意)。
您在 information_schema.columns
的查询中不需要 DISTINCT
。列名是唯一的 per table.
你 do 需要指定模式,但是(或者使用另一种方式来挑出 一个模式),或者您可能在多个模式中混合来自多个table的同名列名,导致无意义。
您必须清理动态代码中的 所有 标识符 - 包括 table 个名称:quote_ident(mytable)
。请注意,函数的文本参数区分大小写! information_schema.columns
上的查询也需要这样做。
我解开了你的整个结构,用 string_agg()
而不是数组构造函数来构建列名列表。相关回答:
- Update multiple columns that start with a specific string
The assignment operator in plpgsql is :=
.
的简化语法
无法解决的核心问题
所有这些仍然不能解决您的主要问题:SQL 需要定义要return 的列。您可以像您尝试的那样通过 returning 匿名记录来规避此问题。但这只是推迟了inevitable。现在您必须在调用时 提供列定义列表,就像您的错误消息告诉您的那样。但您只是不知道哪些列将被 returned。赶上 22.
你的调用会这样工作:
SELECT *
FROM myresult('dkj_p_k27ac','enri') AS f (
enrich_d_dkj_p_k27ac text -- replace with actual column types
, enrich_lr_dkj_p_k27ac text
, enrich_r_dkj_p_k27ac text);
但是您不知道 returned 列的编号、名称(可选)和数据类型,在创建函数时不知道,甚至在调用时也不知道。 不可能在单个调用中做到这一点。您需要两个单独的数据库查询。
你可以return所有列的任何给定table 使用 多态类型 动态地使用函数,因为整个 table 有一个明确定义的类型。本相关回答最后一章:
- Refactor a PL/pgSQL function to return the output of various SELECT queries
我创建了以下存储过程,它基本上接收表名和前缀。该函数然后查找共享此前缀和 returns 的所有列作为 'select' 查询命令 ('myoneliner') 的输出。 如下:
CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS text AS $myoneliner$
declare
myoneliner text;
BEGIN
SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable
INTO myoneliner
FROM (
SELECT array(
SELECT DISTINCT quote_ident(column_name::text)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
order by quote_ident
)::text cols
) sub;
RETURN myoneliner;
END;
$myoneliner$ LANGUAGE plpgsql;
致电:
select mytext('dkj_p_k27ac','enri');
作为运行此存储过程及其后的 'select' 的结果,我在数据输出 window 中得到以下输出(全部在一个单元格中,名为 "mytext text"):
'SELECT enrich_d_dkj_p_k27ac,enrich_lr_dkj_p_k27ac,enrich_r_dkj_p_k27ac
FROM dkj_p_k27ac'
我希望基本上能够将收到的输出命令行作为输出并执行它。换句话说,我希望能够并执行我的存储过程的输出。 我该怎么做?
我尝试了以下方法:
CREATE OR REPLACE FUNCTION mytext (mytable text, myprefix text)
RETURNS SETOF RECORD AS $$
declare
smalltext text;
myoneliner text;
BEGIN
SELECT 'SELECT ' || substr(cols,2,length(cols)-2) ||' FROM '||mytable
INTO myoneliner
FROM (
SELECT array(
SELECT DISTINCT quote_ident(column_name::text)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
order by quote_ident
)::text cols
) sub;
smalltext=lower(myoneliner);
raise notice '%','my additional text '||smalltext;
RETURN QUERY EXECUTE smalltext;
END;
$$ LANGUAGE plpgsql;
调用函数:
SELECT * from mytext('dkj_p_k27ac','enri');
但是我收到以下错误消息,请问我应该更改什么才能执行它?:
ERROR: a column definition list is required for functions returning "record"
LINE 26: SELECT * from mytext('dkj_p_k27ac','enri');
********** Error **********
ERROR: a column definition list is required for functions returning "record"
SQL state: 42601
Character: 728
你的第一个问题是通过使用动态 SQL 和 EXECUTE
解决的,就像克雷格建议的那样。
但兔子洞更深:
CREATE OR REPLACE FUNCTION myresult(mytable text, myprefix text)
RETURNS SETOF RECORD AS
$func$
DECLARE
<strike>smalltext text;</strike>
myoneliner text;
BEGIN
SELECT INTO myoneliner
'SELECT '
|| string_agg(quote_ident(column_name::text), ',' ORDER BY column_name)
|| ' FROM ' || quote_ident(mytable)
FROM information_schema.columns
WHERE table_name = mytable
AND column_name LIKE myprefix||'%'
AND table_schema = 'public'; -- schema name; might be another param
<strike>smalltext := lower(myoneliner);</strike> -- nonsense
RAISE NOTICE 'My additional text: %', myoneliner;
RETURN QUERY EXECUTE myoneliner;
END
$func$ LANGUAGE plpgsql;
要点
不要将整个语句转换为小写。列名可能用大写字母双引号引起来,在这种情况下区分大小写(没有双关语意)。
您在
information_schema.columns
的查询中不需要DISTINCT
。列名是唯一的 per table.你 do 需要指定模式,但是(或者使用另一种方式来挑出 一个模式),或者您可能在多个模式中混合来自多个table的同名列名,导致无意义。
您必须清理动态代码中的 所有 标识符 - 包括 table 个名称:
quote_ident(mytable)
。请注意,函数的文本参数区分大小写!information_schema.columns
上的查询也需要这样做。我解开了你的整个结构,用
string_agg()
而不是数组构造函数来构建列名列表。相关回答:- Update multiple columns that start with a specific string
The assignment operator in plpgsql is
:=
.- 的简化语法
无法解决的核心问题
所有这些仍然不能解决您的主要问题:SQL 需要定义要return 的列。您可以像您尝试的那样通过 returning 匿名记录来规避此问题。但这只是推迟了inevitable。现在您必须在调用时 提供列定义列表,就像您的错误消息告诉您的那样。但您只是不知道哪些列将被 returned。赶上 22.
你的调用会这样工作:
SELECT *
FROM myresult('dkj_p_k27ac','enri') AS f (
enrich_d_dkj_p_k27ac text -- replace with actual column types
, enrich_lr_dkj_p_k27ac text
, enrich_r_dkj_p_k27ac text);
但是您不知道 returned 列的编号、名称(可选)和数据类型,在创建函数时不知道,甚至在调用时也不知道。 不可能在单个调用中做到这一点。您需要两个单独的数据库查询。
你可以return所有列的任何给定table 使用 多态类型 动态地使用函数,因为整个 table 有一个明确定义的类型。本相关回答最后一章:
- Refactor a PL/pgSQL function to return the output of various SELECT queries