0

在使用 UTF8 编码的 PostgreSQL 8.4.13 数据库中,我在此表中保留了一个(非英语)字典:

create table good_words (
        word varchar(64) primary key
);

以及以下错误(但经常建议或输入错误)单词的列表:

create table bad_words (
        word varchar(64) primary key
);

对于前一个表,我有一个BEFORE INSERT 触发器,我正在尝试扩展它:

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();

我的问题是:我正在尝试NULL向我的触发器添加 3 条规则(返回):

  1. 禁止使用以 X、Y 或 Z 字母开头的单词
  2. 禁止以 Z 字母结尾的单词
  3. 连续 3 个相同字母的单词非常罕见,只有在出现时才允许使用like '%KLLL%' or like '%MLLL%'

作为 Perl 程序员,我非常了解正则表达式,但我的问题是 Pl/PgSQL 部分 - 如何在该语言中执行正则表达式匹配,我总是必须使用SELECT INTOorPERFORM吗?或者我可以:=在这里使用运算符,甚至可以在IF语句中执行字符串匹配?

更新:

经过克雷格的解释(谢谢!)我准备了以下 SQL Fiddle,但它仍然存在2个问题:

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:触发器现在可以工作了,谢谢:http ://sqlfiddle.com/#!11/98403/1

4

1 回答 1

2

使用 PostgreSQL 的~运算符或regexp_matches函数。请参阅文档中的模式匹配

简单的 PL/PgSQL 示例:

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

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

于 2013-03-19T13:18:22.597 回答