powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Связь один-к-одному
23 сообщений из 23, страница 1 из 1
Связь один-к-одному
    #32962075
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
Знаю, что эта тема уже поднималась, но хочется кое-что уточнить. Вот приблизительная постановка задачи, которая у меня возникла.

Пусть есть некий класс объектов A , и класс объектов B , являющихся "разновидностью" A , но имеющих большее количество атрибутов. Держать их в одной таблице не хочется, и вроде бы естественной является мысль организовать связь 1:1. Поскольку у них есть "подчиненные" объекты, то держать A и B в несвязных таблицах тоже нехорошо. Для юзера эти объекты совершенно разные, то есть просматривать и редактировать A (которые не являются B ) и B он должен отдельно.

Опишу для начала то, как я решаю это на данный момент (синтаксис IB'шный, но вроде без особой специфики):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
CREATE TABLE A (
   A_Id INTEGER NOT NULL PRIMARY KEY,
   A_Attrib_1 INTEGER,
   A_Attrib_2 VARCHAR(...),
   ...
);

CREATE TABLE B (
   B_Id INTEGER NOT NULL PRIMARY KEY REFERENCES A (A_Id),
   B_Attrib_1 INTEGER,
   B_Attrib_2 VARCHAR(...),
   ...
);

CREATE VIEW V_A (A_Id, A_Attrib_1, ...) AS
   SELECT A.A_Id, A.A_Attrib_1, ...
   FROM A
   WHERE NOT EXISTS (SELECT * FROM B WHERE B.B_Id=A.A_Id)
;

CREATE VIEW V_B (A_Id, A_Attrib_1, ..., B_Attrib_1, ...) AS
   SELECT A.A_Id, A.A_Attrib_1, ..., B.B_Attrib_1, ...
   FROM A
   INNER JOIN B ON (A.A_Id=B.B_Id)
;
Потом идут триггеры на вьюшках, делающие их редактируемыми. Пользователи не имеют никаких прав на таблицы, только на вьюшки.

Собственно, основная проблема, которую я здесь вижу - это anti-join в V_A , который, по-видимому, может очень сильно тормозить. Сначала я хотел даже сделать примерно так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE TABLE B (
   B_Id INTEGER NOT NULL PRIMARY KEY,
   ...
);

CREATE TABLE A (
   A_Id INTEGER NOT NULL PRIMARY KEY,
   B_Id INTEGER REFERENCES B (B_Id)
   ...
);
, но потом понял, что избавляясь от проблемы идентификации "тех A , которые не B ", я получаю кучу других проблем. Единственное, что сейчас приходит в голову - держать в A признак того, что объект является B , т.е., что у него в B есть подчиненная запись. Сделать это несложно, а невозможность артефактов обеспечат вьюшки со своими триггерами, но это нарушает нормализацию.

Какой, по вашему мнению, более правильный вариант? Или, возможно, более правильное решение задачи в целом?
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962194
olol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
автор
Не морочь себе голову... делай все в одной...
Поставь дополнительно признак-А и выбирай по нему или все...
А то завтра понадобится какой-нибудь признак перетаскивать из В->A или наоборот... :)
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962281
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
CREATE VIEW V_A (A_Id, A_Attrib_1, ...) AS
   SELECT A.A_Id, A.A_Attrib_1, ...
   FROM A LEFT OUTER JOIN B ON B.B_Id=A.A_Id
   WHERE B.B_id IS NULL;
??
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962334
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LVU
CREATE VIEW V_A (A_Id, A_Attrib_1, ...) AS
SELECT A.A_Id, A.A_Attrib_1, ...
FROM A
WHERE NOT EXISTS (SELECT * FROM B WHERE B.B_Id=A.A_Id)


Зачем NOT EXISTS ? Все B являются также и A. Поэтому во view, которое представляет A, нужно иметь также и экземпляры B.

LVU
Какой, по вашему мнению, более правильный вариант? Или, возможно, более правильное решение задачи в целом?


