ruby-on-rails - Rails Postgres 插入重复行检查问题

标签 ruby-on-rails postgresql duplicates

我正在尝试检测并静默丢弃任何重复的 INSERT 到表中,如果检测到重复,则返回现有记录的 ID(主键)。否则,插入记录并返回新的 ID。

我可以使用 RULE 或 TRIGGER 来做到这一点,但是两者都有缺点。这是我的规则示例:

CREATE OR REPLACE RULE territory_products_ignore_duplicate_inserts AS
ON INSERT TO territory_products
WHERE (EXISTS ( SELECT 1
       FROM territory_products tp
      WHERE tp.territory_id = NEW.territory_id AND tp.product_id = NEW.product_id)) DO INSTEAD SELECT tp.id
       FROM territory_products tp WHERE tp.territory_id = NEW.territory_id AND tp.product_id = NEW.product_id LIMIT 1;

在 SQL 控制台或带有 INSERT 的 psql 中测试它工作正常。如果存在欺骗,它将返回第一个现有记录的 ID,而不执行 INSERT。否则,它将继续执行 INSERT。但是,在 Rails 中,它会失败并返回此错误:

错误:无法对关系“territory_products”执行插入返回 提示:您需要一个带有 RETURNING 子句的无条件 ON INSERT DO INSTEAD 规则。

转向触发,我试试这个:

CREATE OR REPLACE Function territory_products_ignore_dups() Returns Trigger
As $$
Begin
If Exists (
    Select id From territory_products tp
    Where tp.territory_id = NEW.territory_id And tp.product_id = NEW.product_id            
) Then
    Return NULL;
End If;
Return NEW;
End;
$$ Language plpgsql;

Create Trigger territory_products_ignore_dups
Before Insert On territory_products
For Each Row
Execute Procedure territory_products_ignore_dups();

这也可以正常工作,除了我无法让它返回现有 ID,因为 Return NULL(这是禁止 INSERT 所必需的)。

任何人都可以解决这些问题中的任何一个,以便我得到我正在寻找的结果吗? (例如,在发生重复的情况下静默丢弃 INSERT 并返回现有记录的 ID。或者如果 INSERT 成功,则返回新记录的 ID)。

最佳答案

为您的数据库添加唯一索引:

# migration file
add_index : territory_products, [:territory_id, :product_id], unique: true

在您的逻辑中查找现有记录,如果不存在则创建。如果出现竞争条件,它将引发异常。重新搜索记录即可。

#logic when finding/creating record
begin
  TerritoryProduct.where(territory_id: params[:territory_id], product_id: params[:product_id]).first_or_create!
rescue ActiveRecord::RecordNotUnique
  # In case it already exists
  TerritoryProduct.where(territory_id: params[:territory_id], product_id: params[:product_id]).first
end

关于ruby-on-rails - Rails Postgres 插入重复行检查问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45513357/

相关文章:

ruby-on-rails - 如何管理造成停机的旅客过时 worker

ruby-on-rails - 清除 Rails 中单元测试和功能测试之间的测试数据库 (factory_girl)

ruby-on-rails - 将 HTML 转换为适当的纯文本?

postgresql - 每次 postgres super 用户登录到 postgres 数据库时,如何生成(电子邮件)警报

django - 将现有数据库卷到容器的最佳方法是什么?

php - 如何在 php 中获取重复的多维数组

javascript - "family"在 Assets 管道的上下文中意味着什么?

postgresql - 无法使用Postgresql或Redshift驱动程序连接到Redshift服务器

c# - 在列表中查找连续的重复项

list - 从方案中的列表中删除负值