列の組み合わせに一意の制約を追加する移行


140

列の組み合わせに一意の制約を適用するための移行が必要です。以下のためのすなわちpeopleテーブルの組み合わせfirst_namelast_NameおよびDob一意である必要があります。

回答:


242

add_index :people, [:firstname, :lastname, :dob], :unique => true


12
それは制約ではなく、一意のインデックスを追加していると思います。または、インデックスによって制約も追加されますか?
ポールカントレル2011

16
いいえ、それはすべて良好です。悪い!一意性制約には一意性インデックスが付属しています。
ポールカントレル

7
@ paul-cantrellに同意します。インデックスではなく、制約のみを追加する方法はありません(dbストレージに影響を与えます)
Augustin Riedinger

17
モデルレベルの検証の問題は、スケーリングされないことです。私は今、私のDBに2つの同一のレコードを持っているし、モデルが検証を持っている(APIの重いアプリをダブルタップなど)を同時に介して2台のサーバーが..同じデータを実行することができます
baash05

6
私は両方を持っているのが好きです。念のため
baash05

25

howmanyofme.comによると、米国だけで「John Smithという名前の人は46,427人います」。それは約127年の日数です。これは人間の平均寿命を十分に超えているため、DOBの衝突が数学的に確実であることを意味します。

私が言っていることは、ユニークなフィールドの特定の組み合わせは、将来、ユーザー/顧客の極端なフラストレーションにつながる可能性があるということです。

必要に応じて、国民識別番号のように、実際にユニークなものを検討してください。

(私はこれでパーティーに非常に遅れていると思いますが、それは将来の読者の役に立つかもしれません。)


3
うーん...あなたは確かに正しいです。しかし、おそらくそれは、イアンが質問を明確にするためにしたいことのほんの一例にすぎません。
エリティロ2016年

1
多分。答えはイアンのためのものではありませんでした。または、確かにランガロ。
フェーダーDarkly

Ianやランガロだけでなく、すべてのfoo-sを対象としています。
ARK

20

インデックスなしで制約を追加したい場合があります。これは、使用しているデータベースによって異なります。以下は、Postgresのサンプル移行コードです。 (tracking_number, carrier)制約に使用する列のリストです。

class AddUniqeConstraintToShipments < ActiveRecord::Migration
  def up
    execute <<-SQL
      alter table shipments
        add constraint shipment_tracking_number unique (tracking_number, carrier);
    SQL
  end

  def down
    execute <<-SQL
      alter table shipments
        drop constraint if exists shipment_tracking_number;
    SQL
  end
end

追加できる制約はいくつかあります。 ドキュメントを読む


12
Docs for PostgreSQL 9.4によると:一意の制約を追加すると、制約で使用される列または列のグループに一意のbtreeインデックスが自動的に作成されます。一部の行にのみ一意性制約を適用するには、部分インデックスを作成します。 したがって、結果が基本的にadd_indexメソッドを使用する場合と同じになるとき、私見は生のSQLにドロップする必要はありません。;)
RafałCieślak2015年

8
実際には1つの理由があります。これは実装の詳細であり、ドキュメントでは推奨されていません。また、制約はpg_constraintテーブルに追加されていないため、名前で参照できないことに注意してください。
kaikuchn

8

こんにちは、たとえば、移行の一意のインデックスを列に追加できます

add_index(:accounts, [:branch_id, :party_id], :unique => true)

または列ごとに個別のインデックス


申し訳ありませんが、うまくいきました。まず、編集して既存のマイグレーションを試しましたが、うまくいきませんでした。次に、新しいマイグレーションを追加して、うまくいきました。
ランガロ2010

4

ユーザーと投稿の間の結合テーブルの典型的な例では:

create_table :users
create_table :posts

create_table :ownerships do |t|
  t.belongs_to :user, foreign_key: true, null: false
  t.belongs_to :post, foreign_key: true, null: false
end

add_index :ownerships, [:user_id, :post_id], unique: true

2つの類似したレコードを作成しようとすると、データベースエラーがスローされます(私の場合はPostgres)。

ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_ownerships_on_user_id_and_post_id"
DETAIL:  Key (user_id, post_id)=(1, 1) already exists.
: INSERT INTO "ownerships" ("user_id", "post_id") VALUES ($1, $2) RETURNING "id"

例:

Ownership.create!(user_id: user_id, post_id: post_id)
Ownership.create!(user_id: user_id, post_id: post_id)

完全に実行可能な例:https : //gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

db/schema.rb生成:https : //gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a


4

完全を期すため、および混乱を避けるために、同じことを行う3つの方法を
次に示します。Rails 5.2以降の列の組み合わせに名前付き一意制約を追加する

広告主に属し、列reference_codeがあり、広告主ごとに1つの参照コードのみが必要なLocationsテーブルがあるとします。したがって、列の組み合わせに一意の制約を追加して名前を付けます。

行う:

rails g migration AddUniquenessConstraintToLocations

そして、移行を次のいずれかのように見せます。

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    add_index :locations, [:reference_code, :advertiser_id], unique: true, name: 'uniq_reference_code_per_advertiser'
  end
end

または、このブロックバージョン。

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    change_table :locations do |t|
     t.index ['reference_code', 'advertiser_id'], name: 'uniq_reference_code_per_advertiser', unique: true
    end
  end
end

または、この生のSQLバージョン

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
      execute <<-SQL
          ALTER TABLE locations
            ADD CONSTRAINT uniq_reference_code_per_advertiser UNIQUE (reference_code, advertiser_id);
        SQL
  end
end

これらのどれでも同じ結果になります。 schema.rb

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.