【问题标题】:Running a SELECT in a PL/pgSQL block在 PL/pgSQL 块中运行 SELECT
【发布时间】:2015-07-07 06:10:00
【问题描述】:

我是 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。 上下文: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 中做类似的事情。

标签: postgresql plpgsql


【解决方案1】:

您的示例有两个问题 - 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');

【讨论】:

  • 您好帕维尔,感谢您的意见。上述解决方案在我的场景中不起作用,因为我们无法在 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: 顺便说一句,我不明白为什么没有人推荐这种执行几乎所有请求的简单方法。这是一种非常有用的方法,可以快速形成查询并执行它,而无需创建阻塞数据库的单独函数。

      【讨论】:

        猜你喜欢
        • 2018-12-05
        • 2012-08-12
        • 2012-04-24
        • 2012-07-28
        • 2018-09-01
        • 1970-01-01
        • 2018-02-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多