在 PL/pgSQL 块中运行 SELECT
Posted
技术标签:
【中文标题】在 PL/pgSQL 块中运行 SELECT【英文标题】:Running a SELECT in a PL/pgSQL block 【发布时间】:2015-07-07 06:10:00 【问题描述】:我是 PostgreSQL 的新手,我必须在 s-s-rS 报告中使用内联查询来从 PostgreSQL 数据库中获取数据。
场景是:根据报告参数的选定值,我需要从不同的表中获取输出。请参阅下面的示例内联查询。
DO
$do$
BEGIN
IF ($1 = 'Monthly') THEN
SELECT *
FROM table1;
ELSE
SELECT *
FROM table2;
END IF;
END
$do$
以上查询报错,
错误:查询没有结果数据的目的地 SQL 状态:42601 提示:如果要丢弃 SELECT 的结果,请改用 PERFORM。 上下文:SQL 语句中的 PL/pgSQL 函数 inline_code_block 第 6 行
请注意,我不能使用存储过程或函数来检索所需的数据,我只能使用内联查询。
有人可以告诉我如何解决上述错误吗?
【问题讨论】:
选择的结果需要去某处 - 所以你需要把结果放到一个变量中。而且您的代码减少了很多,以至于不再有意义:if (1 > 0)
将始终为真,第二条语句将永远不会被执行。您可以将整个块替换为select * from table1
请在下面找到更新后的查询,DO $do$ BEGIN IF ($1 = 'Monthly') THEN SELECT * FROM table1; ELSE SELECT * FROM table2;万一;结束$do$
您不能将参数传递给匿名代码块,也不能从中返回结果。所以你的提议永远不会奏效。
感谢帕特里克的回复。那么是否有任何解决方法来实现所需的行为?这本来是 SQL Server 中的一个简单查询,但我发现 Postgresql 不支持类似的东西令人失望。
嗯,每个 DBMS 都是不同的。您总是会在一个 DBMS 中找到无法直接移植到另一个 DBMS 的东西。我可以说出许多 SQL Server 无法做到但在 Postgres 中非常简单的事情。此外:您也无法在 Oracle 或 DB2 中做类似的事情。
【参考方案1】:
您的示例有两个问题 - DO 语句(匿名块)不支持
-
参数
返回结果。
PostgreSQL 不支持在 T-SQL 或 MS-SQL 中使用的称为未绑定查询的技术。每个查询都必须有指定的目标。您可以改用函数(table1
和 table2
应该具有相同的结构):
CREATE OR REPLACE FUNCTION foo(frequency)
RETURNS SETOF table1 AS $$
BEGIN
IF $1 = 'Monthly' THEN
RETURN QUERY SELECT * FROM table1;
ELSE
RETURN QUERY SELECT * FROM table2;
END IF;
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM foo('Monthly');
【讨论】:
您好帕维尔,感谢您的意见。上述解决方案在我的场景中不起作用,因为我们无法在 Postgresql DB 中创建任何函数/存储过程。我们只能使用内联查询来获取数据。请让我知道是否有任何其他方法可以实现相同的目标? @VinayakZirmirkar - 那么你必须在应用程序中做出这个决定,或者像 Gary 描述的那样使用 UNION。没有其他办法。【参考方案2】:假设表具有相同的列结构,您可以使用联合在单个查询中执行这两个选项。
SELECT * FROM table1 WHERE $1 = 'Monthly'
UNION ALL
SELECT * FROM table2 WHERE NOT ($1 = 'Monthly')
【讨论】:
【参考方案3】:您可以创建一个临时表来获取外部结果,但不能传递参数:
DO
$$
BEGIN
IF <> THEN
CREATE TEMPORARY TABLE foo AS
SELECT *FROM ...
ELSE
....
END IF;
END
$$
SELECT * FROM FOO;
【讨论】:
【参考方案4】:如果你创建一个接受'select'查询文本并返回SETOF RECORD
的函数,那么你可以直接在sql窗口中执行:
with c_sql as (
-- >>> --- your any query
select STRING_AGG('select ''"' || t.table_schema || '"."' || t.table_name || '"'' tab, count(*) cnt from "' || t.table_schema || '"."' || t.table_name || '"', ' union all ')
|| ' order by 2 desc' v_sql
from information_schema.tables t
where t.table_schema like 'tiger'
-- <<< ---
)
select ex.* from c_sql
LEFT JOIN lateral ( select * from execsql(c_sql.v_sql) as ss(tab text, cnt int8) ) ex on true
这是execsql函数:
CREATE OR REPLACE FUNCTION public.execsql(
text)
RETURNS SETOF RECORD
LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RETURN QUERY EXECUTE $1 ;
END
$BODY$;
请注意,您应该将 execsql 函数的结果转换为 与您的“选择”查询匹配的特定记录结构。
PS: 顺便说一句,我不明白为什么没有人推荐这种执行几乎所有请求的简单方法。这是一种非常有用的方法,可以快速形成查询并执行它,而无需创建阻塞数据库的单独函数。
【讨论】:
以上是关于在 PL/pgSQL 块中运行 SELECT的主要内容,如果未能解决你的问题,请参考以下文章
有没有为 PostgreSQL 开发的 PL/pgSQL 免费环境?