【问题标题】:PSQL Database Update trigger update procedure works. But insert procedure doesn'tPSQL 数据库更新触发器更新过程有效。但是插入过程没有
【发布时间】:2020-03-25 22:59:11
【问题描述】:

我目前正在尝试为我的 rails 应用程序实现 Postgres 文本搜索。我的迁移成功运行,创建了所有表。我的一个迁移添加了一个触发器来更新我的列表表上的 ts_vector 列 (TSV)。它在表上执行一堆连接,在中间表上执行两个连接。不确定这个触发器是否是最有效的,但是当它被过程调用时它会起作用。

CREATE OR REPLACE FUNCTION update_listings_tsv() RETURNS trigger AS $$
BEGIN
 NEW.tsv := (
   SELECT
     setweight(to_tsvector(l.item_name), 'A') ||
     setweight(to_tsvector(l.description), 'B') ||
     setweight(to_tsvector(categories.name), 'B') ||
     setweight(to_tsvector(sub_categories.name), 'B') ||
     setweight(to_tsvector(sizes.name), 'B') ||
     setweight(to_tsvector(users.username), 'C') ||
     setweight(to_tsvector(string_agg(DISTINCT brands.name, ',')), 'A') ||
     setweight(to_tsvector(string_agg(DISTINCT colours.name, ',')), 'B')


   FROM listings l
   JOIN users ON users.id = l.user_id
   JOIN categories ON categories.id = l.category_id
   JOIN sub_categories ON sub_categories.id = l.sub_category_id
   JOIN sizes ON sizes.id = l.size_id
   JOIN conditions ON conditions.id = l.condition_id


   JOIN brands_listings ON brands_listings.listing_id = l.id
   JOIN brands ON brands.id = brands_listings.brand_id

   JOIN colours_listings ON colours_listings.listing_id = l.id
   JOIN colours ON colours.id = colours_listings.colour_id


   WHERE l.id = NEW.id
   GROUP BY l.id, users.id, categories.id, sub_categories.id, sizes.id, conditions.id
 );
 RETURN NEW;
END;
$$ LANGUAGE plpgsql;

这就是问题所在:

调用触发器的更新过程工作正常。正如预期的那样,当列表列更新时,该确切列表的 TSV 列也会更新。

CREATE TRIGGER tsvectorupdateupdate BEFORE UPDATE
ON listings FOR EACH ROW EXECUTE PROCEDURE update_listings_tsv();

插入过程不起作用。我已经在插入之前和之后尝试过。我不知道问题出在哪里。在 db:reset 之后,TSV 列应该已经填充了 ts_vector 值。

CREATE TRIGGER tsvectorupdateinsert AFTER INSERT OR UPDATE
ON listings FOR EACH ROW EXECUTE PROCEDURE update_listings_tsv(tsv);

【问题讨论】:

  • 更新前触发器调用改变NEW.tsv值的触发器函数。 After 触发器无法更改插入/更新的记录 (NEW) 值。好吧 - 你不会得到错误 - 但它对存储的记录没有影响。

标签: ruby-on-rails postgresql pg-search


【解决方案1】:

如果您执行 AFTER 触发器,则更改该值为时已晚。如果您执行 BEFORE 触发器,那么加入“列表”表中的(尚不存在的)行还为时过早。您需要从 NEW 中获取新数据,而不是从“列表”中获取。

我已将其简化为最小的本质,用额外的表格和列来充实它取决于你:

CREATE OR REPLACE FUNCTION update_listings_tsv() RETURNS trigger AS $$
BEGIN
 NEW.tsv := (
   SELECT
     setweight(to_tsvector(NEW.item_name), 'A') ||
     setweight(to_tsvector(users.username), 'C')
   FROM users where users.id = NEW.user_id   
 );
 RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER tsvectorupdateinsert BEFORE INSERT OR UPDATE    
ON listings FOR EACH ROW EXECUTE PROCEDURE update_listings_tsv();

【讨论】:

  • 所以在我的情况下,这看起来像` CREATE OR REPLACE FUNCTION update_listing_tsv() RETURNS trigger AS $$ BEGIN NEW.tsv := ( SELECT setweight(to_tsvector(NEW.item_name), 'A ') || setweight(to_tsvector(NEW.description), 'C') FROM listings.id = NEW.id );返回新的;结尾; $$ 语言 plpgsql;在插入或更新列表之前创建触发器 tsvectorupdate 每行执行过程 update_listing_tsv(); `
  • 这适用于列表行的更新,但同样不适用于新列表行的插入/创建。无论如何,谢谢您的回复,这让我对这个问题有了更多的思考。当我获得新插入行的 TSV 列以在创建时填充时,我将使用修复程序更新此问题。
  • 不,您仍在从“列表”中进行选择。您需要从除了“listings”之外的每个表中进行选择,使用 NEW 代替“listings”。
猜你喜欢
  • 2013-09-07
  • 2013-11-12
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2013-03-06
  • 2022-01-05
相关资源
最近更新 更多