Migrasi untuk menambahkan batasan unik ke kombinasi kolom

140

Yang saya butuhkan adalah migrasi untuk menerapkan batasan unik ke kombinasi kolom. yaitu untuk peopletabel, kombinasi first_name, last_Namedan Dobharus unik.

rangalo
sumber

Jawaban:

242

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

Robert Speicher
sumber
12
Saya pikir itu menambahkan indeks unik, bukan kendala. Atau apakah indeks juga menambah kendala?
Paul Cantrell
16
Tidak, semua baik-baik saja. Salahku! Batasan unik hadir dengan indeks unik.
Paul Cantrell
7
Saya setuju dengan @ paul-cantrell: tidak ada cara untuk hanya menambahkan kendala, bukan indeks (yang memiliki pengaruh penyimpanan db)
Augustin Riedinger
17
Masalah dengan validasi tingkat model adalah tidak skala. Dua server dapat menjalankan data yang sama pada saat yang sama (seperti ketuk dua kali pada aplikasi api berat) Saya memiliki dua catatan identik di DB saya sekarang dan model memiliki validasi ..
baash05
6
Saya ingin memiliki keduanya .. Hanya untuk memastikan
baash05
25

Menurut howmanyofme.com, "Ada 46.427 orang bernama John Smith" di Amerika Serikat saja. Itu sekitar 127 tahun. Karena ini jauh melebihi usia rata-rata manusia, ini berarti bahwa bentrokan DOB secara matematis pasti.

Semua yang saya katakan adalah bahwa kombinasi bidang unik tertentu dapat menyebabkan frustrasi pengguna / pelanggan yang ekstrem di masa depan.

Pertimbangkan sesuatu yang benar-benar unik, seperti nomor identifikasi nasional, jika sesuai.

(Saya sadar bahwa saya sangat terlambat ke pesta dengan pesta ini, tetapi ini bisa membantu pembaca di masa depan.)

A Fader Darkly
sumber
3
hrm ... Anda tentu benar. tapi mungkin itu hanya contoh dari apa yang ingin dilakukan Ian hanya untuk memperjelas pertanyaannya.
eritiro
1
Mungkin. Namun, jawabannya tidak ditujukan untuk Ian. Atau memang Rangalo.
A Fader Darkly
Itu dimaksudkan untuk semua foo-s, bukan hanya Ian atau rangalo.
BAHTERA
20

Anda mungkin ingin menambahkan batasan tanpa indeks. Ini akan tergantung pada database apa yang Anda gunakan. Di bawah ini adalah contoh kode migrasi untuk Postgres. (tracking_number, carrier)adalah daftar kolom yang ingin Anda gunakan untuk kendala.

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

Ada beberapa kendala yang dapat Anda tambahkan. Baca dokumen

Josh
sumber
12
Documents untuk PostgreSQL 9.4 mengatakan: Menambahkan batasan unik akan secara otomatis membuat indeks btree unik pada kolom atau grup kolom yang digunakan dalam kendala. Batasan keunikan hanya pada beberapa baris dapat ditegakkan dengan membuat indeks parsial. Jadi IMHO tidak perlu lagi ke SQL mentah ketika hasilnya pada dasarnya sama dengan menggunakan add_indexmetode. ;)
Rafał Cieślak
8
Sebenarnya ada satu alasan: Ini adalah detail implementasi dan tidak disarankan oleh dokumen . Perhatikan juga bahwa Anda tidak bisa merujuk ke kendala dengan nama, karena itu tidak ditambahkan ke pg_constrainttabel.
kaikuchn
8

Hai Anda dapat menambahkan indeks unik dalam migrasi Anda ke kolom misalnya

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

atau pisahkan indeks unik untuk setiap kolom

Bohdan
sumber
Maaf, berhasil, pertama saya mencoba dengan mengedit dan migrasi yang sudah ada yang tidak berhasil, kemudian menambahkan yang baru dan berhasil, terima kasih.
rangalo
4

Dalam contoh khas tabel gabungan antara pengguna dan pos:

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

Mencoba membuat dua catatan serupa akan membuat kesalahan basis data (Postgres dalam kasus saya):

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"

misalnya melakukan itu:

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

Contoh sepenuhnya dapat dijalankan: https://gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

db/schema.rbdihasilkan: https://gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a

Dorian
sumber
4

Demi kelengkapan, dan untuk menghindari kebingungan di sini adalah 3 cara melakukan hal yang sama:
Menambahkan kendala unik bernama ke kombinasi kolom di Rails 5.2+

Katakanlah kita memiliki tabel Lokasi yang dimiliki pengiklan dan memiliki kode referensi_kolom dan Anda hanya ingin 1 kode referensi per pengiklan. jadi Anda ingin menambahkan batasan unik ke kombinasi kolom dan beri nama.

Melakukan:

rails g migration AddUniquenessConstraintToLocations

Dan buat migrasi Anda terlihat seperti ini:

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

ATAU versi blok ini.

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

ATAU versi SQL mentah ini

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

Semua ini akan memiliki hasil yang sama, periksa schema.rb

Khalil Gharbaoui
sumber