【问题标题】:Why does function i PostgreSQL not raise exception?为什么函数 i PostgreSQL 不会引发异常?
【发布时间】:2021-01-28 05:41:14
【问题描述】:

我有一个插入或更新前触发器,它应该验证插入/更新数据中两列的值,如果数据无效或 - 如果有效 - 将值添加到插入中的其他两列,则引发异常/更新。

但是,当我使用无效数据进行测试时,我得到“错误:查询没有结果数据的目的地。提示:如果您想丢弃 SELECT 的结果,请改用用户执行。上下文:PL/pgSQL 函数 before_insert_update() SQL 语句的第 3 行。”

我曾尝试阅读 PostgreSQL 文档并在 Google 上搜索解释,但我只需要管理一下,我对 SQL 的理解不足以使其正常工作。

我的功能是

CREATE or replace FUNCTION before_insert_update()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
begin
    select * from addresses
    where addresses.roadname = NEW.roadname and
        addresses.housenumber = NEW.housenumber;

    if @@ROWCOUNT > 0 then
        begin
            select addresses.roadcode,
                    addresses.geom
                into NEW.roadcode, NEW.geom
            from addresses
            where addresses.roadname = NEW.roadname and
                addresses.housenumber = NEW.housenumber;

            return NEW;
        end;
    else
        declare _adresse text;
        begin
            _address := concat(NEW.roadname, ' ', NEW.housenumber);
            raise exception 'The address does not exist: %', _address
                using hint = 'Check the address here: https://danmarksadresser.dk/adresser-i-danmark/';
        end;
    end if;
END
$BODY$;

触发器非常简单

BEFORE INSERT OR UPDATE
ON table
FOR EACH ROW
EXECUTE PROCEDURE before_insert_update();

我做错了什么?

【问题讨论】:

  • 将您的第一个 select 替换为 perform 并可能使用 if FOUND
  • 该函数一开始不会编译
  • 编译时没有错误

标签: postgresql function plpgsql


【解决方案1】:

如果该行存在,则无需运行测试。只需选择它,然后check the status

CREATE or replace FUNCTION before_insert_update()
    RETURNS trigger
    LANGUAGE plpgsql
    COST 100
    VOLATILE NOT LEAKPROOF
AS 
$BODY$
begin
  select addresses.roadcode, addresses.geom
      into NEW.roadcode, NEW.geom
  from addresses
  where addresses.roadname = NEW.roadname and
        addresses.housenumber = NEW.housenumber;
        
  if found then 
    return new;
  end if;
    
  raise exception 'The address does not exist: %', concat(NEW.roadname, ' ', NEW.housenumber)
    using hint = 'Check the address here: https://danmarksadresser.dk/adresser-i-danmark/';
END
$BODY$;

【讨论】:

    【解决方案2】:

    看起来您正试图在 Postgres 中使用 SQL Server 特定代码,这当然行不通。

    PL/pgSQL 不允许在任何地方使用SELECTs,当结果没有传递给某个变量时,比如变量等。并且没有@@ROWCOUNT。从我可以猜到你想要做什么,你可以使用EXISTS 和你对IF 条件的查询。

    CREATE 
     OR REPLACE FUNCTION before_insert_update()
                         RETURNS trigger
    AS
    $$
    BEGIN
      IF EXISTS(SELECT *
                       FROM addresses
                       WHERE addresses.roadname = new.roadname
                             AND addresses.housenumber = new.housenumber) THEN
        SELECT addresses.roadcode,
               addresses.geom
               INTO new.roadcode,
                    new.geom
               FROM addresses
               WHERE addresses.roadname = new.roadname
                     AND addresses.housenumber = new.housenumber;
    
        RETURN new;
      ELSE
        RAISE EXCEPTION 'The address does not exist: %', concat(new.roadname, ' ', new.housenumber)
                        USING HINT = 'Check the address here: https://danmarksadresser.dk/adresser-i-danmark/';
    
    
      END IF;
    END
    $$
    LANGUAGE plpgsql;
    

    【讨论】:

    • 过去四年我一直主要使用 SQL Server,所以是的,我可能正在使用 SQL Server 特定代码。我没有尝试过您的代码,因为上面的代码更简单并且可以完美运行。但感谢您的帮助。
    猜你喜欢
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多