未找到行时 SELECT INTO 不会引发异常

问题描述 投票:0回答:3

我有一张空桌子

stock_holdings
:

select qty,total_amount from stock_holdings where account_id=1 and ticker_cd='XYZ';

 qty | total_amount
-----+--------------
(0 rows)

当我运行以下 PL/pgSQL 代码块时,异常应该处理这种情况。但是,我得到以下结果:

NOTICE:  before v_qty: -100
NOTICE:  before v_total_amount: -1000
NOTICE:  after v_qty: <NULL>
NOTICE:  after v_total_amount: <NULL>
DO

Query returned successfully in 70 msec.

代码块如下所示:

do 
    language plpgsql
$$
declare
v_qty numeric := -100;
v_total_amount numeric := -1000;
begin
    raise notice 'before v_qty: %', v_qty;
    raise notice 'before v_total_amount: %', v_total_amount;
    SELECT qty,total_amount INTO v_qty,v_total_amount
    FROM stock_holdings
    WHERE account_id = 1 AND ticker_cd = 'XYZ';
    raise notice 'after v_qty: %', v_qty;
    raise notice 'after v_total_amount: %', v_total_amount;
exception
    when NO_DATA_FOUND then
    raise notice 'No data found error: %', sqlstate;
    when others then
    raise notice 'Other error: %', sqlstate;
end;
$$
postgresql error-handling plpgsql
3个回答
3
投票

您需要使用

STRICT
关键字,否则如果查询没有返回行,则表达式会将变量设置为
NULL

例如。

SELECT qty,total_amount INTO STRICT v_qty, v_total_amount FROM stock_holding;

参见 https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATMENTS-SQL-ONEROW

虽然您也可以使用特殊的

FOUND
变量,如果查询返回一行
或更多
行,则该变量设置为 true。如果您使用
STRICT
关键字,则当查询返回多于一行时,会引发
TOO_MANY_ROWS
异常。

例如。

SELECT qty,total_amount INTO v_qty, v_total_amount FROM stock_holding;
IF NOT FOUND THEN
    -- logic for handling if no value for v_qty and v_total_amount
END IF;

2
投票

要让

select
加注
NO_DATA_FOUND
,您必须使用
strict
选项。目的是当您期望恰好返回 ONE 行时。

如果指定了 STRICT 选项,则该命令必须恰好返回一行,否则将报告运行时错误,NO_DATA_FOUND(无行)或 TOO_MANY_ROWS(多于一行)...

    SELECT qty,total_amount 
      INTO STRICT v_qty,v_total_amount
    FROM stock_holdings
    WHERE account_id = 1 
      AND ticker_cd = 'XYZ';

示范.


0
投票

可以添加关键字

STRICT
来引发异常,但这通常是错误的方法。引发控制流异常的成本高昂且具有破坏性。 手册警告:

包含

EXCEPTION
子句的块明显更多 进入和退出比没有进入和退出的街区昂贵。因此,不要 无需使用
EXCEPTION

使用特殊变量

FOUND
实现更简单、更便宜的控制流程:

DO
$do$
DECLARE
   v_qty numeric := -100;
BEGIN
   RAISE NOTICE 'before v_qty: %', v_qty;

   SELECT s.qty
   INTO   v_qty
   FROM   stock_holdings s
   WHERE  s.account_id = 1
   AND    s.ticker_cd = 'XYZ';

   RAISE NOTICE 'after v_qty: %', v_qty;

   -- do NOT raise an exception!
   IF NOT FOUND THEN
      RAISE NOTICE 'No data found (no error)';
   END IF;

   -- no reason to add an expensive EXCEPTION clause
END
$do$;

相关:

© www.soinside.com 2019 - 2024. All rights reserved.