powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Таблицы категорий (category tables)
22 сообщений из 22, страница 1 из 1
Таблицы категорий (category tables)
    #32175174
Было бы интересно узнать, кто сталкивался с задачей "наследования" таблиц, а также различными методами ее решения. Задача уже понятна, я думаю: есть набор полей, который надо раскидать по таблицам таким образом, чтобы некий базовый набор располагался в одной таблице, а "расширяющие" его поля в других таблицах. Простое связывание 1:М не является допустимым по двум причинам:
1. На самом деле это ведь отношение 1:1, что в РБД не приветствуется.
2. Такая схема не исключает принадлежность одного и того же расширяющего набора полей разным объектам.

До сих пор не приходилось сталкиваться с MS SQL Server, обходился PostgreSQL, где этой проблемы не существует, поскольку наследование таблиц поддерживается самим сервером (native).

При разработке схемы данных в Visio 2002 также использовал объект "Category" с соответствующими коннекторами "Parent to category" и "Category to child". Но как-то не задумывался, каким образом это реализуется в РБД. В результате нахожусь если не в тупике, то в замешательстве. Собственные идеи проблему не решают, а поиск пока не увенчался успехом.

Буду рад дельным советам и идеям.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32175595
Фотография wara
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alisher H. Abdurahmanov,
Не могли бы Вы привести пример того, как используется это "наследование таблиц". Некоторые (я в том числе) даже не слышали про такое.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32175782
Если надо хранить данные о незначительно разных (в смысле наборов полей) классах объектов, то можно пойти одним из двух "лобовых" путей:
1. Организовать таблицу с набором атрибутов, который является объединением множества полей всех классов.
2. Организовать в каждой таблице полные наборы полей для каждого класса (тогда некоторый базовый набор будет дублироваться в каждой такой таблице).
Но было бы удобнее иметь базовый набор в одной таблице, а расширяющие его наборы для каждого дочернего класса в других таблицах. По крайней мере, это представляется более логичным решением.

Например, представим, что в больнице надо организовать хранение данных о пациентах и результатах некоторых анализов. Представим также, что наборы анализов для мужчин и женщин разные (ведь это легко представить). Имеем три сущности: пациент, пациент-мужчина, пациент-женщина. В родительской таблице я хочу хранить ID, пол, полное имя, возраст etc. В дочерних - специфичные для каждого пола данные. В PostgreSQL я бы реализовал это примерно следующим образом.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
CREATE TABLE Patients (
  PatID int PRIMARY KEY,
  Sex char( 1 ),
  Name varchar( 64 ),
  . . .
);

CREATE TABLE MalePatients (
  ProstateStatus varchar( 32 ),
  . . .
) INHERITS Patients;

CREATE TABLE FemalePatients (
  PregnancyCount int,
  PapSmear boolean,
  . . .
) INHERITS Patients;


После чего смог бы обращаться как ко всем пациентам через родительскую таблицу, так и к пациентам отдельного пола через дочерние таблицы. Причем за "кухней" следит сам PostgreSQL, то есть мне не надо волноваться, например, о том, что я могу завести одного пациента как мужчину и женщину одновременно.

Могу описать и концептуальную модель, как я ее обычно рисую в Visio, но и так уже большое сообщение получилось, поэтому лучше почитать прямо в Microsoft в MSDN Library: "Visio-Based Database Modeling in Visual Studio .NET Enterprise Architect (Part 5)". Все понятно с концепцией, но вот с реализацией толком не разобрался. Вопрос о согласованности данных так и остался открытым. Каким образом поле-дискриминатор (в нашем примере это поле Sex) может гарантировать эту согласованность...

P.S. Чувствую, что где-то что-то у меня в голове зациклилось, вот и не получается увидеть очевидное.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32175873
Rudyshin Sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
мне не надо волноваться, например, о том, что я могу завести одного пациента как мужчину и женщину одновременно.

Я не специалист в PostgreSQL, но каким образом Вы не сможете этого сделать?

Я так понимаю, что БД не разрешит сделать следующее:

Код: plaintext
1.
2.
3.
INSERT INTO Patients (PatID, Sex, Name )
    VALUES ( 1 , 'M', 'Alisher');
