การบังคับใช้ข้อ จำกัด “ ออกไปสองตาราง”


10

ฉันพบปัญหาในการสร้างแบบจำลองวงจรไฟฟ้าใน SQL โครงสร้างที่ฉันต้องการจะจับคือ

  part ←────────── pin
                   
part_inst ←───── pin_inst

โดยที่ "inst" สั้นสำหรับ "อินสแตนซ์"

ยกตัวอย่างเช่นผมอาจจะมีเป็นpartLM358 op-amp กับpins 1OUT, 1IN-, 1in + GND, 2in + 2IN-, 2OUT และ V CC จากนั้นฉันอาจวางส่วนนี้ลงบนแผนผังสร้างpart_instและ 8 pin_instวินาที

ละเว้นเขตข้อมูลความพยายามครั้งแรกของฉันที่ schema คือ

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial primary key,
    part_id bigint not null references parts
);
create table part_insts (
    part_inst_id bigserial primary key,
    part_id bigint not null references parts
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null references part_insts,
    pin_id bigint not null references pins
);

ปัญหาหลักคีมานี้ก็คือว่าpin_instอาจจะมีการเชื่อมโยงกับpart_instที่มีpart_id=1แต่มีpinpart_id=2

ฉันต้องการหลีกเลี่ยงปัญหานี้ในระดับฐานข้อมูลมากกว่าระดับแอปพลิเคชัน ดังนั้นฉันจึงปรับเปลี่ยนคีย์หลักเพื่อบังคับใช้ --ฉันทำเครื่องหมายสายการเปลี่ยนแปลงกับ

create table parts (
    part_id bigserial primary key
);
create table pins (
    pin_id bigserial,                                          --
    part_id bigint not null references parts,
    primary key (pin_id, part_id)                              --
);
create table part_insts (
    part_inst_id bigserial,                                    --
    part_id bigint not null references parts,
    primary key (part_inst_id, part_id)                        --
);
create table pin_insts (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,                              --
    pin_id bigint not null,                                    --
    part_id bigint not null references parts,                  --
    foreign key (part_inst_id, part_id) references part_insts, --
    foreign key (pin_id, part_id) references pins              --
);

จับฉันด้วยวิธีนี้ก็คือว่ามันเป็นมลพิษคีย์หลัก: ทุกที่ฉันหมายถึงpart_instฉันต้องติดตามทั้งใน และpart_inst_id part_idมีวิธีอื่นอีกpin_inst.part_inst.part_id = pin_inst.pin.part_idไหมที่ฉันจะบังคับใช้ข้อ จำกัด โดยไม่ใช้คำพูดมากเกินไป?


คุณสามารถลบสิ่งpin_inst_idที่ซ้ำซ้อนได้เช่นกัน คุณสามารถใช้(part_inst_id, part_id, pin_id)เป็นคีย์หลัก
ypercubeᵀᴹ

สองสิ่ง: (a) ไม่ได้ 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT และ VCC ให้ผลตอบแทน 11 pin? (b) ฉันไม่ได้รับสคีมาเริ่มต้นของคุณ ไม่สามารถใช้พินได้มากกว่าหนึ่งส่วนใช่หรือไม่ คุณต้องมีความสัมพันธ์ NN ระหว่างพินและส่วนที่ไม่ใช่ 1-N
Marcus Junius Brutus

@ user34332: (a) ตัวเลขเป็นส่วนหนึ่งของชื่อ ตัวอย่างเช่น "2OUT" เป็นพินเดียว นี่คือภาพวาดแผนผังของชิปที่ฉันพูดถึงในคำถาม (b) ฉันไม่เห็นด้วย แน่นอนว่าสองส่วนอาจมีพิน VCC (แรงดันไฟฟ้าเป็นบวก, "แรงดันไฟฟ้า [ที่] ตัวสะสมทั่วไป") แต่พวกมันมีพินที่แตกต่างกันอย่างมีเหตุผล ตัวอย่างเช่นโดยปกติแล้ว VCC พินหนึ่งอาจจะดึง 500 µA และ 250 250 A
สโนว์บอล

@Snowball มันจะช่วยให้ผู้อื่นเข้าใจ schema ของคุณถ้าคุณเพิ่มซอ - SQLด้วยข้อมูลตัวอย่าง
ypercubeᵀᴹ

คำตอบ:


13

ทางออกที่น้อยที่สุด

ทางออกหนึ่งที่รุนแรงอาจเป็นการลบpin_instอย่างสมบูรณ์:

  part ←────────── pin
                   
part_inst ←───── pin_inst

ไม่มีคำถามใดที่จะแนะนำให้คุณต้องการตารางที่ซ้ำซ้อน สำหรับpins เชื่อมโยงกับpart_instรูปลักษณ์ที่ของที่เกี่ยวข้องpinpart

ที่จะลดความซับซ้อนของรหัสไปที่:

create table part (    -- using singular terms for table names
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part
);

แต่ความคิดเห็นของคุณชัดเจนว่าเราจะไม่ไปกับ ...

ทางเลือกถ้าpin_instจำเป็น

การรวมpart_idเช่นเดียวกับที่คุณทำคือโซลูชันที่ง่ายที่สุดพร้อมด้วยข้อ จำกัด ของคีย์ต่างประเทศ คุณไม่สามารถอ้างอิงตาราง“สองตารางห่าง” กับข้อ จำกัด ที่สำคัญต่างประเทศ

แต่อย่างน้อยคุณก็สามารถทำได้โดยไม่ต้อง "ทำให้เสีย" กุญแจหลัก เพิ่มข้อ จำกัดUNIQUE

create table part (
    part_id bigserial primary key
);
create table pin (
    pin_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, pin_id)         -- note sequence of columns
);
create table part_inst (
    part_inst_id bigserial primary key,
    part_id bigint not null references part,
    unique(part_id, part_inst_id)
);
create table pin_inst (
    pin_inst_id bigserial primary key,
    part_inst_id bigint not null,
    pin_id bigint not null,
    part_id bigint not,
    foreign key (part_id, pin_id) references pin,
    foreign key (part_id, part_inst_id) references part_inst
);

ฉันใส่part_idก่อนในข้อ จำกัด ที่ไม่ซ้ำกัน นั่นไม่เกี่ยวข้องกับ Referential Integrity แต่มันสำคัญสำหรับประสิทธิภาพ คีย์หลักใช้ดัชนีสำหรับคอลัมน์ pk อยู่แล้ว จะดีกว่าหากมีคอลัมน์อื่นก่อนในดัชนีหลายคอลัมน์ที่ใช้ข้อ จำกัด เฉพาะ รายละเอียดภายใต้คำถามที่เกี่ยวข้องเหล่านี้:

คำถามที่เกี่ยวข้องกับ SO:

ทางเลือกกับทริกเกอร์

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


มีคอลัมน์เพิ่มเติมบางส่วนอยู่pin_instsแต่ฉันไม่สนใจคอลัมน์เหล่านั้นเพื่อความสะดวกในการอ่าน ("ไม่สนใจช่องข้อมูล [... ]") ตัวอย่างเช่น a pin_instอาจถูกทำเครื่องหมายเป็นอินพุตหรือเอาต์พุต
สโนว์บอล

@Snowball: จะเป็นเรื่องง่ายที่จะเป็นจริง ฉันขยายโซลูชันของคุณเล็กน้อย
Erwin Brandstetter

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