Sütun birleşimine benzersiz kısıtlama eklemek için taşıma


140

İhtiyacım olan sütun birleşimine benzersiz kısıtlama uygulamak için bir geçiş. Bir yani için peoplemasa, bir kombinasyonu first_name, last_Nameve Dobbenzersiz olmalıdır.

Yanıtlar:


244

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


12
Bence bu bir kısıtlama değil , benzersiz bir dizin ekliyor . Veya dizin de kısıtlama ekliyor mu?
Paul Cantrell

17
Hayır, her şey yolunda. Benim hatam! Benzersiz kısıtlama benzersiz dizinle birlikte gelir.
Paul Cantrell

7
@ Paul-cantrell ile hemfikirim: sadece bir kısıtlama eklemek için herhangi bir yol yok, bir indeks değil (db depolama etkileri vardır)
Augustin Riedinger

17
Model seviyesi doğrulamasındaki sorun ölçeklenmemesidir. İki sunucu aynı anda (api heavy app çift dokunma gibi) aynı verileri çalıştırabilir Şu anda benim DB iki özdeş kayıtları var ve model doğrulama vardır ..
baash05


25

Howmanyofme.com'a göre, sadece Amerika Birleşik Devletleri'nde "John Smith adında 46.427 kişi var". Bu yaklaşık 127 yıl sürüyor. Bu, bir insanın ortalama ömrünün çok üzerinde olduğundan, DOB çatışmasının matematiksel olarak kesin olduğu anlamına gelir.

Söylediğim tek şey, benzersiz alanların belirli bir kombinasyonunun gelecekte aşırı kullanıcı / müşteri hayal kırıklığına yol açabileceğidir.

Uygunsa, ulusal kimlik numarası gibi gerçekten benzersiz bir şey düşünün.

(Bu partiye çok geç kaldığımı fark ettim, ama gelecekteki okuyuculara yardımcı olabilir.)


3
hrm ... kesinlikle haklısın. ama muhtemelen Ian'ın sadece soruyu netleştirmek için ne yapmak istediğine bir örnekti.
eritiro

1
Olabilir. Cevap Ian için tasarlanmamıştı. Ya da gerçekten Rangalo.
Bir Fader Karanlıkta

Sadece Ian veya rangalo için değil, tüm foo-s'lar için tasarlanmıştır.
ARK

21

Dizin olmadan bir kısıtlama eklemek isteyebilirsiniz. Bu, hangi veritabanını kullandığınıza bağlı olacaktır. Postgres için örnek taşıma kodu aşağıdadır. (tracking_number, carrier)kısıtlama için kullanmak istediğiniz sütunların bir listesidir.

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

Ekleyebileceğiniz farklı kısıtlamalar vardır. Dokümanları okuyun


12
PostgreSQL 9.4 için dokümanlar şunları söylüyor: Benzersiz bir kısıtlama eklemek, kısıtlamada kullanılan sütun veya sütun grubunda otomatik olarak benzersiz bir btree dizini oluşturur. Kısmi bir dizin oluşturularak yalnızca bazı satırlarda benzersizlik kısıtlaması uygulanabilir. Dolayısıyla sonuç temelde add_indexyöntemi kullanmakla aynı olduğunda IMHO'nun ham SQL'e düşmesine gerek yoktur . ;)
Rafał Cieślak

8
Aslında bir sebep var: Bu bir uygulama detayıdır ve dokümanlar tarafından cesaretini kırmıştır . Ayrıca, pg_constrainttabloya eklenmediğinden, kısıtlamaya ada göre başvuramayacağınızı unutmayın .
kaikuchn

8

Merhaba Sütunlara geçişinizde benzersiz bir dizin ekleyebilirsiniz.

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

veya her sütun için benzersiz dizinler ayırın


Üzgünüm, işe yaradı, önce düzenleme ve çalışmayan mevcut göçü denedim, sonra yeni bir tane ekledim ve işe yaradı, teşekkürler.
rangalo

4

Kullanıcılar ve yayınlar arasındaki bir birleştirme tablosunun tipik örneğinde:

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

İki benzer kayıt oluşturmaya çalışmak bir veritabanı hatası (benim durumumda Postgres) atar:

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"

örneğin bunu yapmak:

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

Tamamen çalıştırılabilir örnek: https://gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

db/schema.rboluşturulan: https://gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a


4

Tamlık uğruna ve karışıklığı önlemek için burada aynı şeyi yapmanın 3 yolu vardır:
Rails 5.2+ içindeki sütun kombinasyonuna adlandırılmış benzersiz bir kısıtlama ekleme

Diyelim ki bir reklamverene ait olan ve reference_code sütununa sahip Konumlar tablosumuz var ve her reklamveren için yalnızca 1 referans kodu istiyorsunuz. böylece bir sütun kombinasyonuna benzersiz bir kısıtlama eklemek ve adlandırmak istersiniz.

Yapmak:

rails g migration AddUniquenessConstraintToLocations

Göçünüzü şu tek astar gibi görünmesini sağlayın:

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

VEYA bu blok sürümü.

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

VEYA bu ham SQL sürümü

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

Bunlardan herhangi biri aynı sonuca sahip olacak, schema.rb

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.