INSERT INTO Patients (PatID, Sex, Name )
    VALUES ( 2 , 'M', 'Alisher');


Но разрешит:

Код: plaintext
1.
2.
3.
INSERT INTO Patients (PatID, Sex, Name )
    VALUES ( 1 , 'M', 'Alisher');
INSERT INTO Patients (PatID, Sex, Name )
    VALUES ( 2 , 'F', 'Alisher');


?
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176033
x
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
x
Гость
По отображению объектов на реляционную базу данных много различных статей. Например: www.agiledata.org : The Fundamentals of Mapping Objects to Relational Databases. by Scott W.Ambler
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176087
Нет, имелась ввиду другая ситуация. Если я в PostgreSQL вставляю запись в дочернюю таблицу, то запись уже будет иметь PatID и поля как родительской, так и дочерней таблицы:
Код: plaintext
1.
INSERT INTO MalePatients (PatID, Sex, Name, ProstateStatus)
VALUES ( 1 , 'M', 'John', 'fine');

После этого я не смогу вставить запись в таблицу FemalePatient с таким же PatID. То есть PostgreSQL поддерживает "настоящее" наследование. Например, все следующие запросы верны:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
 -- select all patients
 
SELECT PatID, Name FROM Patients;

 -- select males only
 
SELECT PatID, Name, ProstateStatus FROM MalePatients;

 -- select females only
 
SELECT PatID, Name, PapSmear FROM FemalePatients;

Если же говорить о модели, предлагаемой в статье Microsoft (см. мое предыдущее сообщение), то я не совсем понимаю, каким образом можно запретить делать следующее:
Код: plaintext
1.
INSERT INTO MalePatients (PatID, ProstateStatus) VALUES ( 1 , 'fine');
INSERT INTO FemalePatients (PatID, PapSmear) VALUES ( 1 , TRUE);

Да, PatID присутствует во всех трех таблицах. Да, PatID является первичным ключом в каждой из таблиц. Получается, что выбирая пациентов, я всегда должен помнить, с какой из дочерних таблиц надо выполнять JOIN, в зависимости от того, информация о пациентах какого пола мне нужна:
Код: plaintext
1.
2.
SELECT P.PatID, P.Name, C.ProstateStatus
FROM Patients P, MalePatients C
WHERE P.PatID = C.PatID AND P.Sex = 'M';

Это ли удобно?
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176116
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это ли удобно?

А может поговорим, удобно ли это:
INSERT INTO MalePatients (PatID, ProstateStatus) VALUES (1, 'fine');
INSERT INTO FemalePatients (PatID, PapSmear) VALUES (1, TRUE);


С какой силы перепоя нужно быть, чтобы завести две разных таблицы для разных полов?

И что-то я сомневаюсь, что просто так, сама Postgre, не разрешит внести по записи в этой ситуации:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
CREATE TABLE MalePatients (
  ProstateStatus varchar( 32 ),
  . . .
) INHERITS Patients;

CREATE TABLE FemalePatients (
  PregnancyCount int,
  PapSmear boolean,
  . . .
) INHERITS Patients;


Явно ты опустил определение того, что запись может быть только в одной из этих таблиц. Потому что другого логического объяснения нет - от одно й таблицы можно отнаследовать хоть 10 таблиц, и никто не ставит условий, что в них должна быть однотипная информация.
А если будет еще таблица:
Код: plaintext
1.
2.
3.
4.
CREATE TABLE CrazyPatients (
  CrazyStatus varchar( 32 ),
  . . .
) INHERITS Patients;

То по твоему утверждению и сюда БД не даст вставить строку.

Ну? Где промах у тебя, мож расскажешь?
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176153
Хорошо, давай обсудим и это. =8-)

Разные таблицы заведены не собственно для пациентов, а для хранения информации о их состоянии и анализах. В самом деле, мало ли сколько всего может быть у женщин и мужчин разного в этом плане, верно? Таблица Patients хранит информацию о пациентах, вне зависимости от их пола (имя, возраст etc), а две дочерние - те самые данные о состоянии их органов и результатах анализов (сколько раз еще повториться придется). Можно хранить все эти поля и в одной таблице, но тогда заполнение записей будет "разреженным": для мужчин будут всегда пустыми "женские поля" и наоборот. Хорошо, давайте просто назовем дочерние таблицы иначе.

