Як моделювати спадкування двох таблиць MySQL


15

У мене є кілька таблиць, де я зберігаю дані і залежно від типу людини (працівника, громадянина), яка зробила роботу, я хочу зберігати її в eventтаблиці, зараз ці хлопці рятують тварину (є animalтаблиця).

Нарешті, я хочу створити стіл для зберігання події, коли хлопець (працівник, цивільний) врятував тварину, але кланяюся, чи потрібно додати іноземний ключ або як дізнатися idцінність цивільного чи працівника, який зробив цю роботу?

Тепер у цій конструкції я не знаю, як співвідносити, яка людина зробила цю роботу, якщо я мав би лише таку людину (він же цивільний), я б зберігав civil_idвале в personстовпці в останній таблиці ... але як знаю, чи це був цивільний чи працівник, чи потрібні мені інші "проміжні" таблиці?

Як відобразити дизайн наступної діаграми в MySQL?

введіть тут опис зображення

Додаткові деталі

Я моделював це наступним чином:

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

Однак чи є спосіб позбутися нулів?

У мене запити:

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 ;

Ось оновлена sqlfiddle .


яка мета таблиці, TYPE_PERSONколи вона містить лише один стовпець?
JW 웃

1
Слідкуйте за цим: stackoverflow.com/questions/15128222/… ?

@cMinor - Ви запитуєте "як дізнатись ідентифікатор цивільного чи працівника, який зробив цю роботу?" Ви насправді знаєте, хто робив цю роботу в реальному житті (або уявному, якщо це домашнє завдання)? Чи є у вас достатньо вихідних даних?

Я звикаю до спадщини, тому я створив таблицю людини, яка б містила типи людей (робітника, громадянина), потім у таблиці подій, Як посилатися на людину залежно від того, як пройшла робота (цивільна чи працівник)?
cMinor

1
Я вірю, що ви отримаєте кращі поради в адміністраторах баз даних
Пітер Геркенс

Відповіді:


14

Оскільки я склав схему, я краще відповім;)

Поточні реляційні бази даних, на жаль, не підтримують спадщину безпосередньо, тому вам потрібно перетворити її на "прості" таблиці. Зазвичай існує 3 стратегії для цього:

  1. Усі класи 1 в одній таблиці з NULL-нестандартними полями.
  2. Конкретні класи 2 в окремих таблицях. Абстрактні класи не мають власних таблиць.
  3. Усі класи в окремих таблицях.

Докладніше про те, що це насправді означає, а також деякі плюси та мінуси, будь ласка, дивіться посилання, надані в моєму початковому дописі , але в двох словах, (3), мабуть, має бути вашим дефолтом, якщо у вас немає конкретної причини для двох інших. Ви можете представити (3) у базі даних просто так:

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

На жаль, ця структура дозволить вам мати personте, що не є ні civilнормою worker(тобто ви можете створити екземпляр абстрактного класу), а також дозволить створити personте, що є і те, civil і worker. Існують способи застосування першого на рівні бази даних, а в СУБД, яка підтримує відкладені обмеження 3, навіть остання може бути застосована в базі даних, але це один з небагатьох випадків, коли використання цілісності рівня додатків може бути фактично кращим. .


1 person , civilі workerв цьому випадку.

2 civil і workerв цьому випадку ( personє "абстрактним").

3 Що не в MySQL.


Як останні можуть бути застосовані в СУБД, які підтримують відкладені обмеження? (забороняє людині бути обома civilта worker)
Гіма

@Gima Перейдіть за посиланням, яке я надав у відповіді.
Бранко Димитрієвич

Ви стверджуєте, що поточні реляційні бази даних не підтримують успадкування. А що з postgresql? postgresql.org/docs/9.6/static/ddl-inherit.html
Climax

@Climax Я знаю про PostgreSQL, але його реалізація є лише частковою. З вашого посилання: "Інші типи обмежень (унікальні, первинні та обмеження зовнішнього ключа) не успадковуються."
Бранко Димитріевич

1
@naaz Зовнішні ключі існують і в, civilі в worker. Можливо, ви пропустили синтаксис короткої руки (просто REFERENCESбез FOREIGN KEY)?
Бранко Димитріевич

5

Не потрібно розрізняти Civil_ID та Worker_ID; просто продовжуйте використовувати Person-ідентифікатор як ключ для всіх трьох таблиць: Person, Civil та Worker. Додайте стовпець PersonType до Person з двома значеннями "Civil" та "Worker".

Тепер це представляє два підкласи CivilClass та WorkerClass абстрактного базового класу PersonClass як підрозділи Civil та Worker базової особи Person. Ви отримуєте гарну відповідність моделі даних у БД з об'єктною моделлю в додатку.


Я зробив sqlfiddle sqlfiddle.com/#!2/1f6a4/1, але я не знаю, як приєднатись до іншої таблиці, чи не могли б ви вказати свою відповідь тут у sqlfiddle?
cMinor

Немає «чітких» civil_idі worker_id- вони те саме, що person_id, тільки названі по-іншому, - подивіться на FK1(зовнішній ключ) маркер перед ними.
Бранко Димитріевич

4

Ваш випадок є екземпляром моделювання класу / підкласу. Або, як ви це схемували в ER, узагальнення / спеціалізація.

Є три методи, які допоможуть вам створити таблиці mysql для висвітлення цього випадку. Вони називаються Спадковістю однієї таблиці, Спадковим спадком таблиці та Спільним первинним ключем. Ви можете прочитати їх на вкладці інформації з відповідного тегу в розділі SO.

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

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

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

Успадкування однієї таблиці корисно для простих випадків, коли наявність NULL не викликає проблем. Успадкування таблиці класів краще для складніших випадків. Спільний первинний ключ - це хороший спосіб налагодити взаємні стосунки та прискорити приєднання.


1

Ви можете створити таблицю типів особи та додати поле до всіх таблиць, які потребують примусового виконання типу. Потім створіть сторонні ключі. Ось приклад, що походить від вашого ...

    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...
    );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.