postgresql - Postgresql CHECK IN 列表约束的自定义错误消息

标签 postgresql function triggers check-constraints custom-error-handling

我想为 Postgres CHECK IN 违规创建更具体的错误消息。例如,在列上违反了以下 CHECK 约束:

management_zone varchar(15) NOT NULL CHECK (management_zone IN ('Marine', 'Terrestrial') ),

应该返回一条自定义错误消息,例如:“提示:检查拼写。只允许输入:'Marine'、'Terrestrial'。

到目前为止我看到的最好的解决方案是通过使用错误消息作为检查约束的名称来解决它,即

ADD CONSTRAINT c_managementzone_@Check_spelling._Only_allowed_inputs_are:_'Marine',_'Terrestrial' CHECK (management_zone IN ('Marine', 'Terrestrial') ),

然后应用一个函数来修复 @ 符号后的错误消息,方法是将下划线替换为空格以使其更具可读性。然后使用 try 和 catch 语句调用该函数。

然而,这段代码在我不熟悉的 t-sql 中,而且我对 PL/pgSQL 的了解也不够多,无法转换和复制它。因此,我想知道是否有人可以建议如何在 postgres 中完成类似的事情,例如。使用函数和触发器?

t-sql 代码和解释可从这里获得,我将其复制粘贴到下面: https://social.technet.microsoft.com/wiki/contents/articles/29187.t-sql-error-handling-for-check-constraints.aspx

CREATE FUNCTION dbo.ufnGetClearErrorMessage2()
RETURNS NVARCHAR(4000)
AS
BEGIN
    DECLARE @Msg NVARCHAR(4000) = ERROR_MESSAGE() ;
    DECLARE @ErrNum INT = ERROR_NUMBER() ;
    DECLARE @ClearMessage NVARCHAR(4000) ;
    IF @ErrNum = 547
        BEGIN
            /*--how to find @ClearMessage:
            SELECT @msg ,
               CHARINDEX('@', @msg) ,
               RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)) ,
               CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) ,
               LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ) ,
               REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'
        */
            SELECT @ClearMessage = @Msg + CHAR(13) +
            REPLACE(LEFT(RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg)), CHARINDEX('"', RIGHT(@msg, LEN(@msg) - CHARINDEX('@', @msg))) - 1 ), '_', SPACE(1)) + '.'

        END
    ELSE
        SET @ClearMessage = @Msg ;

    RETURN @ClearMessage ;
END

尝试捕获:

BEGIN TRY
INSERT  dbo.Book
        ( BookId, WritingDate, publishDate )
VALUES  ( 1, GETDATE(), GETDATE() + 1 )
END TRY
BEGIN CATCH

DECLARE @Msg NVARCHAR(4000) = dbo.ufnGetClearErrorMessage2();
THROW 60001, @Msg, 1;
END CATCH

非常感谢任何建议。

最佳答案

如果您可以接受稍微不同的检查约束,您可以执行以下操作:

创建一个检查值的函数:

create function check_zone(p_input text)
  returns boolean
as
$$
declare
  l_allowed text[] := array['Marine', 'Terrestrial'];
begin
  if p_input = any(l_allowed) then 
    return true;
  end if;
  raise 'The only allowed values are: %', array_to_string(l_allowed, ', ');
end;
$$
language plpgsql
immutable;

然后使用该函数代替 IN 条件:

create table data
(
  management_zone text not null,
  CONSTRAINT check_zone CHECK (check_zone(management_zone))
);

以下插入

insert into data values ('foo');

将导致:

ERROR: The only allowed values are: Marine, Terrestrial

关于postgresql - Postgresql CHECK IN 列表约束的自定义错误消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53448473/

相关文章:

function - 根据doc字段的字符串值在Elasticsearch中 boost 结果

附加属性上的 WPF 触发器不起作用

sql - 必须相互更新的两个表的触发器替代方案

sql - 在特定时间间隔内创建的 Postgresql 记录百分比

postgresql - postgres中的月份(仅月份)的数据类型是什么?

sql - 在 postgres 中使用函数时出现语法错误

postgresql - postgres函数返回的特定列名

c++ - 通过引用和指针传递参数 C++

postgresql - 如何将 NEW/OLD 传递给从 PostgreSQL 中的触发器函数调用的过程?

sql - 在 Postgres 中从多行到单列