在PostgreSQL中使用Activerecord-import进行非唯一列的upsert

3
我正在尝试使用activerecord-import来导入数据,但遇到了问题。如果行已经存在,则需要更新该行,否则需要创建新行。表中唯一的行由两列的组合定义,其中每个列的值在表中可能不是唯一的。如何使用on_duplicate_key_update的conflict_target,因为这些列不是唯一的列。
现在让我们来看细节。我有一个名为Order的模型,在Order模型中,以下是列的简化版本。
id
order_number
sku_number
quantity

数据库中唯一的行由order_number和sku_number的组合标识。id列是自动递增的。通常情况下,如果我有一个唯一的列作为标识符,我可以像下面的例子那样做。因此,在下面的示例中,假设id列是唯一标识符,我将使用id列作为冲突目标。

order = Order.create(order_number: '1', sku_number: '1', quantity: 100)
order.quantity = 200
Order.import [order], on_duplicate_key_update: {conflict_target: [:id], columns: [:quantity]}

它会更新数量,因为订单已经存在。

但我需要的是类似于

Order.import [order], on_duplicate_key_update: {conflict_target: [:order_number, :sku_number], columns: [:quantity]}

订单号和sku编号将唯一标识冲突行。

但是这会失败,因为Postgres期望有一个唯一的列作为冲突目标。

是否有办法使用非唯一列(例如订单号和sku编号)调用on_duplicate_key_update?

非常感谢任何帮助。

2个回答

6

我已经理解了。如果其他人遇到相同的问题,我会提供解决方案。

最终,我在Order上创建了一个唯一索引。

class AddUniqueKeyConstraintToOrders < ActiveRecord::Migration
  def change
    add_index :orders, [:order_number, :sku_number], unique: true
  end
end

activerecord-import支持使用索引作为约束条件。所以我最终做了类似以下的操作:

order = Order.last
order.quantity = 200
Order.import [order], on_duplicate_key_update: {conflict_target: [:order_number, :sku_number], index_name: :index_orders_on_order_number_and_sku_number, columns: [:quantity]}

其中index_orders_on_order_number_and_sku_number是迁移创建的索引名称。该索引将数量从之前的值更新为200,而不会创建其他记录。


0
另一种实现相同效果的方法是创建一个约束作为多列的唯一组合。在迁移文件中,在 create_table 之后可以这样做:
create_table :board_statistics do |t|
    t.string :hostname, null: false
    t.string :slotend

创建唯一索引

add_index :board_statistics, [:hostname, :slot, :serial_number], unique: true

或者创建约束

execute <<-SQL                                                                                                        
       ALTER TABLE board_statistics  
        ADD CONSTRAINT one_card_xan_slot UNIQUE (hostname, slot, serial_number);
 SQL

在 Activerecord-import gem 中可以使用 Constraint,例如:

BoardStatistic.import columns, on_duplicate_key_ignore: {constraint_name: :one_card_xan_slot}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接