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

时间:2018-11-23 14:26:20

标签: 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

任何建议都值得赞赏。

1 个答案:

答案 0 :(得分:1)

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

创建一个检查值的函数:

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

insert into data values ('foo');

将导致:

  

错误:唯一允许的值为:海洋,陆地