在 PL/pgSQL 块中运行 SELECT 查询

7

我是PostgreSQL的新手,需要在SSRS报表中使用内联查询从PostgreSQL数据库检索数据。

情景如下:根据所选报表参数的值,我需要从不同的表中获取输出。请查看以下示例内联查询。

    DO
    $do$

    BEGIN
    IF ($1 = 'Monthly') THEN

    SELECT *
    FROM table1;

    ELSE 

    SELECT *
    FROM table2;

    END IF;

    END
    $do$

上述查询出现错误,

错误:查询没有结果数据的目标 SQL状态:42601 提示:如果要丢弃SELECT的结果,请使用PERFORM。 上下文:PL / pgSQL函数inline_code_block第6行的SQL语句

请注意,我不能使用存储过程或函数来检索所需的数据,我只能使用内联查询。

有人能告诉我如何解决上述错误吗?


一个select语句的结果需要被存储在某个地方,所以你需要将结果存储在一个变量中。如果你的代码被简化到不再有意义,例如 if (1 > 0) 这样的语句总是为真,第二个语句永远不会被执行,那么你可以用 select * from table1 来替换整个代码块。 - user330315
请查看下面的更新查询,DO $do$BEGIN IF ($1 = 'Monthly') THEN SELECT * FROM table1;ELSE SELECT * FROM table2;END IF;END $do$ - Vinayak Zirmirkar
你不能向匿名代码块传递参数,也不能从中返回结果。所以你提出的方法永远不会生效。 - Patrick
感谢Patrick的回复。那么有没有任何解决方法来实现所需的行为?这在SQL Server中将是一个简单的查询,但我发现令人失望的是Postgresql不支持类似的功能。 - Vinayak Zirmirkar
1
每个数据库管理系统都是不同的。你总会发现在一个DBMS中有些东西无法直接移植到另一个DBMS中。我可以列举出许多SQL Server无法做到但在Postgres中非常容易的事情。而且:你在Oracle或DB2中也无法做这样的事情。 - user330315
5个回答

9
你的例子有两个问题 - DO语句(匿名块)不支持
  1. 参数
  2. 返回结果。
PostgreSQL不支持T-SQL或MS-SQL中使用的未绑定查询技术。每个查询都必须有指定的目标。您可以改用函数(table1table2应具有相同的结构):
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');

1
嗨,Pavel,感谢您的建议。上述解决方案在我的情况下无法使用,因为我们不能在Postgresql数据库中创建任何函数/存储过程。我们必须仅使用内联查询来获取数据。请告诉我是否有其他方法可以实现相同的效果? - Vinayak Zirmirkar
@VinayakZirmirkar - 然后你必须在应用程序中做出这个决定,或者像Gary描述的那样使用UNION。没有其他方法。 - Pavel Stehule

2
假设表具有相同的列结构,您可以使用union在单个查询中执行两个选项。
SELECT * FROM table1 WHERE $1 = 'Monthly'
UNION ALL
SELECT * FROM table2 WHERE NOT ($1 = 'Monthly')

1
你可以创建一个临时表格来获取结果,但不能传递参数:
DO
$$
BEGIN
IF <> THEN
CREATE TEMPORARY TABLE foo AS
SELECT *FROM ...
 ELSE

 ....
 END IF;
 END
 $$
 SELECT * FROM FOO;

0
如果您创建一个接受“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 函数的结果转换为与您的“select”查询匹配的特定记录结构。
PS: 顺便说一下,我不明白为什么没有人推荐这种简单的执行几乎任何请求的方法。这是一种非常有用的方式,可以快速形成查询并在不创建阻塞数据库的单独函数的情况下执行它。

0
你可以使用光标:
BEGIN; -- open a transaction to extend the scope visibility of the cursor

DO $$
DECLARE
  _cursor cursor FOR select * from my_table;
BEGIN
  OPEN _cursor;
END
$$;

FETCH ALL FROM _cursor;

ABORT;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接