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


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.