İki tablonun kalıtım modeli MySQL nasıl


16

Verileri depoladığım bazı tablolarım var ve bir eventtabloda saklamak istediğim bir işi yapan kişinin türüne (işçi, sivil) bağlı olarak , şimdi bu çocuklar bir hayvanı kurtarıyor (bir animaltablo var).

Son olarak, bir erkeğin (işçi, sivil) bir hayvanı kurtardığı olayı saklamak için bir masa istiyorum, ancak bir yabancı anahtar eklemeli miyim idya da işi yapan sivil ya da işçinin değerini nasıl bilebilirim ?

Şimdi, bu tasarımda, hangi kişinin işi yaptığını nasıl ilişkilendireceğimi bilmiyorum, eğer sadece bir çeşit kişi (aka sivil) olsaydı, civil_idvale'yi personbu son tabloda bir sütunda saklardım ... ama nasıl yapılır sivil ya da işçi olup olmadığını bilmek, başka bir "ara" tabloya ihtiyacım var mı?

Aşağıdaki diyagramın tasarımını MySQL'e nasıl yansıtabilirim?

resim açıklamasını buraya girin

Ek detaylar

Ben şu şekilde modellenmiştir:

DROP    TABLE IF EXISTS `tbl_animal`; 
CREATE TABLE `tbl_animal` (
    id_animal       INTEGER     NOT NULL PRIMARY KEY AUTO_INCREMENT,
    name            VARCHAR(25) NOT NULL DEFAULT "no name",
    specie          VARCHAR(10) NOT NULL DEFAULT "Other",
    sex             CHAR(1)     NOT NULL DEFAULT "M",
    size            VARCHAR(10) NOT NULL DEFAULT "Mini",
    edad            VARCHAR(10) NOT NULL DEFAULT "Lact",
    pelo            VARCHAR(5 ) NOT NULL DEFAULT "short",
    color           VARCHAR(25) NOT NULL DEFAULT "not defined",
    ra              VARCHAR(25) NOT NULL DEFAULT "not defined",
    CONSTRAINT `uc_Info_Animal` UNIQUE (`id_animal`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


INSERT INTO `tbl_animal` VALUES (1,'no name', 'dog', 'M','Mini','Lact','Long','black','Bobtail');
INSERT INTO `tbl_animal` VALUES (2,'peluchin', 'cat', 'M','Mini','Lact','Long','white','not defined');
INSERT INTO `tbl_animal` VALUES (3,'asechin', 'cat', 'M','Mini','Lact','Corto','orange','not defined');

DROP    TABLE IF EXISTS `tbl_person`;  
CREATE TABLE `tbl_person` (
    type_person  VARCHAR(50) NOT NULL primary key        
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
INSERT INTO `tbl_person` (type_person) VALUES ('Worker');
INSERT INTO `tbl_person` (type_person) VALUES ('Civil');



DROP    TABLE IF EXISTS `tbl_worker`;  
CREATE TABLE `tbl_worker`(
    id_worker           INTEGER  NOT NULL PRIMARY KEY,
    type_person         VARCHAR(50) NOT NULL , 
    name_worker         VARCHAR(50) NOT NULL ,    
    address_worker      VARCHAR(40) NOT NULL DEFAULT "not defined",     
    delegation          VARCHAR(40) NOT NULL DEFAULT "not defined",
    FOREIGN KEY (type_person)               REFERENCES `tbl_person` (type_person),
    CONSTRAINT `uc_Info_worker` UNIQUE (`id_worker`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

INSERT INTO `tbl_worker` VALUES (1,'Worker','N_CEDENTE1', 'DIR Worker 1', 'DEL');
INSERT INTO `tbl_worker` VALUES (2,'Worker','N_worker1', 'DIR Worker 2', 'DEL');
INSERT INTO `tbl_worker` VALUES (3,'Worker','N_worker2', 'address worker','delegation worker'); 


DROP    TABLE IF EXISTS `tbl_civil`; 
CREATE TABLE `tbl_civil`(
    id_civil                        INTEGER  NOT NULL PRIMARY KEY,
    type_person         VARCHAR(50) NOT NULL ,
    name_civil                      VARCHAR(50)  ,
    procedence_civil                VARCHAR(40)  NOT NULL DEFAULT "Socorrism",    
  FOREIGN KEY (type_person)             REFERENCES `tbl_person` (type_person),
    CONSTRAINT `uc_Info_civil` UNIQUE (`id_civil`)           
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;


INSERT INTO `tbl_civil`  VALUES (1,'Civil','N_civil1' , 'Socorrism');


CREATE TABLE `tbl_event` (
    id_event     INTEGER NOT NULL,
    id_animal    INTEGER NOT NULL,
    type_person  VARCHAR(50) NOT NULL , 
    date_reception DATE DEFAULT '2000-01-01 01:01:01',
    FOREIGN KEY (id_animal)   REFERENCES `tbl_animal`    (id_animal),
    FOREIGN KEY (type_person )  REFERENCES `tbl_person`   (type_person ),
    CONSTRAINT `uc_Info_ficha_primer_ingreso` UNIQUE (`id_animal`,`id_event`)     
)ENGINE=InnoDB  DEFAULT CHARSET=utf8;

INSERT INTO `tbl_event` VALUES (1,1, 'Worker','2013-01-01 01:01:01' );
INSERT INTO `tbl_event` VALUES (2,2, 'Civil','2013-01-01 01:01:01' );

Ancak, boş değerlerden kurtulmanın bir yolu var mı?

Sahip olduğum sorgular şunlardır:

SELECT  a.*,b.*,z.*
FROM    tbl_event a
        left JOIN tbl_worker b
            ON a.type_person = b.type_person
        left JOIN tbl_animal z
            ON   z.id_animal = a.id_animal ;

SELECT  a.*,b.*,z.*
FROM    tbl_event a
        left JOIN tbl_civil b
            ON a.type_person = b.type_person
        left JOIN tbl_animal z
            ON   z.id_animal = a.id_animal ;

İşte güncellenmiş bir sqlfiddle .


TYPE_PERSONyalnızca bir sütun içerdiğinde tablonun amacı nedir?
JW


@cMinor - "İşi yapan inşaat işçisinin veya işçinin kimliğini nasıl bilebilirsiniz?" Aslında bu işi gerçek hayatta kimin yaptığını biliyor musunuz (veya bu bir ödevse hayali)? Yeterli kaynak veriniz var mı?

Mirasa alışığım, bu yüzden insan türlerini (işçi, sivil) tutacak bir masa kişisi oluşturdum, o zaman olay tablosunda, işin (sivil veya işçi) nasıl yapıldığına bağlı olarak bir kişiye nasıl başvurulur?
cMinor

1
Veritabanı Yöneticilerinde daha iyi tavsiye alacağınıza inanıyorum
Pieter Geerkens 11.03.2013

Yanıtlar:


15

Diyagramı yaptığımdan beri daha iyi cevap veririm;)

Mevcut ilişkisel veritabanları maalesef doğrudan mirası desteklememektedir, bu nedenle onu "düz" tablolara dönüştürmeniz gerekir. Bunu yapmak için genellikle 3 strateji vardır:

  1. Tüm sınıflar 1 NULL mümkün olmayan ortak alanları olan tek bir tabloda.
  2. Ayrı tablolarda beton sınıfları 2 . Soyut sınıfların kendi tabloları yoktur.
  3. Tüm sınıflar ayrı tablolarda.

Bunun gerçekte ne anlama geldiği ve bazı artıları ve eksileri hakkında daha fazla bilgi için lütfen orijinal yazımda verilen bağlantılara bakın , ancak diğer ikisinden biri için belirli bir nedeniniz yoksa (3) muhtemelen varsayılanınız olmalıdır. Veritabanındaki (3) 'ü aşağıdaki gibi temsil edebilirsiniz:

CREATE TABLE person (
    person_id int PRIMARY KEY
    -- Other fields...
);

CREATE TABLE civil (
    civil_id int PRIMARY KEY REFERENCES person (person_id)
    -- Other fields...
);

CREATE TABLE worker (
    worker_id int PRIMARY KEY REFERENCES person (person_id)
    -- Other fields...
);

CREATE TABLE event (
    event_id int PRIMARY KEY,
    person_id int REFERENCES person (person_id)
    -- Other fields...
);

Ne yazık ki, bu yapı bir atalım olacak personne olduğunu civilne de worker(yani soyut sınıf örneğini) ve ayrıca bir oluşturmasına olanak tanıyacak personolduğunu hem civil ve worker. Birincisini veritabanı düzeyinde zorlamanın yolları vardır ve ertelenmiş kısıtlamaları 3 destekleyen bir DBMS'de , ikincisi bile veritabanında zorlanabilir, ancak bu, uygulama düzeyinde bütünlüğün kullanılmasının gerçekten tercih edilebildiği birkaç durumdan biridir. .


1 person , civilve workerbu durumda.

2 civil ve workerbu durumda ( person"soyut" dur).

3 Hangi MySQL desteklemez.


İkincisi, ertelenmiş kısıtlamaları destekleyen DBMS'de nasıl uygulanabilir? (bir insanı her ikisinden de civilworker
vazgeçirir

@Gima Lütfen cevapta verdiğim bağlantıyı takip edin.
Branko Dimitrijevic

Mevcut ilişkisel veritabanlarının mirası desteklemediğini iddia ediyorsunuz. Postgresql ne olacak? postgresql.org/docs/9.6/static/ddl-inherit.html
Doruk

@Climax PostgreSQL'in farkındayım, ancak uygulaması sadece kısmi. Bağlantınızdan: "Diğer kısıtlama türleri (benzersiz, birincil anahtar ve yabancı anahtar kısıtlamaları) miras alınmaz."
Branko Dimitrijevic

1
@ naaz Yabancı anahtarlar civilve worker. Belki de kısa süreli sözdizimini (sadece REFERENCESolmadan FOREIGN KEY) kaçırdınız mı?
Branko Dimitrijevic

5

Farklı Civil_ID ve Worker_ID öğelerine gerek yoktur; Kişi-Kimliği'ni her üç tablonun anahtarı olarak kullanmaya devam edin: Kişi, İnşaat ve İşçi. "İnşaat" ve "İşçi" iki değerine sahip Kişiye bir sütun PersonType ekleyin.

Bu şimdi, soyut temel sınıf PersonClass'ın CivilClass ve WorkerClass adlı iki alt sınıfı temsil etmektedir. DB veri modeli ile uygulamada nesne modeli arasında güzel bir yazışma olsun.


Bir sqlfiddle sqlfiddle.com/#!2/1f6a4/1 yaptım ama diğer masaya nasıl katılacağımı bilmiyorum, lütfen cevabınızı sqlfiddle'da gösterebilir misiniz?
cMinor

"Farklı" yoktur civil_idve worker_id- bunlar person_idsadece farklı isimlerle aynıdır FK1- önlerindeki (yabancı anahtar) işaretine bakın.
Branko Dimitrijevic

4

Durumunuz sınıf / alt sınıf modellemesinin bir örneğidir. Veya, ER'de çizdiğiniz gibi, genelleme / uzmanlaşma.

Bu durumu kapsayacak şekilde mysql tabloları tasarlamanıza yardımcı olacak üç teknik vardır. Bunlara Tek Tablo Devralma, Sınıf Tablosu Devralma ve Paylaşılan Birincil anahtar denir. Bunları bilgi sekmesinde SO'daki ilgili etiketten okuyabilirsiniz.

/programming//tags/single-table-inheritance/info

/programming//tags/class-table-inheritance/info

/programming//tags/shared-primary-key/info

Tek tablo devralma, NULL'ların varlığının sorun yaratmadığı basit durumlar için kullanışlıdır. Sınıf tablosu mirası daha karmaşık vakalar için daha iyidir. Paylaşılan birincil anahtar, bire bir ilişkileri zorlamanın ve birleştirmeleri hızlandırmanın iyi bir yoludur.


1

Kişi türü tablosu oluşturabilir ve tür zorlaması gerektiren tüm tablolara bir alan ekleyebilirsiniz. Ardından yabancı anahtarlar oluşturun. İşte sizinkinden türeyen bir örnek ...

    CREATE TABLE person_type (
        person_type_id int PRIMARY KEY
        -- data: 1=civil, 2=worker
        -- Other fields (such as a label)...
    );

    CREATE TABLE person (
        person_id int PRIMARY KEY
        person_type_id int FOREIGN KEY REFERENCES person_type (person_type_id)
        -- Other fields...
    );

    CREATE TABLE civil (
        civil_id int PRIMARY KEY REFERENCES person (person_id)
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );

    CREATE TABLE worker (
        worker_id int PRIMARY KEY REFERENCES person (person_id)
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );

    CREATE TABLE event (
        event_id int PRIMARY KEY,
        person_id int REFERENCES person (person_id)
        -- Type is optional here, but you could enforce event for a particular type
        person_type_id int FOREIGN KEY REFERENCES person (person_type_id)
        -- Other fields...
    );
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.