【问题标题】:Postgres function always return a rowPostgres 函数总是返回一行
【发布时间】:2015-05-10 23:16:21
【问题描述】:

我在 Postgres 中编写了以下函数,但我遇到了一个问题:它总是返回一个 Row。我的意思是,当没有用户匹配该对时,它会返回所有列为空的行。

有没有办法让函数在没有结果时返回 0(零)行?

CREATE OR REPLACE FUNCTION find_user_by_credentials(email text, password text)
RETURNS
"User"
AS
$$
    SELECT *
        FROM "User" AS "U"
    WHERE email = "U"."Email" AND "U"."Password" = md5(password || "U"."Salt")
    ;
$$
LANGUAGE SQL IMMUTABLE STRICT;

有趣: 如果我将返回类型从“用户”更改为 TABLE("Email" text,"GivenName" text,"ID" int8, "Password" text,"Salt" text)

它按预期工作。 但我真的想使用对“用户”的“引用”,因为维护会更容易。

谢谢!

【问题讨论】:

    标签: postgresql


    【解决方案1】:

    这是一个标量函数,所以每次都要返回值。你可能需要一个 SRF 函数,Set Returning Function:

    CREATE OR REPLACE FUNCTION public.foo(boolean)
     RETURNS integer
     LANGUAGE sql
     AS $function$
      SELECT * FROM generate_series(1,2) WHERE $1;
     $function$
    
    CREATE OR REPLACE FUNCTION public.srf_foo(boolean)
     RETURNS SETOF integer
     LANGUAGE sql
     AS $function$
      SELECT * FROM generate_series(1,2) WHERE $1;
     $function$
    
    postgres=# \pset null [NULL]
    Null display is "[NULL]".
    postgres=# SELECT * FROM foo(false);
    ┌────────┐
    │  foo   │
    ╞════════╡
    │ [NULL] │
    └────────┘
    (1 row)
    
    postgres=# SELECT * FROM srf_foo(false);
    ┌─────────┐
    │ srf_foo │
    ╞═════════╡
    └─────────┘
    (0 rows)
    

    这可能有点奇怪,因为 PostgreSQL 区分标量函数和 SRF 函数,但允许将 SRF 用作标量,将标量用作 SRF(但最好在 FROM 子句中使用 SRF 函数,在查询表达式中使用标量函数:

    postgres=# SELECT srf_foo(false);
    ┌─────────┐
    │ srf_foo │
    ╞═════════╡
    └─────────┘
    (0 rows)
    
    postgres=# SELECT foo(false);
    ┌────────┐
    │  foo   │
    ╞════════╡
    │ [NULL] │
    └────────┘
    (1 row)
    

    您可以看到,SRF 功能正在工作:

    postgres=# SELECT * FROM srf_foo(true);
    ┌─────────┐
    │ srf_foo │
    ╞═════════╡
    │       1 │
    │       2 │
    └─────────┘
    (2 rows)
    

    对于您的示例 - 只需将 return 子句更改为 RETURNS SETOF "User"

    【讨论】:

      【解决方案2】:

      您需要将返回类型从 "user" 更改为 SETOF "user"。在单行类型的情况下,该函数将始终生成一行 - 有或没有值,而使用 SETOF 将允许返回由零行或多行组成的集合。我还将函数的语言从 SQL 更改为 PLPGSQL:

      CREATE OR REPLACE FUNCTION find_user_by_credentials(email text, password text)
      RETURNS SETOF "user" AS $$
      DECLARE
        user_row RECORD;
      BEGIN
        SELECT INTO user_row *
        FROM "user" AS "U"
        WHERE "U".email = "U"."email"
        AND "U"."password" = md5("U"."password" || "U"."salt");
        IF FOUND THEN
          RETURN NEXT user_row;
        END IF;
        RETURN;
      END;
      $$
      LANGUAGE plpgsql VOLATILE;
      

      【讨论】:

      • 请注意 - 从性能角度来看,将 plpgsql 用于这些琐碎的功能并不好。由于内联到外部查询,SQL 通常可以明显更快。其他注意事项 - 如果你必须使用 plpgsql - 那么你可以将你的例子减少到一个语句 - `RETURN QUERY ...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-16
      • 2013-08-01
      • 2013-03-25
      • 2021-10-27
      • 2016-07-21
      相关资源
      最近更新 更多