Activerecord-import upsert with non unique columns into postgres

时间:2016-10-12 10:40:59

标签: ruby-on-rails postgresql activerecord-import

我正在尝试使用activerecord-import导入数据,但我遇到了一个问题。如果该行已存在,则需要更新其他需要创建的行。表中的唯一行由两列的组合定义,其中每个列值在表中可能不唯一。我将如何使用on_duplicate_key_update的conflict_target,因为列不是唯一列。

现在了解详情。我有一个名为Order的模型,下面是Order模型中列的简化版本。

id
order_number
sku_number
quantity

数据库中的唯一行由order_number和sku_number的组合标识。 id列自动递增。通常情况下,如果我有一个唯一的列作为标识符,我可以执行以下操作。因此,在下面的示例中,我将使用id列作为conflict_target,假设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]}

order_number和sku_number将唯一标识冲突行。

但由于Postgres期望为conflict_target提供一个独特的列,因此失败了。

有没有办法用非唯一列调用on_duplicate_key_update,即order_number和sku_number?

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

我明白了。我正在制定解决方案以防其他人遇到同样的问题。

我最终在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而不创建其他记录。

答案 1 :(得分:0)

另一种方法是将CONSTRAIANT创建为多列的唯一组合。在create_table之后的迁移文件中,我们可以:

create_table :board_statistics do |t|
    t.string :hostname, null: false
    t.string :slot
    …

end

只创建一个唯一索引

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

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

BoardStatistic.import columns, on_duplicate_key_ignore: {constraint_name: :one_card_xan_slot}
相关问题