【问题标题】:Return a record from function从函数返回一条记录
【发布时间】:2017-10-14 07:08:32
【问题描述】:

我正在尝试使用非常简单的测试函数在 plpgsql 中返回多个值。测试函数将整数作为输入,如果它是正数、负数和零,则应该返回。我看过一些例子,但它们都太复杂了,我无法理解。

这是我尝试过的:

create or replace function test(v integer)
returns record as $$

BEGIN

    IF v > 0
        THEN return true as positive, false as negative, false as zero;
    ELSEIF v < 0
        THEN return false as positive, true as negative, false as zero;
    ELSE 
        return false as positive, false as negative, true as zero;
    END IF;

END;
$$ LANGUAGE plpgsql;

也试过了

create or replace function test(v integer)
returns record as $$

DECLARE 
    result record;

BEGIN

    IF v > 0
        THEN 
            result.positive = true;
            result.negative = false;
            result.zero = false;

    ELSEIF v < 0
        THEN 
            result.positive = false;
            result.negative = true;
            result.zero = false;
    ELSE 
            result.positive = false;
            result.negative = false;
            result.zero = true;
    return result;
    END IF;

END;
$$ LANGUAGE plpgsql;

还有这个:

IF v > 0
    THEN 
        SELECT true, false, false into
        result.positive, result.negative, result.zero;

ELSEIF v < 0
    THEN 
        SELECT false, true, false into
        result.positive, result.negative, result.zero;
ELSE 
        SELECT false, false, true into
        result.positive, result.negative, result.zero;
return result;
END IF;

【问题讨论】:

    标签: postgresql plpgsql


    【解决方案1】:

    我会这样解决问题:

    CREATE TYPE sign AS ENUM ('negative', 'zero', 'positive');
    
    CREATE FUNCTION test(integer) RETURNS sign
       LANGUAGE sql IMMUTABLE STRICT AS
    $$SELECT CASE
                WHEN $1 < 0
                THEN 'negative'
                WHEN $1 > 0
                THEN 'positive'
                ELSE 'zero'
             END::sign$$;
    

    如果您想像在示例中那样返回 record,则必须使用 ROW() 构造函数从三个布尔值创建单个复合值:

    RETURN ROW(true, false, false);
    

    但是这个解决方案有它的缺点:你不能在 SQL 中访问复合类型的单个字段,因为 PostgreSQL 在解析时不知道这些字段:

    test=> SELECT test(42);
    ┌─────────┐
    │  test   │
    ├─────────┤
    │ (t,f,f) │
    └─────────┘
    (1 row)
    
    test=> SELECT (test(42)).*;
    ERROR:  record type has not been registered
    
    test=> SELECT * FROM test(42);
    ERROR:  a column definition list is required for functions returning "record"
    LINE 1: SELECT * FROM test(42);
                          ^
    

    您必须在查询中指定记录定义:

    test=> SELECT positive FROM test(42) test(positive boolean, negative boolean, zero boolean);
    ┌──────────┐
    │ positive │
    ├──────────┤
    │ t        │
    └──────────┘
    (1 row)
    

    但这违背了您可变记录的目标。这就是为什么此类功能不如您所引用的答案有用的原因。

    【讨论】:

    • 这里的答案:stackoverflow.com/a/6085167/4299560 说使用 RECORD 类型。这就是为什么我的问题专门询问它的原因。这似乎比每次我需要自定义结果时都创建类型更实用。
    • 是的。我已将答案扩展为专门涵盖record,以便您可以运行您的功能。
    【解决方案2】:

    这将返回一条记录,因此结果将是(真、假、假)。

    CREATE OR REPLACE FUNCTION test(v integer)
      RETURNS record AS $$
    
    DECLARE 
        result record;
    
    BEGIN
            SELECT true , false , false  into result;
    return result;
    
    END;
    

    问题是结果没有命名,所以你有这个( true, false, false),你想分别获取每个值。为此,您可以这样做:

    select a, b, c from test(1) AS (a BOOL, b bool, c bool);
    

    【讨论】:

      【解决方案3】:

      这里有一个对我有用的“返回多个值”问题的解决方案。

      坦率地说,为了解决如此普遍的需求,花了 WAAAAAY 太久了!像 OP 一样,我见过的大多数示例都过于复杂并且超出了我的想象。当然,我什至在寻找示例的唯一原因是因为 the docs 对于这个初学者来说并不清楚。希望这会对某人有所帮助。

      将以下代码粘贴到 pgAdmin 查询窗口中,选择其中一种调用解决方案,然后执行。

      create or replace function receive_two_values() returns void language plpgsql as
      $main$
      declare
          returned record;
      begin
      
          create or replace function return_two_arguments(
                  arg1    text,
                  arg2    text,
              out return1 text,
              out return2 text)
              language plpgsql as --"Returns record" is implied by multiple outs, so unnecessary here.
          $$
          begin
              return1 := arg1;
              return2 := arg2;
          end;
          $$;
      
          returned = return_two_arguments('Hello', 'World');
          raise notice 'return1="%"', returned.return1;
          raise notice 'return2="%"', returned.return2;
      
      end;
      $main$;
      
      --Invoke in one of at least two ways:
      
      --ONE:
          select receive_two_values();
      
      --TWO:
          do language plpgsql
          $$
          begin
              perform receive_two_values();
          end;
          $$;
      
      
      --Outputs:
      --NOTICE:  return1="Hello"
      --NOTICE:  return2="World"
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多