Di chuyển để thêm ràng buộc duy nhất vào tổ hợp các cột


140

Những gì tôi cần là một di chuyển để áp dụng ràng buộc duy nhất cho sự kết hợp của các cột. ví dụ đối với peoplebảng, một sự kết hợp của first_name, last_NameDobphải là duy nhất.

Câu trả lời:


242

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


12
Tôi nghĩ rằng đó là thêm một chỉ mục duy nhất, không phải là một ràng buộc. Hoặc chỉ số thêm các ràng buộc là tốt?
Paul Cantrell

16
Không, tất cả đều tốt. Lỗi của tôi! Các ràng buộc duy nhất đi kèm với chỉ số duy nhất.
Paul Cantrell

7
Tôi đồng ý với @ paul-cantrell: không có cách nào để chỉ thêm một ràng buộc, không phải là một chỉ mục (có ảnh hưởng lưu trữ db)
Augustin Riedinger

17
Vấn đề với xác nhận mức mô hình là nó không có tỷ lệ. Hai máy chủ có thể chạy cùng một dữ liệu cùng một lúc (như chạm hai lần vào ứng dụng nặng api) Tôi có hai bản ghi giống hệt nhau trong DB của mình ngay bây giờ và mô hình có xác thực ..
baash05 17/03/2015

6
Tôi muốn có cả hai .. Chỉ để đảm bảo
baash05 17/03/2015

25

Theo howmanyofme.com, "Có 46.427 người tên John Smith" chỉ riêng ở Hoa Kỳ. Đó là khoảng 127 năm. Vì điều này vượt quá tuổi thọ trung bình của một con người, điều này có nghĩa là một cuộc đụng độ DOB là chắc chắn về mặt toán học.

Tất cả những gì tôi nói là sự kết hợp đặc biệt của các lĩnh vực duy nhất có thể dẫn đến sự thất vọng của người dùng / khách hàng trong tương lai.

Hãy xem xét một cái gì đó thực sự độc đáo, như số nhận dạng quốc gia, nếu phù hợp.

(Tôi nhận ra rằng tôi đến bữa tiệc rất muộn với điều này, nhưng nó có thể giúp những độc giả tương lai.)


3
hrm ... bạn chắc chắn đúng nhưng có lẽ đó chỉ là một ví dụ về những gì Ian muốn làm chỉ để làm cho câu hỏi rõ ràng.
eritiro

1
Có lẽ. Câu trả lời không dành cho Ian. Hoặc thực sự là Rangalo.
Một Fader tối

Nó được dành cho tất cả các foo-s, không chỉ Ian hay rangalo.
ARK

20

Bạn có thể muốn thêm một ràng buộc mà không có chỉ mục. Điều này sẽ phụ thuộc vào cơ sở dữ liệu bạn đang sử dụng. Dưới đây là mã di chuyển mẫu cho Postgres. (tracking_number, carrier)là danh sách các cột bạn muốn sử dụng cho ràng buộc.

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

Có những ràng buộc khác nhau mà bạn có thể thêm. Đọc tài liệu


12
Tài liệu cho PostgreQuery 9.4 nói: Thêm một ràng buộc duy nhất sẽ tự động tạo một chỉ mục btree duy nhất trên cột hoặc nhóm cột được sử dụng trong ràng buộc. Một ràng buộc duy nhất trên chỉ một số hàng có thể được thi hành bằng cách tạo một chỉ mục một phần. Vì vậy, IMHO không cần phải chuyển sang SQL thô khi kết quả về cơ bản sẽ giống như sử dụng add_indexphương thức. ;)
Rafał Cieślak

8
Trên thực tế có một lý do: Đó là một chi tiết thực hiện và không được khuyến khích bởi các tài liệu . Cũng lưu ý rằng bạn không thể tham khảo các ràng buộc theo tên, vì nó không được thêm vào pg_constraintbảng.
kaikuchn

8

Xin chào Bạn có thể thêm chỉ mục duy nhất trong di chuyển của bạn vào các cột chẳng hạn

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

hoặc tách các chỉ mục duy nhất cho mỗi cột


Xin lỗi, nó đã hoạt động, đầu tiên tôi đã thử bằng cách chỉnh sửa và di chuyển hiện tại không hoạt động, sau đó thêm một cái mới và nó hoạt động, cảm ơn.
rangalo

4

Trong ví dụ điển hình về bảng tham gia giữa người dùng và bài đăng:

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

Cố gắng tạo hai bản ghi tương tự sẽ gây ra lỗi cơ sở dữ liệu (Postgres trong trường hợp của tôi):

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"

ví dụ: làm điều đó:

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

Ví dụ đầy đủ có thể chạy: https://gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced

db/schema.rbđã tạo: https://gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a


4

Để hoàn thiện hơn và để tránh nhầm lẫn, đây là 3 cách thực hiện tương tự:
Thêm một ràng buộc duy nhất có tên vào tổ hợp các cột trong Rails 5.2+

Giả sử chúng ta có bảng Vị trí thuộc về một nhà quảng cáo và có cột tham chiếu_code và bạn chỉ muốn 1 mã tham chiếu cho mỗi nhà quảng cáo. vì vậy bạn muốn thêm một ràng buộc duy nhất cho sự kết hợp của các cột và đặt tên cho nó.

Làm:

rails g migration AddUniquenessConstraintToLocations

Và làm cho di chuyển của bạn trông giống như một lớp lót này:

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

HOẶC phiên bản khối này.

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

HOẶC phiên bản SQL thô này

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

Bất kỳ trong số này sẽ có kết quả tương tự, kiểm tra của bạn schema.rb

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.