Если тебе нужно выделить чистые A, то лучше сделать еще одного наследника от A - скажем, C, который будет играть роль тех объектов, которые сейчас у тебя являются чистыми A. Тогда вместо A и B ты будеш использовать B и C, и обе view будут только с join-ами, без вычитания.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962360
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Павел Воронцов
Код: plaintext
1.
2.
3.
4.
CREATE VIEW V_A (A_Id, A_Attrib_1, ...) AS
   SELECT A.A_Id, A.A_Attrib_1, ...
   FROM A LEFT OUTER JOIN B ON B.B_Id=A.A_Id
   WHERE B.B_id IS NULL;
??

Ну и что ты советуешь ? Вычитание - оно все равно вычитание, как его не записывай, в виде NOT EXISTS или в виде LEFT OUTER JOIN. Один фиг долго.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962371
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
olol автор
Не морочь себе голову... делай все в одной...
Поставь дополнительно признак-А и выбирай по нему или все...
А то завтра понадобится какой-нибудь признак перетаскивать из В->A или наоборот... :)
Ну , скажем так - совет не продвинутый, туповатенький. Если надо иметь не два класса, а несколько , то тут уже такое все меньше и меньше будет подходить. Но все естественно от задачи зависит.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962390
Фотография Old Nick
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
При показе класса А в виде списка объекты класса В должны присутствовать, но не быть редактируемыми. Можно сделать форму для редактирования одной записи (одну для А, другую для В, причем форму В можно наследовать от А). В таблице А можно ввести тип, определяющий класс объектов. К тому же если тебе нужны будут только объекты типа А (без наследников), то можно будет список фильтровать по типу.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962633
olol
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivНу , скажем так - совет не продвинутый, туповатенький. Если надо иметь не два класса, а несколько , то тут уже такое все меньше и меньше будет подходить. Но все естественно от задачи зависит.
Ты наверное умник считаешь, что на каждый клас нужно делать:
CREATE TABLE В (...
CREATE TABLE С (...

В этом случае уж лучше признак-B,признак-C...

А если нужны разные фильтры для выборки, то и должны быть все признаки не в одной строке, а в виде таблицы перечня свойств... и для них таблица-фильтр...
Тогда можно будет спокойно добавлять и A_Attrib_3, A_Attrib_4...
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962711
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LVU

Для такой реализации наследования вам стоит почитать про descriminator'ы. А то какая-то частичная реализация получается - осюда и проблемы
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962909
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
MasterZivЗачем NOT EXISTS ? Все B являются также и A. Поэтому во view, которое представляет A, нужно иметь также и экземпляры B.
С точки зрения "реального мира" (и юзера) есть объекты B , и есть A , которые не B , поэтому не так.

Old NickПри показе класса А в виде списка объекты класса В должны присутствовать, но не быть редактируемыми.
См. выше.
Old NickВ таблице А можно ввести тип, определяющий класс объектов. К тому же если тебе нужны будут только объекты типа А (без наследников), то можно будет список фильтровать по типу.
Я в первом посте сказал, что это основной рассматриваемый вариант. Но все-таки денормализация...

MasterZivЕсли тебе нужно выделить чистые A, то лучше сделать еще одного наследника от A - скажем, C, который будет играть роль тех объектов, которые сейчас у тебя являются чистыми A.
Тогда, теоретически, могут появиться такие A , ктороые не являются ни B , ни C . Да и избыточность получается больше, чем если вводить в A признак.

MasterZiv Павел Воронцов
Код: plaintext
1.
2.
3.
4.
CREATE VIEW V_A (A_Id, A_Attrib_1, ...) AS
   SELECT A.A_Id, A.A_Attrib_1, ...
   FROM A LEFT OUTER JOIN B ON B.B_Id=A.A_Id
   WHERE B.B_id IS NULL;

Ну и что ты советуешь ? Вычитание - оно все равно вычитание, как его не записывай, в виде NOT EXISTS или в виде LEFT OUTER JOIN. Один фиг долго.

А действительно ли один фиг? По крайней мере, это выглядит изящнее, чем мой вариант. Я просто не уверен в том, насколько одинаково воспримет эти запросы FB'шный оптимизатор.

ololА если нужны разные фильтры для выборки, то и должны быть все признаки не в одной строке, а в виде таблицы перечня свойств... и для них таблица-фильтр...
Тогда можно будет спокойно добавлять и A_Attrib_3, A_Attrib_4...
Все-таки, заводить свои метаданные, и организовывать, по сути, собственную БД поверх существующей, не стоит, если нет реальной необходимости. Хотя в другом месте в этой задаче такая фигня у меня есть.

funikovyuriДля такой реализации наследования вам стоит почитать про descriminator'ы. А то какая-то частичная реализация получается - осюда и проблемы
А не подскажете, где о них почитать? Что-то я, видно, не смог правильный вопрос гуглю задать.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32962934
iLLer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На самом деле не все так просто.
Нужно анализировать предметную область, если присутствует вероятность изменения типов объектов, их связей или состава, то будет большая головная боль при переделке предложенной структуры. Поясню, если объект А - это объект "свтильник", а В - это объект "светильник настольный", то очевидны проблемы, если наш "завод" вдруг начнет выпускать "стол". А вот если объект А - это "описание товара", а В - "проверенное и дополненное описание товара", то тут возможно расширения не предвидится.
В общем случае структуру можно сделать такой:

Таблица Объекты
id int, идентификатор
class_id int, класс объекта

Таблица Свойства объектов
obj_id идентификатор объекта
prop_id идентификатор свойства
data varbinary значение свойства

Таблица Классификатор объектов
id идентификатор класса
parent_id идентификатор родительского класса
...

Таблица Классификатор свойств
id идентификатор свойства
type_id тип данных свойства
...

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

Вывод такой: анализируйте предметную область(или читайте ТЗ, здесь оно будет как нельзя кстати) и ищите золотую середину.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963022
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
LVU funikovyuriДля такой реализации наследования вам стоит почитать про descriminator'ы. А то какая-то частичная реализация получается - осюда и проблемы
А не подскажете, где о них почитать? Что-то я, видно, не смог правильный вопрос гуглю задать.
Вроде нашел, приблизительно: http://blog.hibernate.org/cgi-bin/blosxom.cgi/Gavin%20King/discrimination.html . Но в этой статье, ИМХО, как раз получается приблизительно то же, что у меня, с поправкой от Павла Воронцова, за исключением того, что я не ввозу дискриминатор явно, а использую его неявное значение во VIEW.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963062
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
iLLerПоясню, если объект А - это объект "свтильник", а В - это объект "светильник настольный", то очевидны проблемы, если наш "завод" вдруг начнет выпускать "стол". А вот если объект А - это "описание товара", а В - "проверенное и дополненное описание товара", то тут возможно расширения не предвидится.

Вот, очень близко ко второму варианту, на самом деле.

iLLerВ общем случае структуру можно сделать такой:
...


Подобную штуку предлагал olol (если я правильно его понял), и, как я ему уже сказал, она используется в этом проекте, но в другом месте. Здесь, я уверен, она совершенно не нужна.

iLLerВывод такой: анализируйте предметную область(или читайте ТЗ, здесь оно будет как нельзя кстати) и ищите золотую середину.
Насчет ТЗ я согласен, но его нет :( Сами ставим, сами пишем... А насчет предметной области - стараемся. Как я уже сказал, расширение номенклатуры объектов здесь невозможно, просто "по построению".
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963412
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Рискну предложить ещё один вариант.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
CREATE TABLE B (B_ID NUMBER NOT NULL
  ,TYPE CHAR( 1 ) NOT NULL CHECK (TYPE IN ('1','2'))
  ,CONSRAINT B_PK PRIMARY KEY (B_ID)
  ,CONSRAINT B_UK UNIQUE (B_ID, TYPE)
) 
CREATE TABLE B1 (B_ID NUMBER NOT NULL
   ,TYPE CHAR( 1 ) DEFAULT '1' NOT NULL CHECK (TYPE='1')
   , ...
   ,CONSTRAINT B1_FK FOREIGN KEY (B_ID, TYPE) REFERENCES B (B_ID, TYPE) 
) 
CREATE TABLE B2 (B_ID NUMBER
  ,TYPE CHAR( 1 ) DEFAULT '2' NOT NULL CHECK (TYPE='2')
  , ...
  ,CONSTRAINT B2_FK FOREIGN KEY (B_ID, TYPE) REFERENCES B (B_ID, TYPE) 
)
CREATE TABLE A ( ...., B_ID FOREGN KEY REFERENCES B (B_ID), ... )
этакий тип-подтип...
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963526
Фотография Old Nick
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Херней маетесь :-)
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963662
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
Павел ВоронцовРискну предложить ещё один вариант.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
CREATE TABLE B (B_ID NUMBER NOT NULL
  ,TYPE CHAR( 1 ) NOT NULL CHECK (TYPE IN ('1','2'))
  ,CONSRAINT B_PK PRIMARY KEY (B_ID)
  ,CONSRAINT B_UK UNIQUE (B_ID, TYPE)
) 
CREATE TABLE B1 (B_ID NUMBER NOT NULL
   ,TYPE CHAR( 1 ) DEFAULT '1' NOT NULL CHECK (TYPE='1')
   , ...
   ,CONSTRAINT B1_FK FOREIGN KEY (B_ID, TYPE) REFERENCES B (B_ID, TYPE) 
) 
CREATE TABLE B2 (B_ID NUMBER
  ,TYPE CHAR( 1 ) DEFAULT '2' NOT NULL CHECK (TYPE='2')
  , ...
  ,CONSTRAINT B2_FK FOREIGN KEY (B_ID, TYPE) REFERENCES B (B_ID, TYPE) 
)

Интересный вариант, такая себе дополнительная жесткость образуется. Но при этом в B все равно могут быть записи, причем с любым значением TYPE, на которые никто не ссылается. Для моего случая точно не подходит, но если подклассов много - сгодится, наверное.

Павел Воронцов
Код: plaintext
1.
CREATE TABLE A ( ...., B_ID FOREGN KEY REFERENCES B (B_ID), ... )

А вот зачем это нужно, я не понял. Мне, по крайней мере, показалось, что "суперкласс" - это B , у него "подклассы" - B1 и B2 . При чем здесь вообще A ?
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963720
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нужно учиться работать с гуглом http://www.google.ru/search?hl=ru&q=discriminator+column&lr=

Вот от Versant

автор6.3. Inheritance
Classes in an inheritance hierarchy can be mapped to the same table (flat) or to different tables (vertical) or any combination of the two strategies. Each class indicates how it is mapped to its superclass. Flat mapping requires the addition of a discriminator or indicator column to the table for the base class to identify the type of each row (except for one special case Section 6.3.6). The default name of the descriminator column is 'jdo_class'. This is optional for vertical mapping. The discriminator column value for each class can be an int or a String.

The discriminator column is mapped to a SQL INTEGER if all of the discriminator values are ints, and a SQL VARCHAR otherwise, but can be changed using the Workbench or editing the jdbc-class-id extension (see Section 21.9) in the meta data. The default class-id (or discriminator) value for a class is a 32 bit positive hash of the fully qualified class name but you can also change this using jdbc-class-id extension or by editing class properties in the Workbench. In particular the default can be changed to the fully qualified name of the class or the name without package (see Section 6.3.4).

вот кусок документации к hibernate

автор
8.1. The Three Strategies
Hibernate supports the three basic inheritance mapping strategies.

table per class hierarchy

table per subclass

table per concrete class (some limitations)
...
Note that Hibernate's implementation of table-per-subclass requires no discriminator column.

Если коротко - discriminator column - это поле определяющее класс к которому принадлежит данная запись-объект
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963847
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
funikovyuriНужно учиться работать с гуглом http://www.google.ru/search?hl=ru&q=discriminator+column&lr=
<skip>
вот кусок документации к hibernate
<skip>
Если коротко - discriminator column - это поле определяющее класс к которому принадлежит данная запись-объект
Это я видел, но оно довольно малоинформативно. А в статье discrimination.html , которая к hibernate, видимо, какое-то отношение имеет, объясняют доходчиво и на примерах :) У меня, по-видимому, стратегия "table per subclass", в которой, согласно и тому, что читал я, и тому, что писали вы, использовать физическое поле для дискриминатора необязательно. В статье предлагают в таком случае вычислять его примерно так, как советовал Павел Воронцов. Поскольку собственно значение дискриминатора мне использовать не нужно (мне бы только выборку), то фактически, я его неявно ввожу как вычисляемое :)
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963954
Фотография Павел Воронцов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LVUА вот зачем это нужно, я не понял. Мне, по крайней мере, показалось, что "суперкласс" - это B , у него "подклассы" - B1 и B2 . При чем здесь вообще A ?Это вариант ссылки на суперкласс. Когда я такое ваял меня спрашивали "А вот как бы сделать так, чтобы была ссылка либо на одну либо на другую таблицу". Такой вот был вопрос. Наличие "объектов" "суперкласса" без конкретных подтипов - проблаема решаемая. Если бы Вы работали с Ораклом и/или МС, я бы подсказал конкретные пути. А ФБ не знаю, увы.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32963980
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
Павел ВоронцовЭто вариант ссылки на суперкласс. Когда я такое ваял меня спрашивали "А вот как бы сделать так, чтобы была ссылка либо на одну либо на другую таблицу". Такой вот был вопрос.

