Postgresql: ข้อ จำกัด ที่ไม่ซ้ำกันตามเงื่อนไข


117

ฉันต้องการเพิ่มข้อ จำกัด ที่บังคับใช้ความเป็นเอกลักษณ์ในคอลัมน์ในส่วนหนึ่งของตารางเท่านั้น

ALTER TABLE stop ADD CONSTRAINT myc UNIQUE (col_a) WHERE (col_b is null);

WHEREส่วนข้างต้นเป็นคิดนึก

วิธีใดในการทำเช่นนี้ หรือฉันควรกลับไปที่กระดานวาดภาพเชิงสัมพันธ์?


2
ทำกันทั่วไป. ดู "ดัชนีเฉพาะบางส่วน"
Craig Ringer

11
@yvesonline ไม่นั่นเป็นข้อ จำกัด เฉพาะปกติ ผู้โพสต์ต้องการข้อ จำกัด เฉพาะบางส่วน
Craig Ringer

คำตอบ:


188

PostgreSQL ไม่ได้กำหนดUNIQUEข้อ จำกัดบางส่วน (เช่นเงื่อนไข) - อย่างไรก็ตามคุณสามารถสร้างดัชนีเฉพาะบางส่วนได้ PostgreSQL ใช้ดัชนีที่ไม่ซ้ำกันเพื่อใช้ข้อ จำกัด ที่ไม่ซ้ำกันดังนั้นเอฟเฟกต์จึงเหมือนกันคุณจะไม่เห็นข้อ จำกัด ในรายการinformation_schema.

CREATE UNIQUE INDEX stop_myc ON stop (col_a) WHERE (col_b is NOT null);

ดูดัชนีบางส่วน


24
สุดยอด! โดยไม่รู้ตัวว่า "ข้อ จำกัด " ไม่ได้แสดงเป็นข้อ จำกัด แต่กระนั้นก็ให้ข้อผิดพลาดที่ต้องการERROR: duplicate key value violates unique constraint "stop_myc"
EoghanM

8
เป็นที่น่าสังเกตว่าสิ่งนี้ไม่อนุญาตให้สร้างการอ้างอิง FKs ที่ฟิลด์ที่ไม่ซ้ำกันบางส่วน
ffflabs

12
นอกจากนี้ยังเป็นที่น่าสังเกตว่าเอฟเฟกต์ดัชนีนี้ไม่สามารถเลื่อนออกไปได้ หากคุณจำเป็นต้องดำเนินการอัปเดตจำนวนมากสิ่งนี้อาจทำให้เกิดปัญหาได้เนื่องจากมีการตรวจสอบความไม่ซ้ำกันหลังจากทุกแถวไม่ใช่หลังจากคำสั่งเหมือนกับว่าจะเป็นข้อ จำกัด หรือหลังจากการทำธุรกรรมเช่นเดียวกับข้อ จำกัด ที่สามารถเลื่อนได้
sage88

38

ได้กล่าวไปแล้วว่า PG ไม่ได้กำหนดข้อ จำกัด UNIQUE บางส่วน (เช่นเงื่อนไข) นอกจากนี้เอกสารประกอบยังบอกด้วยว่าวิธีที่ต้องการเพิ่มข้อ จำกัด เฉพาะในตารางคือADD CONSTRAINT ดัชนีที่ไม่ซ้ำกัน

วิธีที่แนะนำในการเพิ่มข้อ จำกัด เฉพาะให้กับตารางคือแก้ไขตาราง ... เพิ่มข้อ จำกัด การใช้ดัชนีเพื่อบังคับใช้ข้อ จำกัด เฉพาะอาจถือเป็นรายละเอียดการนำไปใช้งานที่ไม่ควรเข้าถึงโดยตรง อย่างไรก็ตามคุณควรทราบว่าไม่จำเป็นต้องสร้างดัชนีด้วยตนเองในคอลัมน์ที่ไม่ซ้ำกัน การทำเช่นนั้นจะทำซ้ำดัชนีที่สร้างขึ้นโดยอัตโนมัติ

มีวิธีการนำไปใช้โดยใช้ข้อ จำกัด การยกเว้น (ขอบคุณ @dukelion สำหรับวิธีแก้ปัญหานี้)

ในกรณีของคุณจะมีลักษณะดังนี้

ALTER TABLE stop ADD CONSTRAINT myc EXCLUDE (col_a WITH =) WHERE (col_b IS null);

ในแนวทางนั้นคุณไม่ได้ใช้ "ใช้" ในการกำหนดวิธีการทำดัชนีดังนั้นจึงอาจช้ามากหรือ postgres สร้างดัชนีเริ่มต้นในสิ่งนั้น? วิธีนั้นเป็นทางเลือกที่ยอมรับได้ แต่ไม่ใช่ทางเลือกที่ดีกว่า! ฉันคิดว่าคุณต้องมีอนุประโยค "ใช้" กับดัชนีเพื่อให้ตัวเลือกนั้นดีกว่า
Natan Medeiros

10
ในขณะที่ช้าลงข้อดีของโซลูชันที่แยกออกมาคือสามารถเลื่อนเวลาได้ (และโดยค่าเริ่มต้นจะเลื่อนไปจนกว่าจะสิ้นสุดคำสั่ง) ในทางตรงกันข้ามโซลูชันดัชนีเฉพาะที่ได้รับการยอมรับจะไม่สามารถเลื่อนออกไปได้ (และจะถูกตรวจสอบหลังจากเปลี่ยนแถวทุกครั้ง) ดังนั้นการอัปเดตจำนวนมากมักไม่สามารถทำได้เนื่องจากขั้นตอนในระหว่างการอัปเดตจะละเมิดข้อ จำกัด เฉพาะแม้ว่าจะไม่มีการละเมิดในตอนท้ายของคำสั่งการอัปเดตอะตอมก็ตาม
sage88

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