Далее. Промаха нет. PostgreSQL действительно следит за наследованными таблицами. Можно даже думать, что на самом деле работаешь с одной таблицей, но в зависимости от того, по какому имени к ней обращаешься, имеешь разные наборы полей. В том примере, который Вы привели, не удастся вставить запись в таблицу CrazyPatioents с уже существующим PatID в таблице Patients. В этой таблице на самом деле есть и поля таблицы Patients, поскольку она от нее наследована, так что ограничение PRIMARY KEY не даст совершить такую операцию.

Эх-х-х... но я-то хотел получить ответы на свои вопросы, а не объяснять, как я бы я решил эту задачу раньше. Сейчас мне надо решать ее на Microsoft SQL Server 2000.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176154
Спасибо за статью "The Fundamentals of Mapping Objects to Relational Databases"! Очень интересно было почитать, но там ровно то, о чем я уже говорил и к чему уже пришел. Видимо, придется оставлять решение таким и надеяться, что когда-нибудь потом мне посчастливится придумать или найти то самое, о котором мечтаю.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176271
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Alisher H. Abdurahmanov
Вы можете реализовать требуемую функциональность в реляционной БД следующим образом:
[src]
CREATE TABLE Patients (
PatID int PRIMARY KEY,
Sex char(1),
Name varchar(64)
)

CREATE TABLE MalePatients (
PatID int PRIMARY KEY REFERENCES Patients,
ProstateStatus varchar(32)
)

CREATE TABLE FemalePatients (
PatID int PRIMARY KEY REFERENCES Patients,
PregnancyCount int,
PapSmear bit
)
[src]

Здесь видно преимущество реляционной БД перед "постреляционной", т.е. реляционной с урезанной функциональностью, БД PostgreSQL - мы можем учесть ситуацию, когда пациент имеет и те, и другие первичные ПП, а так-же когда пациент имел сначала ж. ППП, а потом стал иметь м. ППП, или, к примеру, вообще не иметь таковых изначально.

Конечно, поле Sex в Patients не имеет смысла, и Sex должен определятся по наличию записей в MalePatients и FemalePatients как одно из четырёх значений:
М
Ж
МЖ
n/a
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176278
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Далее. Промаха нет. PostgreSQL действительно следит за наследованными таблицами. Можно даже думать, что на самом деле работаешь с одной таблицей, но в зависимости от того, по какому имени к ней обращаешься, имеешь разные наборы полей. В том примере, который Вы привели, не удастся вставить запись в таблицу CrazyPatioents с уже существующим PatID в таблице Patients. В этой таблице на самом деле есть и поля таблицы Patients, поскольку она от нее наследована, так что ограничение PRIMARY KEY не даст совершить такую операцию.

Странно - и отчего же тогда наследовать CrazyPatients?
Странная логика у БД - хорошо, что не с ней работаю.

Разные таблицы заведены не собственно для пациентов, а для хранения информации о их состоянии и анализах. В самом деле, мало ли сколько всего может быть у женщин и мужчин разного в этом плане, верно? Таблица Patients хранит информацию о пациентах, вне зависимости от их пола (имя, возраст etc), а две дочерние - те самые данные о состоянии их органов и результатах анализов (сколько раз еще повториться придется). Можно хранить все эти поля и в одной таблице, но тогда заполнение записей будет "разреженным": для мужчин будут всегда пустыми "женские поля" и наоборот. Хорошо, давайте просто назовем дочерние таблицы иначе.

Это все понятно. Уже :)

Эх-х-х... но я-то хотел получить ответы на свои вопросы, а не объяснять, как я бы я решил эту задачу раньше. Сейчас мне надо решать ее на Microsoft SQL Server 2000.

Ну и на SQL сервере можно решить.
Такие же таблицы:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
CREATE TABLE Patients (
  PatID int identity( 1 , 1 ) PRIMARY KEY,
  Sex char( 1 ),
  Name varchar( 64 ),
  . . .
)