Понятно :)

Павел ВоронцовНаличие "объектов" "суперкласса" без конкретных подтипов - проблаема решаемая. Если бы Вы работали с Ораклом и/или МС, я бы подсказал конкретные пути. А ФБ не знаю, увы.
Давайте для Оракла и/или МС, с ними я тоже работал. Все это не имеет отношения к моей задаче, т.к. держать практически пустую таблицу для "чистых" объектов A ИМХО глупо, но в целом интересно, какое там решение.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32964016
funikovyuri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Павел Воронцов

Уважаемый - а CONSRAINT B_UK разве не лишний?


LVU

У Павла есть дескриминатор - это поле тип. Я за дескриминатор, так как он позволяет работать с иерархиями наследования на стороне сервера БД очень эффективно и практически за даром. Насчет того что hibernate может для table per class работать без него это хорошо - НО этого так просто не сможете вы на стороне сервера без каких-то других систем метаданных
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32964073
LVU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LVU
Гость
funikovyuri Павел Воронцов

Уважаемый - а CONSRAINT B_UK разве не лишний?

Рискну ответить за него - без B_UK не удастся сделать B1_FK и B2_FK, т.к. Foreign Key должен "смотреть" либо на Primary Key, либо на Unique (по кр. мере в FB, в остальных не помню. Но это, вроде, логично?)

funikovyuri
LVU

У Павла есть дескриминатор - это поле тип. Я за дескриминатор, так как он позволяет работать с иерархиями наследования на стороне сервера БД очень эффективно и практически за даром. Насчет того что hibernate может для table per class работать без него это хорошо - НО этого так просто не сможете вы на стороне сервера без каких-то других систем метаданных
Когда я говорил о предложении Павла, я имел в виду этот вариант anti-join'а. Собственно, anti-join и есть та единственная "система метаданных", которой эта схема отличается от использования дискриминатора. Впрочем, именно к дискриминатору я сколняюсь. Надо будет еще провести тест скорости, насколько этот anti-join тормозит.
...
Рейтинг: 0 / 0
Связь один-к-одному
    #32965912
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
LVUА действительно ли один фиг?


Один, один. Даже с NOT EXISTS еще и лучше вариант - потенциально он быстрее, и лучше отражает суть операции.
...
Рейтинг: 0 / 0
23 сообщений из 23, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Связь один-к-одному
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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