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

私の問題は次のとおりです。トリガーに3つのルールを追加しようとしています(NULLを返します):

  1. X、Y、Z の文字で始まる単語は禁止されています
  2. Z文字で終わる単語は禁止されています
  3. 3 つの同じ文字が連続する単語は非常にまれであり、次の場合にのみ許可されます。like '%KLLL%' or like '%MLLL%'

Perl プログラマーとして、私は正規表現をよく知っていますが、私の問題は Pl/PgSQL の部分です。その言語で正規表現マッチングを実行するには、常に or を使用する必要がありますSELECT INTOPERFORM? :=または、ここで演算子を使用したり、IFステートメント内で文字列の一致を実行したりできますか?

アップデート:

Craig の説明の後 (ありがとう!) 、次の 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 エンコーディングの最初の 2 語を使用するべきではありませんが、次のようになります。

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 に答える