查询返回语句 - PostgreSQL

Posted

技术标签:

【中文标题】查询返回语句 - PostgreSQL【英文标题】:Query on Return Statement - PostgreSQL 【发布时间】:2020-04-17 14:09:00 【问题描述】:

我有这个问题,我正在从 SQL Server 迁移到 PostgreSQL 12。

我正在尝试完成的场景:

函数应该有一个 RETURN 语句,无论是 SETOF 'tableType' 还是 RETURN TABLE(一些列数)

正文以记录计数开始,如果根据输入参数没有找到记录,则简单地返回零(0),否则返回 RETURN 语句中定义的整个记录​​集。

SQL Server 或 Oracle 中的等效部分是:他们只需将 SELECT 语句放入过程中即可完成此操作。但是,对于 PostgreSQL 来说,这有点困难。

任何建议,请。

我现在仍然可以完成的工作 - 如果没有找到记录,它将简单地返回 NULL,可能正在使用 PERFORM,或者可能选择 NULL 作为返回 tableType 列的列名。

希望我清楚!

我想要的是-

================================================ ==============

CREATE OR REPLACE FUNCTION public.get_some_data(
    id integer)
    RETURNS TABLE ( id_1 integer, name character varying )

    LANGUAGE 'plpgsql'



AS $BODY$

 DECLARE 

 p_id alias for $1;
 v_cnt integer:=0;

BEGIN

    SELECT COUNT(1) FROM public.exampleTable e
    WHERE id::integer = e.id::integer;

    IF v_cnt= 0 THEN
        SELECT 0;
    ELSE

    SELECT
       a.id, a.name
        public.exampleTable a 
        where a.id = p_id;
END;
$BODY$;

【问题讨论】:

这是一个函数还是一个过程?您甚至使用什么语言,SQL 或 PL/PGSQL?请给我们看看你的代码好吗? 我无法真正显示我的代码。但是,迁移是从 SQL Server 过程到 POstgrSQL 函数。我使用的语言是 pgplsql。如果你愿意,我可以写一个简短的程序让你明白,我想问什么。 如果您对下面无名马的回答不满意,这可能会有所帮助。 如果你的返回类型是多行,你不能返回数字0 是的..就是这样!我知道,只要检查一下,是否有任何解决方法。我知道它不是 PostgrSQL 的工作方式。 【参考方案1】:

如果只想返回一组单表,使用returns setof some_table确实是最简单的方法。最基本的 SQL 函数是:

create function get_data()
   returns setof some_table
as
$$
  select * 
  from some_table;
$$
language sql;

PL/pgSQL 并不是真正需要将 SELECT 语句放入函数中,但如果您需要做其他事情,则需要在 PL/pgSQL 函数中使用 RETURN QUERY:

create function get_data()
   returns setof some_table
as
$$
begin
  return query
    select * 
    from some_table;
end;
$$
language plpgsql;

一个函数正好是 one 返回类型。你不能有一个函数有时返回一个整数,有时返回数千行和十几列。

如果你坚持返回某物,你唯一能做的就是这样:

create function get_data()
   returns setof some_table
as
$$
begin
  return query
    select * 
    from some_table;

  if not found then  
    return query 
      select (null::some_table).*;
  end if;
end;
$$
language plpgsql;

但我认为上述解决方案非常丑陋和令人困惑(不是说愚蠢)。我当然不会让它通过代码审查。


函数的调用者可以测试是否返回了某些东西,就像我实现那个丑陋的黑客一样:使用函数后检查found变量。

【讨论】:

呐!这可以。我想要的是 - 我在主查询上方进行了编辑。无论如何,谢谢你的帮助。 如果我找不到记录,根据输入参数,我只想返回一个零,不为空,不为空,一个数字零。这就是问题所在。我们可以在 SQL Server 过程中执行此操作,或者通过 select 语句在 plsql 过程中执行此操作,但在 Postgresql 中,它变得越来越困难。否则,它很简单,返回查询、setof 等。 @SayanB:你根本做不到。与 one 返回类型完全相同的函数。您不能即时更改该返回类型。您可以返回一个带有空值的虚拟行,但这将是一件非常奇怪的事情(我当然不会让类似的事情通过代码审查)。为什么你还需要那个?如果没有返回任何内容,调用者将知道这一点。 问题不是“为什么”。我在问,有没有办法解决这个问题。有没有其他方法可以在 PostgreSQL 中放置一种动态返回类型。我也知道这是不可能的,正在检查是否有人这样做.. @SayanB:答案是否定的,你不能那样做。我会考虑一个解决方案,一个丑陋的黑客,它也不会通过我为 Oracle 程序进行的代码审查。这样的事情最好由调用者完成。数据库迁移不仅仅是代码重写,还需要migrate your mindset to。这不是在 Postgres 中是如何完成的【参考方案2】:

还有一个技巧可以尽可能接近您想要的。但我会重复其他人告诉你的内容:你不能直接做你想做的事。仅仅因为 MS SQL Server 让您摆脱糟糕的编码并不意味着 Postgres 有义务这样做。正如@a_horse_with_no_name 的链接所暗示的那样,转换代码很容易,一旦您首先迁移您对问题的看法。你能得到的最接近的是返回一个 0 id 的元组。以下是一种方式。

create or replace function public.get_some_data(
    p_id integer)
    returns table ( id integer, name character varying )
    language plpgsql
as $$
declare 
    v_at_least_one boolean = false; 
    v_exp_rec record;
begin
    for v_exp_rec in  
        select a.id, a.name
          from public.exampletable a
        where a.id = p_id   
        union all
        select 0,null
    loop
        if v_exp_rec.id::integer > 0
        or (v_exp_rec.id::integer = 0 and not v_at_least_one)
        then 
            id = v_exp_rec.id;
            name = v_exp_rec.name;
            return next;
            v_at_least_one = true;
        end if;
    end loop ;    
    return;
end 
$$;

但这仍然只是一个 hack,并假设存在 id=0 的无效行。一个更好的方法是让调用路由检查函数返回的内容(无论如何它必须以一种或另一种方式这样做)并让函数只返回找到的数据而不是组成数据。那就是心态转变。这样做可以将此函数简化为一个简单的选择语句:

create or replace function public.get_some_data2(
    p_id integer)
    returns table ( id integer, name character varying )
    language sql strict
as $$
   select a.id, a.name
     from public.exampletable a
    where a.id = p_id;   
$$;  

或提供的其他解决方案之一。

【讨论】:

以上是关于查询返回语句 - PostgreSQL的主要内容,如果未能解决你的问题,请参考以下文章

PHP查询语句,如何返回总记录数??

查询返回语句 - PostgreSQL

返回单行子查询的更新语句返回多于一行

SPARQL 查询根据语句的顺序返回不同的结果

SQL中关于返回查询记录条数的语句

MFC中的SQL查询语句返回空就报错怎么办?