【问题标题】:Postgresql regex in tsvector updatetsvector 更新中的 Postgresql 正则表达式
【发布时间】:2012-12-06 11:27:02
【问题描述】:

我有一个 tsvector 列的以下更新触发器

CREATE TRIGGER tsvector_user_update
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE 
tsvector_update_trigger(user_tsv, 'pg_catalog.english', firstname, surname, email, card_id);

这很好用,但是我的 card_id 列(文本)包含一个用户不知道的前导(它是在扫描卡后添加的),所以我想在生成tsvector值,我已经尝试过触发函数作为开始

CREATE FUNCTION user_change_trigger() RETURNS trigger AS $$
BEGIN
NEW.user_tsv = setweight(to_tsvector('pg_catalog.english', coalesce(NEW.firstname,'')), 'A') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(NEW.surname,'')), 'A') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(REGEXP_REPLACE(NEW.card_id, '^\d+PRE', ''),'')), 'B') ||
    setweight(to_tsvector('pg_catalog.english', coalesce(NEW.email,'')), 'C');
    return new;
END

$$ LANGUAGE plpgsql;

CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON users FOR EACH ROW EXECUTE PROCEDURE user_change_trigger();

执行,但我得到以下信息:

WARNING:  nonstandard use of escape in a string literal

而且没有更新的 tsvector

前导码是一个整数,后跟“PRE”。

(PostgreSQL 9.0)

【问题讨论】:

  • 应该很明显,示例值是按顺序排列的。 regexp_replace() 的结果是你有什么,你想要什么。而且“没有成功”似乎不是我所知道的 PostgreSQL 的错误消息 ..
  • 正则表达式并不是真正相关的,我真的很想知道是否可以在将列内容放入 tsvector_update_trigger 方法之前对其进行修改,正如您在下面所说的那样,这是不可能的,我需要写一个触发函数

标签: sql postgresql triggers postgresql-9.0 tsvector


【解决方案1】:

基本触发器设计

这个问题是主要性质的。在 PostgreSQL 中,您创建一个 触发函数 来完成这项工作。我在问题中看不到您的触发功能。

然后你创建一个 trigger 来使用这个函数。您只能将 constants 传递给触发函数。考虑一下the manual about CREATE TRIGGER的这句话

函数名

一个用户提供的函数,声明为不带参数和 返回类型触发器,在触发器触发时执行。

参数

提供给 触发器执行时的函数。 参数是字面的 字符串常量。可以编写简单的名称和数字常量 这里也一样,但它们都将被转换为字符串。请检查 触发器函数的实现语言的描述 找出如何在函数中访问这些参数;它 可能与普通函数参数不同。

我的大胆强调。

使用NEW 访问触发器函数内的列值。您不需要将它们作为参数传递。首先掌握基本概念。 Start here.

regexp_replace()

用途:

regexp_replace(card_id, '^\d+PRE', '')

.. 因为前导字符应该只是数字(并且至少是其中一个)。

适当的触发器和功能

以下测试用例适用于我在 PostgreSQL 9.1.6 上。你的版本对我来说基本不错,我只做了一些小的改动。但请继续阅读...

创建测试环境(最后会回滚):

BEGIN;
CREATE SCHEMA test;
SET search_path = test;

CREATE TABLE users (
    users_id serial primary key
   ,firstname text
   ,surname text
   ,card_id text
   ,email text
   ,user_tsv tsvector
   );

触发功能:

CREATE FUNCTION user_change_trigger()
  RETURNS trigger AS
$func$
BEGIN

NEW.user_tsv :=
   setweight(to_tsvector('pg_catalog.english', coalesce(NEW.firstname,'')), 'A')
|| setweight(to_tsvector('pg_catalog.english', coalesce(NEW.surname,'')), 'A')
|| setweight(to_tsvector('pg_catalog.english', coalesce(regexp_replace(NEW.card_id, '^\d+PRE', ''),'')), 'B')
|| setweight(to_tsvector('pg_catalog.english', coalesce(NEW.email,'')), 'C');

RETURN NEW;
END

$func$ LANGUAGE plpgsql;

assignment operator of plpgsql is := - 与使用 = 的 SQL 不同。

触发器:

CREATE TRIGGER tsvectorupdate
BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE user_change_trigger();

测试:

INSERT INTO users (firstname, surname, card_id, email)
VALUES ('Erwin', 'Brandstetter', '123PRE456', 'foo@dummy.org')
RETURNING *;

-- looks good!

UPDATE users SET firstname = 'Walter' WHERE TRUE
RETURNING *;

-- looks good, too!

清理:

ROLLBACK;

standard_conforming_strings

探索standard_conforming_strings 的设置。 WARNING 表明您没有启用此设置,这需要您将反斜杠加倍:

'^\\d+PRE'

【讨论】:

  • 感谢您将我指向文档并更正正则表达式,经过一番阅读后,我尝试编写触发函数(请参阅更新的问题),但我是 plpgsql 新手,因此不胜感激
  • @DaveB:我在答案中添加了更多内容。
  • 谢谢 Erwin,我设置了 standard_conforming_strings = 1,它就像你说的那样工作。很好的答案:)
猜你喜欢
  • 1970-01-01
  • 2022-11-12
  • 2018-11-22
  • 2010-10-30
  • 2011-01-31
  • 2011-09-07
  • 2013-12-10
  • 1970-01-01
  • 2011-04-18
相关资源
最近更新 更多