【问题标题】:How to return a value from a function if no value is found如果找不到值,如何从函数返回值
【发布时间】:2015-05-31 07:53:20
【问题描述】:

如果以下函数没有返回任何内容,我正在尝试返回 0.0

CREATE OR REPLACE FUNCTION get_height(firstn VARCHAR, lastn VARCHAR)
  RETURNS FLOAT AS
$$
DECLARE
    height FLOAT = 0.0;
BEGIN
    SELECT into height AVG(((p.h_feet * 12) + p.h_inches) * 2.54)
    FROM player p
    WHERE p.firstname = firstn AND p.lastname = lastn; 

    RETURN height;
END;
$$ LANGUAGE plpgsql;

我试过搜索它,发现COALESCE 不起作用。有谁知道如何解决这个问题?

表结构:

 create table player(
                     firstname text
                    ,lastname text
                    ,h_feet INT
                    ,h_inches INT
                    );

示例数据:

  insert into player values ('Jimmy','Howard',6,2);

【问题讨论】:

  • 是的,我愿意。我发现我在将 COALESCE 添加到我的函数后重命名了我的函数,并且我不小心使用了旧函数。我觉得自己像个白痴。

标签: sql postgresql function null plpgsql


【解决方案1】:

说明

问题的根源在于“什么都不是”的模糊定义。

如果下面的函数没有返回任何东西

NULL 不是什么都没有,只是不知道它到底是什么。就 SQL 而言,“无”将是 no row:根本没有返回任何内容。这通常发生在没有找到行时。但是当使用聚合函数时,这不会发生,因为per documentation:

...当没有选择行时,这些函数返回空值。

avg() 在没有找到行时返回NULL(所以不是“无”)。您会得到一个带有 NULL 值的行作为结果 - 它覆盖您演示的代码中的 init 值。

解决方案

将结果包装在COALESCE 中。演示一个更简单的 SQL 函数:

CREATE OR REPLACE FUNCTION get_height_sql(firstn varchar, lastn varchar)
  RETURNS float AS
$func$
   SELECT COALESCE(AVG(((p.h_feet * 12) + p.h_inches) * 2.54)::float, 0)
   FROM   player p
   WHERE  p.firstname = firstn
   AND    p.lastname = lastn
$func$  LANGUAGE sql STABLE;

SQL Fiddle.

同样可以在 plpgsql 函数中使用。这个函数可以是STABLE,可能有助于在更大的查询上下文中提高性能。

其他情况

如果您确实可以从查询中获得no row,那么简单的COALESCE 将失败,因为它从未被执行。 p>

对于单值结果,您可以像这样包装整个查询:

SELECT COALESCE((SELECT some_float FROM ... WHERE ... LIMIT 1), 0) AS result

PL/pgSQL 能够在从函数实际返回之前进行检查。这也适用于具有一列或多列的多行。有一个example in the manual演示了FOUND的使用:

...
RETURN QUERY SELECT foo, bar ...;

IF NOT FOUND THEN
    RETURN QUERY VALUES ('foo_default'::text, 'bar_default'::text);
END IF;
...

相关:

要始终返回正好一行,您还可以使用纯 SQL

SELECT foo, bar FROM tbl
UNION ALL
SELECT 'foo_default', 'bar_default'
LIMIT 1;

如果第一个 SELECT 没有返回任何行,则第二个 SELECT 返回一个带有默认值的行。

【讨论】:

  • 很高兴找到答案! postgresql 中的 COALESCE 的工作方式与 sql server 不同...谢谢,先生! ?
【解决方案2】:

试试not found条件

SELECT ... into ...
FROM ...
WHERE ...; 

if not found then
  RETURN 0;
end if;

【讨论】:

    【解决方案3】:

    这是我使用的脚本。如您所见,我运行的是 PostgreSQL 9.4.1。 我使用 HeidiSQL 启动查询。 您确定您正确更新了您的功能吗? 我刚刚注意到您在评论中使用了不同的函数('player_height'),而不是原始帖子中的'get_height'。

    select version();
    -- PostgreSQL 9.4.1, compiled by Visual C++ build 1800, 64-bit
    
    delimiter //
    
    CREATE OR REPLACE FUNCTION get_height(firstn VARCHAR, lastn VARCHAR)         
    RETURNS FLOAT AS $$
    DECLARE
    height FLOAT = 0.0;
    BEGIN
        SELECT into height AVG(((p.h_feet * 12) + p.h_inches) * 2.54)
        FROM players p
        WHERE p.firstname = firstn AND p.lastname = lastn; 
            return coalesce(height, 0.0);
    END;
    $$ LANGUAGE plpgsql;
    
    delimiter;
    
    CREATE TABLE players (
         firstname varchar(40),
         lastname  varchar(40),
         h_feet int,
         h_inches int);
    
    
    insert into players values ('Jimmy', 'Howard', 6, 2);
    
    select * from get_height('Jimmy', 'Howard');
    -- gives 187.96
    
    select * from get_height('Random', 'Guy');
    -- gives 0
    

    【讨论】:

    • 我正在使用 postgreSQL 8.4.20 并且无法更新它,因为这不是我的服务器。这可能是为什么这不起作用吗?
    【解决方案4】:

    return coalesce(height, 0::decimal(10,2)); 应该可以解决问题

    【讨论】:

    • @user3376703 为什么这个解决方案不起作用?我刚试过,效果很好。
    • 刚刚尝试 SELECT * FROM player_height('DNE','DNE');它只是返回一个空列。
    • 选择 player_height('DNE', 'DNE');在这里工作正常。
    • 你使用 postgres 吗?也许有区别?我真的不知道为什么。
    • 您的选择需要包含函数调用。 select player_height('dne', 'dne') as height
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 2020-03-09
    • 1970-01-01
    相关资源
    最近更新 更多