CREATE TABLE MalePatients (
  PatID int PRIMARY KEY,
  ProstateStatus varchar( 32 ),
  . . .
)

CREATE TABLE FemalePatients (
  PatID int PRIMARY KEY,
  PregnancyCount int,
  PapSmear boolean,
  . . .
)

Дочерние таблицы вяжем через foreign на Родительскую по PatID
В триггере каждой дочерней таблицы делаем проверку - для MalePatients если пол М, то можно вставить, если Ж, то нельзя. Так же и для FemalePatients .

Выборки придется самому писать - join на родительскую таблицу.

Все.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176296
Фотография tygra
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
:))
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176301
Алексей, именно к этому решению я и пришел уже во второй попытке. Значит, моя голова все еще на месте, чему несказанно рад. Сначала возникло подозрение именно на потерю крыши. =8-)

Моя же проблема как раз заключается в том, чтобы запретить пациенту быть "двуполым" или "никем".
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176320
Оппаньки, Тигра уже помог и с этой проблемой справиться. Триггеры... мое слабое место. Но все равно справлюсь, несомненно. Большущее спасибище, Тигра!
Что ж, а выборки организуем в представления, так что ничего особо страшного не предвидится. Задача решена полностью. Это очень хорошо.

P.S. На experts-exchange для Тигры не пожалел бы баллов за ответы. =8-)
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176351
Фотография akuz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я бы на вашем месте не был бы столь оптимистичным.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE Patients (
  PatID int identity( 1 , 1 ) PRIMARY KEY,
  Sex char( 1 ),
  Name varchar( 64 ),
  ProstateStatus varchar( 32 ) null,  -- только для М
 
  PregnancyCount int null,  -- только для Ж
 
  PapSmear boolean null,  -- только для Ж
 
  . . .
)

Логика логикой, а хранение данных - другой вопрос.
И никаких джойнов и триггеров.
Для верности можно констрейнты навернуть.

Код: plaintext
1.
2.
3.
4.
ALTER TABLE Patients ADD 
	CONSTRAINT [CK_Patients_Sex] CHECK ([Sex] = 'Ж' or [Sex] = 'М'),
	CONSTRAINT [CK_Patients_ProstateStatus] CHECK (([Sex] = 'Ж' and [ProstateStatus] is null) or [Sex] = 'М'),
	CONSTRAINT [CK_Patients_PregnancyCount] CHECK (([Sex] = 'М' and [PregnancyCount] is null) or ([Sex] = 'Ж' and [PregnancyCount] is not null)),
	CONSTRAINT [CK_Patients_PapSmear] CHECK (([Sex] = 'М' and [PregnancyCount] is null) or ([Sex] = 'Ж' and [PregnancyCount] is not null))
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176384
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ладно-уж, подскажу решение без триггеров для противников пола "МЖ" и "n/a" :-)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
 
CREATE TABLE Patients ( 
  PatID int PRIMARY KEY, 
  Sex char( 1 ), 
  Name varchar( 64 ),
  UNIQUE(PatID, Sex)
) 
CREATE TABLE MalePatients ( 
  PatID int PRIMARY KEY,
  Sex char( 1 ) CHECK([Sex] = 'М'), 
  ProstateStatus varchar( 32 ),
  FOREIGN KEY (PatID, Sex) REFERENCES Patients(PatID, Sex)
) 
CREATE TABLE FemalePatients ( 
  PatID int PRIMARY KEY,
  Sex char( 1 ) CHECK([Sex] = 'Ж'), 
  PregnancyCount int, 
  PapSmear bit,
  FOREIGN KEY (PatID, Sex) REFERENCES Patients(PatID, Sex)
)
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176388
Фотография Циничный Кот
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Но было бы удобнее иметь базовый набор в одной таблице, а расширяющие его наборы для каждого дочернего класса в других таблицах. По крайней мере, это представляется более логичным решением.

Что мешает для одной таблицы пользоваться View??? Имхо, они именно для этого и предназначены. А дублировать одинаковую информацию в разных таблицах - не есть хорошо, накладные затраты на поддержание целостности могут быть немаленькими.

