การโอนย้ายเพื่อเพิ่มข้อ จำกัด เฉพาะให้กับการรวมกันของคอลัมน์


140

สิ่งที่ฉันต้องการคือการโยกย้ายเพื่อนำข้อ จำกัด ที่ไม่ซ้ำกันมาใช้กับการรวมกันของคอลัมน์ คือสำหรับpeopleตารางการรวมกันของfirst_name, last_NameและDobต้องไม่ซ้ำกัน

คำตอบ:


244

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


12
ฉันคิดว่านั่นเป็นการเพิ่มดัชนีเฉพาะไม่ใช่ข้อ จำกัด หรือดัชนีเพิ่มข้อ จำกัด เช่นกัน?
Paul Cantrell

17
ไม่มันดีทั้งหมด ความผิดฉันเอง! ข้อ จำกัด ที่ไม่ซ้ำกันมาพร้อมกับดัชนีที่ไม่ซ้ำกัน
Paul Cantrell

7
ฉันเห็นด้วยกับ @ paul-cantrell: ไม่มีวิธีใดที่จะเพิ่มข้อ จำกัด เท่านั้นไม่ใช่ดัชนี (ซึ่งมีผลต่อการจัดเก็บฐานข้อมูล db)
Augustin Riedinger

17
ปัญหาของการตรวจสอบความถูกต้องระดับโมเดลคือไม่ได้ปรับขนาด เซิร์ฟเวอร์สองเครื่องสามารถเรียกใช้ข้อมูลเดียวกันได้ในเวลาเดียวกัน (เช่นการแตะสองครั้งบนแอปหนา api) ฉันมีสองระเบียนที่เหมือนกันในฐานข้อมูลของฉันตอนนี้และรุ่นมีการตรวจสอบ ..
baash05

6
ฉันชอบที่จะมีทั้ง .. เพียงเพื่อให้แน่ใจว่า
baash05

25

อ้างอิงจาก howmanyofme.com "มีคน 46,427 คนชื่อจอห์นสมิ ธ " ในสหรัฐอเมริกาเพียงอย่างเดียว นั่นคือประมาณ 127 ปีของวัน เนื่องจากอายุการใช้งานเฉลี่ยของมนุษย์ดีกว่าซึ่งหมายความว่าการปะทะ DOB นั้นมีความแน่นอนทางคณิตศาสตร์

ทั้งหมดที่ฉันพูดคือการที่การรวมกันของเขตข้อมูลที่ไม่ซ้ำกันอาจนำไปสู่ความยุ่งยากของผู้ใช้ / ลูกค้าในอนาคต

ลองพิจารณาสิ่งที่ไม่เหมือนใครเช่นหมายเลขประจำตัวประชาชนถ้าเหมาะสม

(ฉันรู้ว่าฉันมางานปาร์ตี้สายเกินไป แต่มันจะช่วยผู้อ่านในอนาคตได้)


3
hrm ... คุณพูดถูก แต่อาจเป็นเพียงตัวอย่างของสิ่งที่ Ian ต้องการทำเพื่อทำให้คำถามชัดเจน
eritiro

1
อาจจะ. คำตอบนั้นไม่ได้มีไว้สำหรับเอียน หรือแน่นอน Rangalo
เฟดเดอร์อย่างมืดมน

มันมีไว้สำหรับ foo-s ทั้งหมดไม่ใช่แค่เอียนหรือ rangalo
ARK

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
Docs สำหรับ 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)

หรือแยกดัชนีเฉพาะสำหรับแต่ละคอลัมน์


ขออภัยใช้งานได้ก่อนอื่นฉันลองแก้ไขและย้ายข้อมูลที่มีอยู่แล้วซึ่งใช้งานไม่ได้จากนั้นเพิ่มรายการใหม่และใช้งานได้ขอบคุณ
rangalo

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

เพื่อความสมบูรณ์และเพื่อหลีกเลี่ยงความสับสนที่นี่มี 3 วิธีในการทำสิ่งเดียวกัน: การ
เพิ่มข้อ จำกัด ที่ไม่ซ้ำกันที่มีชื่อให้กับการรวมกันของคอลัมน์ใน Rails 5.2+

สมมติว่าเรามีตารางสถานที่ตั้งซึ่งเป็นของผู้โฆษณาและมีคอลัมน์ 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.