Postgresql 插入触发器中的字符串匹配-如何在条件中使用以返回NULL?

Postgresql 插入触发器中的字符串匹配-如何在条件中使用以返回NULL?,postgresql,triggers,plpgsql,string-matching,postgresql-8.4,Postgresql,Triggers,Plpgsql,String Matching,Postgresql 8.4,在采用UTF8编码的PostgreSQL 8.4.13数据库中,我在下表中保留了一本(非英语)词典: create table good_words ( word varchar(64) primary key ); 以及下列错误(但经常提示或键入错误)单词的列表: create table bad_words ( word varchar(64) primary key ); 对于前一个表,我有一个我正在尝试扩展的表: create or replace f

在采用UTF8编码的PostgreSQL 8.4.13数据库中,我在下表中保留了一本(非英语)词典:

create table good_words (
        word varchar(64) primary key
);
以及下列错误(但经常提示或键入错误)单词的列表:

create table bad_words (
        word varchar(64) primary key
);
对于前一个表,我有一个我正在尝试扩展的表:

create or replace function keep_clean() returns trigger as $body$
        begin
                new.word := upper(new.word);

                perform true
                        from bad_words
                        where word = new.word;

                if found then
                        return null;
                end if;

                -- forbid words with [XYZ] at beginning and Z at the end
                -- forbid words with LLL unless it is KLLL or MLLL

                return new;
        end;
$body$ language plpgsql;

create trigger count_letters
        BEFORE INSERT on good_words
        for each row execute procedure keep_clean();
我的问题是:我正在尝试向触发器添加3条规则(返回
NULL
):

  • 禁止使用以X、Y或Z字母开头的单词
  • 禁止使用以Z字母结尾的单词
  • 一行中有3个相同字母的单词非常罕见,只有在
    类似“%KLLL%”或类似“%MLLL%”的情况下才允许使用这些单词。
  • 作为Perl程序员,我很了解正则表达式,但我的问题是Pl/PgSQL部分——如何在该语言中执行正则表达式匹配,我是否总是必须使用
    SELECT-INTO
    perform
    ?或者我可以在这里使用
    :=
    运算符,或者甚至可以在
    IF
    语句中执行字符串匹配

    更新:

    在Craig的解释(谢谢!)之后,我已经准备好了,但它仍然有两个问题:

    create table good_words (
            word varchar(64) primary key
    );
    
    create or replace function keep_clean() returns trigger as $body$
            begin
                    new.word := upper(new.word);
    
                    /* next line does not compile? */
                    IF new.word !~ '^[\x0410-\x042F]{2,}$' THEN
                        RAISE EXCEPTION 'Not an uppercased Russian word in UTF8';
                    END IF;
    
                    IF new.word ~ '^[ЪЫЬ]' OR new.word ~ 'Ъ$' THEN
                        return NULL;
                    END IF;
    
                    /* does not return NULL for 'ошибббка'? */
                    IF new.word ~ '(.)\1\1' AND new.word NOT LIKE '%ШЕЕЕ%' AND new.word NOT LIKE '%ЗМЕЕЕ%' THEN
                        return NULL;
                    END IF;
    
                    return new;
            end;
    $body$ language plpgsql;
    
    此处不应采用UTF8编码中的前两个单词,但它确实:

    insert into good_words (word)
      values
        ('abcde'),          /* bad word: non-russian */
        ('ошибббка'),       /* bad word: 3 letters in a row */
        ('длинношеее'),
        ('проверка')
    ;
    
    select * from good_words;
    

    更新2:触发器现在可以工作了,谢谢:

    使用PostgreSQL的
    ~
    运算符或
    regexp\u matches
    函数。请参阅文档中的

    简单的PL/PgSQL示例:

    DO
    $$
    BEGIN
      IF 'XABCK' ~ '^[XY]' THEN
        RAISE EXCEPTION 'Disallowed character';
      END IF;
    END;
    $$;
    

    如您所见,
    IF
    可以接受表达式。这些表达式可能具有任意复杂性,可能包括子查询、
    CASE
    ,几乎所有SQL中合法的内容。

    谢谢!你能看看我的SQL小提琴中的两个问题吗?我已经更新了我的问题too@AlexanderFarber升级PostgreSQL;我敢肯定,在8.4中,regex中对utf-8的支持相当缺乏。您的“俄语单词”regexp在9.2上编译并运行良好。您为什么不为此创建一个检查约束?我反复向我的
    good_words
    表中输入新词以扩展词典,并希望不好的单词只是无声地失败-这与检查约束不同。我在插入触发器中还做了更多的工作:我计算字母频率,并将其存储在数组列中(在我的问题中省略),用于文字游戏。