Я бы вашу задачу решал так - таблица, содержащая общие данные, плюс две таблицы по внешнему ключу ссылающиеся на первую. Впрочем, об этом alexeyvg уже написал, не буду повторяться.


Кстати. Я незнаком с реализацией механизма наследования в PostgreSQL, но, имхо, из общих сооображений рискну предположить что join в каком-то виде все равно используется - информацию-то откуда-то надо получать. Другой вопрос, что это может быть скрыто от програмиста. Если неправ - поправьте.


Что касается триггеров - я бы их не стали использовать там, где без них вполне можно обойтись. akuz тоже еуже рассказал, как.




2 akuz

Все это конечно будет работать, но только как вот быть с нормализацией-то???....
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176389
Akuz, в "The Fundamentals of Mapping Objects to Relational Databases" и "Visio-Based Database Modeling in Visual Studio .NET Enterprise Architect (Part 5)" этот подход тоже описывается, равно как и три других. Он меня не устраивает. Предлагаете использовать ту же "разреженную" структуру, о которой уже говорили выше.

P.S. Не устраивает потому, что на самом деле модель с пациентами выбрал показательно. В моей базе и типов, и полей как в родительской, так и в дочерних таблицах, гораздо больше.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176405
Кот, не могу сообразить, где Вы углядели дублирование данных в разных таблицах (кстати, и этот подход тоже описан в "Mapping..."). Предложенный Вами подход к решению - как раз тот, к которому пришли уже в самом начале обсуждения. =8-)

Подход от Алексея к решению проблемы жесткой типизации объектов очень даже ничего смотрится. Надо будет и его попробовать, и триггеры.

P.S. Приятно, что разработчики бывают такими отзывчивыми. Я-то думал, что дня два-три придется ждать ответов.
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176428
Jinn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Alisher H. Abdurahmanov
Эх-х-х... но я-то хотел получить ответы на свои вопросы, а не объяснять, как я бы я решил эту задачу раньше. Сейчас мне надо решать ее на Microsoft SQL Server 2000

Тебя просто попросили конкретизировать задачу. Сама задача несложная, и решить ее можно в четыре таблицы, но что ты дальше будешь делать с таким знанием РСУБД? Лучше почитай книжки, начиная с "ликбезовских". А решение ниже.

Patients (Table)
Pat_ID integer (PK)
Pat_Name varchar
Sex integer

Analise_Type (Table)
Type_ID integer (PK)
An_Name varchar

Analise (Table)
An_ID integer (PK)
Type_ID integer (FK)
An_Name varchar

Analise_Detail (Table)
Pat_ID integer (FK)
An_ID integer (FK)
An_Date date
An_Value varchar

Примерно так. Можно (и нужно!) все это дело расширить и дополнить для полной картины (анамнеза), но это уже твоя забота :-)
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176533
Фотография Циничный Кот
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 A.H.A.

Где я его углядел???.... Имхо, это не я, а вы его углядели:

Организовать в каждой таблице полные наборы полей для каждого класса (тогда некоторый базовый набор будет дублироваться в каждой такой таблице).

сегодня, 07:00


Не так ли???...


ЗЫ. А вообще интересно, как будет выглядеть решение на ANSI SQL-92 ??? :o)
...
Рейтинг: 0 / 0
Таблицы категорий (category tables)
    #32176908
Rudyshin Sergey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
to Alisher H. Abdurahmanov
Нет, имелась ввиду другая ситуация. Если я в PostgreSQL вставляю запись в дочернюю таблицу, то запись уже будет иметь PatID и поля как родительской, так и дочерней таблицы:
INSERT INTO MalePatients (PatID, Sex, Name, ProstateStatus)
VALUES (1, 'M', 'John', 'fine');


Но PostgreSQL не помешает сделать так:

INSERT INTO MalePatients (PatID, Sex, Name, ProstateStatus)
VALUES (1, 'F', 'John', 'fine');

Если БД не помешает это сделать, то помоему мы все же немного по разному понимаем условие задачи.
...
Рейтинг: 0 / 0
22 сообщений из 22, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Таблицы категорий (category tables)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]