Menegakkan kendala "dua tabel jauhnya"

10

Saya mengalami beberapa masalah pemodelan skema listrik dalam SQL. Struktur yang ingin saya tangkap adalah

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

di mana "inst" adalah kependekan dari "instance".

Sebagai contoh, saya mungkin memiliki partop-amp LM358 dengan pins 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT, dan V CC . Saya kemudian dapat menempatkan bagian ini pada skema, membuat a part_instdan 8 pin_insts.

Mengabaikan bidang data, upaya awal saya pada suatu skema adalah

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
);

Masalah utama dengan skema ini adalah bahwa a pin_instmungkin terkait part_instdengan part_id=1tetapi pinmemiliki part_id=2.

Saya ingin menghindari masalah ini pada level database daripada level aplikasi. Jadi, saya memodifikasi kunci utama saya untuk menegakkan itu. Saya menandai baris yang diubah dengan --.

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              --
);

Keluhan saya dengan metode ini adalah bahwa itu mencemari kunci utama: Di mana pun saya merujuk pada part_inst, saya harus melacak baik itu part_inst_iddan part_id. Apakah ada cara lain yang bisa saya lakukan untuk menegakkan batasan pin_inst.part_inst.part_id = pin_inst.pin.part_idtanpa terlalu bertele-tele?

Semakin bertambah
sumber
Anda bisa menghapus pin_inst_idyang merupakan redundansi juga. Anda dapat menggunakan (part_inst_id, part_id, pin_id)kunci utama.
ypercubeᵀᴹ
Dua hal: (a) bukankah 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT, dan VCC menghasilkan instance 11 pin? (B) Saya tidak mendapatkan skema awal Anda. Tidak bisakah pin digunakan di lebih dari satu bagian? Anda memerlukan hubungan NN antara pin dan bagian bukan 1-N.
Marcus Junius Brutus
@ user34332: (a) Jumlahnya adalah bagian dari nama-nama. Misalnya, "2OUT" adalah satu pin. Berikut gambar skematik dari chip yang saya bicarakan dalam pertanyaan. (B) Saya tidak setuju. Tentu saja dua bagian mungkin memiliki pin VCC (tegangan suplai positif, "tegangan [pada] kolektor umum") pin, tetapi mereka pin yang berbeda secara logis. Sebagai contoh, satu pin VCC biasanya dapat menggambar 500 μA dan yang berbeda 250 μA.
Bola Salju
@Snowball Ini akan membantu orang lain memahami skema Anda jika Anda menambahkan SQL-Fiddle dengan data sampel.
ypercubeᵀᴹ
1
Pertanyaan yang terkait erat.
Erwin Brandstetter

Jawaban:

13

Solusi minimal

Salah satu solusi radikal mungkin dengan menghapus pin_instsepenuhnya:

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

Tidak ada dalam pertanyaan Anda untuk menyarankan Anda benar-benar membutuhkan tabel redundan. Untuk pins terkait dengan part_inst, lihat pins dari terkait part.

Itu akan menyederhanakan kode untuk:

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
);

Tetapi komentar Anda menjelaskan bahwa kami tidak akan lolos dari itu ...

Alternatif jika pin_instdiperlukan

Termasuk yang part_idAnda lakukan adalah solusi paling sederhana dengan batasan kunci asing. Anda tidak dapat merujuk tabel "dua tabel jauhnya" dengan batasan kunci asing .

Tapi setidaknya Anda bisa melakukannya tanpa "mencemari" kunci utama. Tambahkan UNIQUEkendala .

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
);

Saya mengutamakan part_idkendala unik. Itu tidak relevan untuk integritas referensial, tetapi itu penting untuk kinerja. Kunci utama sudah menerapkan indeks untuk kolom pk. Lebih baik memiliki kolom lain terlebih dahulu di indeks multicolumn yang menerapkan kendala unik. Detail di bawah pertanyaan terkait ini:

Pertanyaan terkait pada SO:

Alternatif dengan pemicu

Anda dapat menggunakan fungsi pemicu, yang lebih fleksibel, tetapi sedikit lebih rumit dan rawan kesalahan dan sedikit kurang ketat. Manfaatnya: Anda bisa melakukannya tanpa part_inst.part_iddan pin.part_id...

Erwin Brandstetter
sumber
Ada beberapa kolom tambahan di pin_instsdalamnya, tetapi saya menghapusnya untuk kepentingan keterbacaan ("Mengabaikan bidang data, [...]"). Misalnya, a pin_instdapat ditandai sebagai input atau output.
Bola Salju
@Snowball: Pasti mudah untuk menjadi kenyataan. Saya sedikit memperluas solusi Anda.
Erwin Brandstetter
2
Saran kedua Anda bekerja dengan baik untuk situasi saya. Saya tidak menyadari bahwa kunci asing dapat merujuk sesuatu selain kunci utama.
Bola Salju