Una migrazione per aggiungere un vincolo univoco a una combinazione di colonne


140

Ciò di cui ho bisogno è una migrazione per applicare un vincolo univoco a una combinazione di colonne. cioè per un peopletavolo, una combinazione di first_name, last_Namee Dobdovrebbe essere univoco.

Risposte:


244

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


12
Penso che l'aggiunta di un indice univoco, non un vincolo. Oppure l'indice aggiunge anche il vincolo?
Paul Cantrell,

17
No, va tutto bene. Colpa mia! Il vincolo univoco viene fornito con l'indice univoco.
Paul Cantrell,

7
Sono d'accordo con @ paul-cantrell: non esiste un modo per aggiungere solo un vincolo, non un indice (che ha influenze di archiviazione db)
Augustin Riedinger

17
Il problema con la convalida a livello di modello è che non viene ridimensionato. Due server possono eseguire gli stessi dati contemporaneamente (come un doppio tocco su un'app pesante api) Al momento ho due record identici nel mio DB e il modello ha la convalida ..
baash05

6
Mi piace avere entrambi ... Solo per essere sicuri
baash05

25

Secondo howmanyofme.com, "Ci sono 46.427 persone di nome John Smith" solo negli Stati Uniti. Sono circa 127 anni. Poiché questo è ben al di sopra della durata media della vita di un essere umano, ciò significa che uno scontro DOB ​​è matematicamente certo.

Tutto quello che sto dicendo è che quella particolare combinazione di campi unici potrebbe portare a estrema frustrazione utente / cliente in futuro.

Prendi in considerazione qualcosa che sia effettivamente unico, come un numero di identificazione nazionale, se appropriato.

(Mi rendo conto di essere in ritardo alla festa con questo, ma potrebbe aiutare i futuri lettori.)


3
hrm ... hai certamente ragione. ma probabilmente era solo un esempio di ciò che Ian voleva fare solo per chiarire la domanda.
eritiro,

1
Può essere. La risposta non era pensata per Ian però. O davvero Rangalo.
A Fader Darkly,

Era inteso per tutti i foo-s, non solo per Ian o rangalo.
ARK,

21

È possibile che si desideri aggiungere un vincolo senza un indice. Questo dipenderà dal database che stai utilizzando. Di seguito è riportato un codice di migrazione di esempio per Postgres. (tracking_number, carrier)è un elenco delle colonne che si desidera utilizzare per il vincolo.

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

Esistono diversi vincoli che è possibile aggiungere. Leggi i documenti


12
Documenti per PostgreSQL 9.4 dicono: L'aggiunta di un vincolo univoco creerà automaticamente un indice btree univoco sulla colonna o sul gruppo di colonne utilizzate nel vincolo. È possibile applicare un vincolo di unicità solo su alcune righe creando un indice parziale. Quindi IMHO non è necessario passare a SQL non elaborato quando il risultato sarà sostanzialmente lo stesso dell'utilizzo del add_indexmetodo. ;)
Rafał Cieślak,

8
In realtà c'è un motivo: è un dettaglio di implementazione e scoraggiato dai documenti . Si noti inoltre che non è possibile fare riferimento al vincolo per nome, poiché non viene aggiunto alla pg_constrainttabella.
kaikuchn,

8

Ciao Ad esempio puoi aggiungere un indice univoco nella tua migrazione alle colonne

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

o separare indici univoci per ogni colonna


Ci dispiace, ha funzionato, prima ho provato modificando e la migrazione esistente che non ha funzionato, poi ne ho aggiunto uno nuovo e ha funzionato, grazie.
rangalo,

4

Nell'esempio tipico di una tabella di join tra utenti e post:

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

Cercare di creare due record simili genererà un errore del database (Postgres nel mio caso):

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"

ad es. farlo:

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

Esempio eseguibile completamente: https://gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

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


4

Per completezza e per evitare confusione, ecco 3 modi per fare la stessa cosa:
aggiungere un vincolo univoco denominato a una combinazione di colonne in Rails 5.2+

Supponiamo di avere una tabella Locations appartenente a un inserzionista con colonna reference_code e desideri solo 1 codice di riferimento per inserzionista. quindi desideri aggiungere un vincolo univoco a una combinazione di colonne e denominarlo.

Fare:

rails g migration AddUniquenessConstraintToLocations

E fai sembrare la tua migrazione qualcosa del genere:

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

O questa versione a blocchi.

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

O questa versione SQL non elaborata

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

Ognuno di questi avrà lo stesso risultato, controlla il tuo schema.rb

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.