“İki tablo uzakta” ​​kısıtlamalarını uygulama


10

SQL'de bir elektrik şemasını modellemekte bir sorunla karşılaştım. Yakalamak istediğim yapı

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

burada "inst", "örnek" in kısaltmasıdır.

Örneğin, 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT ve V CC'ye sahip partbir LM358 op-amp olarak sahip olabilirim . Daha sonra bu parçayı şemaya yerleştirerek a ve 8 s oluşturabilirim .pinpart_instpin_inst

Veri alanlarını yok sayarak, bir şemadaki ilk denemem şuydu:

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

Bu şema ana sorunu bir olmasıdır pin_instbir bağlı olabilir part_instile part_id=1ancak onun pinsahiptir part_id=2.

Bu sorunu uygulama düzeyi yerine veritabanı düzeyinde önlemek istiyorum. Yani, birincil anahtarlarımı bunu zorlayacak şekilde değiştirdim. Değişen çizgileri ile işaretledim --.

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

Bu yöntemle benim tutkum, birincil anahtarları kirletmesidir: atıfta bulunduğum her yerde part_inst, hem part_inst_idve hem de izlemem gerekiyor part_id. pin_inst.part_inst.part_id = pin_inst.pin.part_idAşırı ayrıntılı olmadan kısıtlamayı uygulamaya koymanın başka bir yolu var mı ?


pin_inst_idArtıklık olanı da kaldırabilirsiniz . (part_inst_id, part_id, pin_id)Birincil anahtarı olarak kullanabilirsiniz .
ypercubeᵀᴹ

İki şey: (a) 1OUT, 1IN-, 1IN +, GND, 2IN +, 2IN-, 2OUT ve VCC 11 pin örneği vermez mi? (b) İlk şemanızı alamıyorum. Bir iğne birden fazla bölümde kullanılamaz mı? 1-N değil pin ve parça arasında bir NN ilişkisine ihtiyacınız vardır.
Marcus Junius Brutus

@ user34332: (a) Sayılar adların bir parçasıdır. Örneğin, "2OUT" tek bir iğnedir. İşte bu şematik çizimi ait çip Bahse konu bahsediyorum. (b) Kabul etmiyorum. Kesinlikle iki parça bir VCC (pozitif besleme voltajı, "ortak toplayıcıda voltaj" ortak toplayıcı ") pimine sahip olabilir, ancak bunlar mantıksal olarak farklı pimlerdir. Örneğin, bir VCC pimi tipik olarak 500 uA ve farklı bir 250 uA çekebilir.
Kartopu

@Snowball Örnek verilerle bir SQL-Fiddle eklediyseniz başkalarının şemanızı anlamasına yardımcı olur .
ypercubeᵀᴹ

Yanıtlar:


13

Minimum çözüm

Bir radikal çözüm pin_insttamamen ortadan kaldırmak olabilir :

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

Sorunuzda gereksiz tabloya gerçekten ihtiyacınız olduğunu gösteren hiçbir şey yok. İçin pinbir ilişkili s part_instat, bakmak pinilişkili ait s part.

Bu, kodu basitleştirecektir:

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

Ama yorumunuz bundan kaçamayacağımızı açıkça belirtti ...

pin_instGerekirse alternatif

Dahil part_idsenin gibi yabancı anahtar kısıtlamaları ile en basit çözümdür. Yabancı anahtar kısıtlamaları olan “iki tablo ötede” bir tabloya başvuramazsınız .

Ama en azından birincil anahtarları "kirletmeden" bunu yapabilirsiniz. UNIQUEKısıtlamalar ekleyin .

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İlk önce benzersiz kısıtlamalara koydum . Bu, referans bütünlüğü için önemsizdir, ancak performans için önemlidir. Birincil anahtarlar zaten pk sütunları için dizinler uygular. Eşsiz kısıtlamaları uygulayan çok sütunlu dizinlerde ilk önce diğer sütunu kullanmak daha iyidir . Bu ilgili sorular altındaki ayrıntılar:

SO ile ilgili sorular:

Tetikleyicilere alternatif

Daha esnek, ancak biraz daha karmaşık ve hata eğilimli ve biraz daha az sıkı olan işlevleri tetikleyebilirsiniz. Yararı: olmadan yapabilirsin part_inst.part_idve pin.part_id...


Bazı ek sütunlar var pin_insts, ancak okunabilirlik ("Veri alanlarını yoksaymak, [...]") için onları atladım. Örneğin a pin_inst, bir girdi veya çıktı olarak işaretlenebilir.
Kartopu

@Karbol: Gerçek olması kolay olurdu. Çözümünüzü biraz genişlettim.
Erwin Brandstetter

2
İkinci öneriniz benim durumum için iyi çalışıyor. Yabancı bir anahtarın birincil anahtardan başka bir şeye başvurabileceğinin farkında değildim.
Kartopu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.