【问题标题】:Shouldn't this PostgreSQL function return zero rows?这个 PostgreSQL 函数不应该返回零行吗?
【发布时间】:2014-05-07 04:05:04
【问题描述】:

给定架构

CREATE TABLE users (
    id bigserial PRIMARY KEY,
    email varchar(254) NOT NULL
);
CREATE UNIQUE INDEX on users (lower(email));

CREATE FUNCTION all_users() RETURNS users AS $$
    SELECT * FROM users;
$$ LANGUAGE SQL STABLE;

,不应该SELECT * FROM all_users()(假设users 表为空)不返回任何行,而不是返回所有null 值的行吗?

在此处查看 SQL Fiddle:http://sqlfiddle.com/#!15/b5ba8/2

【问题讨论】:

    标签: sql postgresql user-defined-functions return-type create-function


    【解决方案1】:

    那是因为您的功能在设计上被破坏了。应该是:

    CREATE FUNCTION all_users() RETURNS SETOF users AS
    'SELECT * FROM users' LANGUAGE sql STABLE;

    或者,更灵活的形式RETURNS TABLE (...)like @Clodoaldo posted。但通常使用RETURNS SETOF usersSELECT * FROM users 进行查询更为明智。

    您的原始函数始终返回单个值(复合类型),它已以这种方式声明。如果您插入一些行,它将以更壮观的方式中断。

    考虑一下SQL Fiddle demo

    为了更好地理解,你的函数调用和这个普通的 SELECT 查询一样:

    SELECT (SELECT u from users u).*;
    

    返回:

    id     | email
    -------+------
    <NULL> | <NULL>
    

    区别:如果子查询返回多行,普通 SQL 将引发异常,而函数将只返回第一行并丢弃其余行。

    As always, details in the manual.

    【讨论】:

    • 谢谢!我为这个问题简化了我的功能。我的真实函数的最后一行要么插入一行,要么不插入行,比如stackoverflow.com/a/12160777/242933。似乎我仍然应该将SETOF 用于INSERT RETURNING,因为如果我插入多个值(尽管我不是)和“如果 INSERT 命令包含 RETURNING 子句,则结果将类似于包含 RETURNING 列表中定义的列和值的 SELECT 语句,根据命令插入的行计算。” postgresql.org/docs/9.3/static/sql-insert.html
    【解决方案2】:

    您的函数返回records。所以它必须至少返回一条记录。如果你想要一个空的结果集,请返回一个表:

    CREATE or replace FUNCTION all_users()
    RETURNS table (id bigint, email varchar(254)) AS $$
        SELECT id, email FROM users;
    $$ LANGUAGE SQL STABLE;
    

    【讨论】:

    • OP 的函数实际上并没有返回“记录”,也没有返回“至少一条记录”。它返回单个复合类型(或“行类型”,如果您愿意的话) - 就像声明的那样。您的链接完全正确。
    • 也说必须返回至少一条记录有点误导 - 它必须只返回一行。如果没有 - 返回一个填充了空值的行。
    猜你喜欢
    • 2011-10-16
    • 1970-01-01
    • 2018-11-09
    • 2013-04-13
    • 1970-01-01
    • 2018-05-30
    • 2018-07-02
    • 1970-01-01
    • 2018-10-11
    相关资源
    最近更新 更多