【问题标题】:PostgreSQL Exception HandlingPostgreSQL 异常处理
【发布时间】:2011-06-20 03:25:57
【问题描述】:

我是 PostgreSQL 新手。谁能更正这个查询。

BEGIN TRANSACTION;

BEGIN;
    CREATE TABLE "Logs"."Events"
    (
        EventId BIGSERIAL NOT NULL PRIMARY KEY,
        PrimaryKeyId bigint NOT NULL,
        EventDateTime date NOT NULL DEFAULT(now()),
        Action varchar(12) NOT NULL,
        UserId integer NOT NULL REFERENCES "Office"."Users"(UserId),
        PrincipalUserId varchar(50) NOT NULL DEFAULT(user)
    );

    CREATE TABLE "Logs"."EventDetails"
    (
        EventDetailId BIGSERIAL NOT NULL PRIMARY KEY,
        EventId bigint NOT NULL REFERENCES "Logs"."Events"(EventId),
        Resource varchar(64) NOT NULL,
        OldVal varchar(4000) NOT NULL,
        NewVal varchar(4000) NOT NULL
    );


    COMMIT TRANSACTION;
    RAISE NOTICE 'Task completed sucessfully.'
EXCEPTION;
    ROLLBACK TRANSACTION;
    RAISE ERROR @ErrorMessage, @LineNumber, @ErrorState --how to catch errors and display them????
END;

问题:

  1. 如何在 T-SQL 中打印类似“PRINT”的消息?
  2. 如何使用异常信息引发错误?

【问题讨论】:

  • 你用什么语言写作?您似乎将 C 宏与直接 SQL 语句混合在一起,并且在标签中说“plpgsql”。
  • 我是 postgres 的新手。你能指导我在 postgres 查询中实现这个吗?
  • 谢谢。已编辑。我尝试了其他几种语法,但徒劳无功。

标签: postgresql plpgsql


【解决方案1】:

捕获错误消息及其代码:

do $$       
begin

    create table yyy(a int);
    create table yyy(a int); -- this will cause an error

exception when others then 

    raise notice 'The transaction is in an uncommittable state. '
                 'Transaction was rolled back';

    raise notice '% %', SQLERRM, SQLSTATE;

end; $$ 
language 'plpgsql';

还没找到行号

2019 年 4 月 16 日更新

按照 Diego Scaravaggi 的建议,对于 Postgres 9.2 及更高版本,请使用 GET STACKED DIAGNOSTICS

do language plpgsql $$
declare
    v_state   TEXT;
    v_msg     TEXT;
    v_detail  TEXT;
    v_hint    TEXT;
    v_context TEXT;
begin

    create table yyy(a int);
    create table yyy(a int); -- this will cause an error

exception when others then 

    get stacked diagnostics
        v_state   = returned_sqlstate,
        v_msg     = message_text,
        v_detail  = pg_exception_detail,
        v_hint    = pg_exception_hint,
        v_context = pg_exception_context;

    raise notice E'Got exception:
        state  : %
        message: %
        detail : %
        hint   : %
        context: %', v_state, v_msg, v_detail, v_hint, v_context;

    raise notice E'Got exception:
        SQLSTATE: % 
        SQLERRM: %', SQLSTATE, SQLERRM;     

    raise notice '%', message_text; -- invalid. message_text is contextual to GET STACKED DIAGNOSTICS only

end; $$;

结果:

NOTICE:  Got exception:
        state  : 42P07
        message: relation "yyy" already exists
        detail : 
        hint   : 
        context: SQL statement "create table yyy(a int)"
PL/pgSQL function inline_code_block line 11 at SQL statement
NOTICE:  Got exception:
        SQLSTATE: 42P07 
        SQLERRM: relation "yyy" already exists

ERROR:  column "message_text" does not exist
LINE 1: SELECT message_text
               ^
QUERY:  SELECT message_text
CONTEXT:  PL/pgSQL function inline_code_block line 33 at RAISE
SQL state: 42703

除了GET STACKED DIAGNOSTICS 符合 SQL 标准之外,它的诊断变量(例如,message_text)仅与 GSD 相关。因此,如果您的表中有一个名为 message_text 的字段,则 GSD 不可能干扰您的字段值。

仍然没有行号。

【讨论】:

  • 如果一条语句失败,postgres 会自动发出回滚吗?是否不需要显式回滚?
  • 是的。如果您处于事务中(在“开始”之后但在“提交”或“回滚”之前)并且发生错误,那么自“开始”以来的所有内容都会回滚。
  • 如何获取raise notice '% %', SQLERRM, SQLSTATE; 并将这些数据放入各种表格中
  • 自 9.2 版起 GET STACKED DIAGNOSTICS myVariable = PG_EXCEPTION_CONTEXT;非常有用。
【解决方案2】:

使用DO statement,9.0 版中的一个新选项:

DO LANGUAGE plpgsql
$$
BEGIN
CREATE TABLE "Logs"."Events"
    (
        EventId BIGSERIAL NOT NULL PRIMARY KEY,
        PrimaryKeyId bigint NOT NULL,
        EventDateTime date NOT NULL DEFAULT(now()),
        Action varchar(12) NOT NULL,
        UserId integer NOT NULL REFERENCES "Office"."Users"(UserId),
        PrincipalUserId varchar(50) NOT NULL DEFAULT(user)
    );

    CREATE TABLE "Logs"."EventDetails"
    (
        EventDetailId BIGSERIAL NOT NULL PRIMARY KEY,
        EventId bigint NOT NULL REFERENCES "Logs"."Events"(EventId),
        Resource varchar(64) NOT NULL,
        OldVal varchar(4000) NOT NULL,
        NewVal varchar(4000) NOT NULL
    );

    RAISE NOTICE 'Task completed sucessfully.';    
END;
$$;

【讨论】:

    【解决方案3】:

    你可以把它写成一个 psql 脚本,例如,

    START TRANSACTION;
    CREATE TABLE ...
    CREATE TABLE ...
    COMMIT;
    \echo 'Task completed sucessfully.'
    

    并运行

    psql -f somefile.sql
    

    在 PostgreSQL 中不能直接使用参数引发错误。在移植此类代码时,有些人会将必要的信息编码在错误字符串中,并在必要时将其解析出来。

    这一切都有点不同,所以要准备好重新学习/重新思考/重写很多东西。

    【讨论】:

      【解决方案4】:

      只想在这个旧帖子上加两分钱:

      在我看来,几乎所有的关系数据库引擎都包括在执行 DDL 命令后自动执行提交事务,即使你有 autocommit=false,所以你不需要启动事务来避免潜在的截断对象创建,因为这是完全没有必要的。

      【讨论】:

      • 这对 Postgres 来说是错误的。 DDL 是事务性的,就像 UPDATE 语句一样。
      • 不适用于 Db2 和 sql server,因此几乎所有内容都可能有点误导。
      • 我认为这对于 Oracle 和 Sybase 以及其他评论员提到的数据库引擎来说都是错误的。当 Postgres、Oracle、Sybase、SQL Server 和 DB2 都被排除在外时,我想知道您所说的“几乎所有”是什么意思。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-10
      • 2015-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多