Міграція для додавання унікального обмеження до комбінації стовпців


140

Мені потрібно міграція, щоб застосувати унікальне обмеження до комбінації стовпців. тобто для peopleтаблиці, комбінації first_name, last_Nameі Dobповинен бути унікальним.

Відповіді:


243

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


12
Я думаю, що це додає унікальний індекс, а не обмеження. Або індекс також додає обмеження?
Пол Кантрелл

16
Ні, все добре. Моє ліжко! Унікальне обмеження має унікальний індекс.
Пол Кантрелл

7
Я погоджуюся з @ paul-cantrell: чи не існує способу додавати лише обмеження, а не індекс (який має вплив на зберігання db)
Августин Рідінгер

17
Проблема валідації рівня моделі полягає в тому, що вона не масштабується. Два сервери можуть одночасно запускати одні й ті самі дані (як подвійний дотик до api heavy app). У мене в БД зараз два однакові записи, і модель має перевірку ..
baash05,

6
Мені подобається мати і те й інше. Просто для переконання
baash05

25

За даними howmanyofme.com, "лише в США 46 467 людей на ім'я Джон Сміт". Це приблизно 127 років. Оскільки це значно за середній термін життя людини, це означає, що зіткнення DOB є математично визначеним.

Все, що я говорю, полягає в тому, що саме ця комбінація унікальних полів може призвести до сильних розладів користувачів / клієнтів у майбутньому.

Розгляньте щось, що насправді є унікальним, як, наприклад, національний ідентифікаційний номер.

(Я усвідомлюю, що я дуже спізнюся на вечірку з цим, але це може допомогти майбутнім читачам.)


3
хрм ... ви, звичайно, праві. але, напевно, це був лише приклад того, що Іан хотів зробити, щоб зрозуміти питання.
eritiro

1
Може бути. Однак відповідь не призначалася Іану. Або справді Рангало.
Fader Darkly

Він призначався для всіх людей, а не тільки для Ян або Рангало.
АРК

21

Ви можете додати обмеження без індексу. Це залежатиме від того, яку базу даних ви використовуєте. Нижче наведено зразок коду міграції для 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
Документи для PostgreSQL 9.4 кажуть: Додавання унікального обмеження автоматично створить унікальний індекс btree для стовпчика або групи стовпців, що використовуються в обмеженні. Унікальне обмеження лише для деяких рядків можна забезпечити, створивши частковий індекс. Таким чином, IMHO не потрібно переходити на необроблений SQL, коли результат буде в основному таким же, як і використання add_indexметоду. ;)
Rafał Cieślak

8
Насправді є одна причина: це деталізація реалізації та відсторонена документами . Також зауважте, що ви не можете посилатися на обмеження по імені, оскільки воно не додано до pg_constraintтаблиці.
kaikuchn

8

Привіт Ви можете додавати унікальний індекс при міграції, наприклад, у стовпці

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

або окремі унікальні індекси для кожного стовпця


Вибачте, це спрацювало, спершу я спробував редагувати та існуючу міграцію, яка не працювала, потім додала нову, і вона спрацювала, дякую.
рангало

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

Спроба створити дві подібні записи призведе до помилки бази даних (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

Для повноти та щоб уникнути плутанини, ось три способи зробити те саме:
Додавання названого унікального обмеження до комбінації стовпців у Rails 5.2+

Скажімо, у нас є таблиця "Місцеположення", яка належить рекламодавцю і має код коду стовпця, і вам потрібно лише 1 довідковий код на одного рекламодавця. тому ви хочете додати унікальне обмеження до комбінації стовпців та назвати його.

Зробіть:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.