Миграция для добавления уникального ограничения к комбинации столбцов


147

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

Ответы:


255

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


12
Я думаю, что это добавление уникального индекса, а не ограничения. Или индекс тоже добавляет ограничение?
— Пол Кантрелл

18
Нет, все хорошо. Виноват! Ограничение уникальности связано с уникальным индексом.
— Пол Кантрелл

7
Я согласен с @ paul-cantrell: нет никакого способа добавить только ограничение, а не индекс (который влияет на хранилище db)
— Августин Ридинджер

18
Проблема с проверкой на уровне модели в том, что она не масштабируется. Два сервера могут передавать одни и те же данные одновременно (например, двойное нажатие на приложение с тяжелым API-интерфейсом). У меня есть две идентичные записи в моей БД прямо сейчас, и модель имеет проверку ..
— baash05

6
Мне нравится иметь и то и другое .. Просто на всякий
— случай

25

Согласно сайту howmanyofme.com, «только в США 46 427 человек по имени Джон Смит». Это примерно 127 лет дней. Поскольку это намного превышает среднюю продолжительность жизни человека, это означает, что конфликт DOB математически определен.

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

Рассмотрите что-то действительно уникальное, например, национальный идентификационный номер, если это необходимо.

(Я понимаю, что очень опаздываю на вечеринку с этим, но это может помочь будущим читателям.)


3
хрм ... ты конечно прав. но, вероятно, это был просто пример того, что Ян хотел сделать, чтобы прояснить вопрос.
— eritiro

2
Может быть. Однако ответ не был предназначен для Яна. Или действительно Рангало.
— A Fader Darkly

Он был предназначен для всех, а не только для Иэна или рангало.
— ARK

22

Вы можете добавить ограничение без индекса. Это будет зависеть от того, какую базу данных вы используете. Ниже приведен пример кода миграции для 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метода. ;)
— Рафал Цеслак

8
На самом деле есть одна причина: Это детали реализации и обескуражены документы . Также обратите внимание, что вы не можете ссылаться на ограничение по имени, так как оно не добавляется в pg_constraintтаблицу.
— kaikuchn

8

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

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

или отдельные уникальные индексы для каждого столбца


Извините, это сработало, сначала я попытался отредактировать существующую миграцию, которая не сработала, затем добавил новую, и она сработала, спасибо.
— rangalo

6

Для полноты картины и во избежание путаницы вот 3 способа сделать то же самое:
Добавление именованного ограничения уникальности к комбинации столбцов в Rails 5.2+.

Допустим, у нас есть таблица Locations, которая принадлежит рекламодателю и имеет столбец reference_code, и вам нужен только 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


5

В типичном примере таблицы соединений между пользователями и сообщениями:

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.