Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Проектирование БД Новый топик    Ответить
 В одной таблице два FK на один PK другой таблицы  [new]
ru_efim
Member

Откуда:
Сообщений: 127
Здравствуйте.
Есть таблица содержащая два FK на один PK второй таблицы. В общем, если упростить до предела будет так:
CREATE TABLE [A_RUser] ( --Реестр пользователей
	[UserId] [int] NOT NULL ,
	[Family] [varchar] (50) NOT NULL ,
	CONSTRAINT [PK_A_RUser] PRIMARY KEY CLUSTERED ([UserId]) ON [PRIMARY] 
) ON [PRIMARY]
GO

CREATE TABLE [A_Transfer] ( --Акт передачи
	[TransId] [int] IDENTITY (1, 1) NOT NULL ,
	[User_Sender] [int] NOT NULL ,
	[User_Receiver] [int] NOT NULL ,
	[Volume_Transfer] [int] NOT NULL ,
	CONSTRAINT [PK_Trans] PRIMARY KEY CLUSTERED ([TransId]) ON [PRIMARY],
	CONSTRAINT [FK_TransReceiv_RUser]	FOREIGN KEY ([User_Receiver])	REFERENCES [A_RUser] ([UserId]),
	CONSTRAINT [FK_TransSend_RUser]		FOREIGN KEY ([User_Sender])	REFERENCES [A_RUser] ([UserId])
) ON [PRIMARY]
GO
--Наполняем данными
INSERT INTO A_RUser(UserId, Family) VALUES(1, 'Иванов')
INSERT INTO A_RUser(UserId, Family) VALUES(2, 'Петров')
INSERT INTO A_RUser(UserId, Family) VALUES(3, 'Сидоров')
GO
INSERT INTO A_Transfer(User_Sender, User_Receiver, Volume_Transfer) VALUES(1, 2, 10)
INSERT INTO A_Transfer(User_Sender, User_Receiver, Volume_Transfer) VALUES(2, 3, 5)
INSERT INTO A_Transfer(User_Sender, User_Receiver, Volume_Transfer) VALUES(3, 1, 5)

Хоть и упростил до безобразия, но думаю суть понятна.
Вопрос: С одной стороны, все как бы логично, вполне себе нормальное представление реальной ситуации "сегодня петров отправитель, Сидоров получатель, завтра наоборот".
Но с другой стороны какая то ерунда. Каскадное удаление, обновление связанных записей не допустимо (для обоих связей одновременно на MS SQL Server). Запросы с "вытаскиванием через связь", в данном случае Фамилий, ... какие то ... конкретно в этом примере нормально, но ... Если связь будет "длиннее", например через FK через таблицу A_RUser(как "промежуточную") в свою очередь, так же через FK придется "тащить" еще что нибудь из третей таблицы то такая "этажерка" получится.
Короче вопрос, по моему "структура!" какая-то ущербная, то ли таблицы не хватает, то ли Чего? По моему ситуация стандартная, но мой мизерный опыт не позволяет найти решение. Помогите пожалуйста.
23 май 16, 23:29    [19209864]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
vmag
Member

Откуда: MP
Сообщений: 2977
ru_efim,

просто мысли в слух:
- Каскадное удаление, обновление... - если всё по уму, то обычно первичные ключи это счётчики (обновляются не они, а паровоз за ними идущий)
- можно в схеме данных оставить только одну связь (или к отправителю или к получателю) а вторую вытягивать искусственно по мере необходимости в запросах и процедурах
- можно в схеме данных оставить только одну связь (или к отправителю или к получателю), а затем добавить главную таблицу в схему БД ещё один раз (с псевдонимом) и протянуть вторую связь уже от дубликата

ну а так-то нужно пробовать...
24 май 16, 08:38    [19210232]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
ru_efim
Member

Откуда:
Сообщений: 127
vmag, спасибо. Но мне КАЖЕТСЯ что в данной схеме именно что-то не так.
Как бы с конкретной реализацией целостности, за счет связей, проблем то и нет. Как вы правильно говорите "обычно первичные ключи это счётчики (обновляются не они, а паровоз за ними идущий)"
Просто на всех этапах с такой схемой возникают какие то проблемы.
Вот на пример, получаем результирующий набор
SELECT
	tr.TransId,
	send.Family AS Sender,
	tr.Volume_Transfer AS Volume
	FROM
		A_Transfer AS tr
		INNER JOIN A_RUser AS send ON tr.User_Sender	= send.UserId
		INNER JOIN A_RUser AS recv ON tr.User_Receiver	= recv.UserId

Далее (в общем я вначале упростил до безобразия, а теперь пытаюсь прикрутить к этому что-то реальное)...
Предположим поле A_Transfer.User_Receiver не является обязательным (ну вот передал в некуда и все (предположим, по пустому полю мы определяем например утерю)!). Я вот, сходу, не могу придумать, как построить запрос, возвращающий такой же набор, как приведенный запрос выше. Хотя всего ДВЕ таблицы.
Вот мне и КАЖЕТСЯ что проблема не в умении строить sql-запросы, а именно в схеме, по этому и написал в данную ветку.
24 май 16, 11:37    [19211213]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
ru_efim
Member

Откуда:
Сообщений: 127
Простите ошибся.
SELECT
	tr.TransId,
	send.Family AS Sender,
	recv.Family AS Receiver,
	tr.Volume_Transfer AS Volume
	FROM
		A_Transfer AS tr
		INNER JOIN A_RUser AS send ON tr.User_Sender	= send.UserId
		INNER JOIN A_RUser AS recv ON tr.User_Receiver	= recv.UserId
24 май 16, 11:40    [19211242]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
Кот Матроскин
Member

Откуда: Москва
Сообщений: 8500
ru_efim,

Схема нормальная, on delete cascade в рабочих базах не нужен примерно никогда.
Если паче чаяния нужен - можно руками написать удаляющий запрос.
автор
Предположим поле A_Transfer.User_Receiver не является обязательным (ну вот передал в некуда и все (предположим, по пустому полю мы определяем например утерю)!). Я вот, сходу, не могу придумать, как построить запрос, возвращающий такой же набор, как приведенный запрос выше.


Заменить в одном месте inner на left, ясное дело.
24 май 16, 11:50    [19211300]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
Cane Cat Fisher
Member

Откуда:
Сообщений: 1700
Ситуация с двумя FK на одну таблицу ничего плохого не содержит. Трудности решаемы, если что давайте их обсуждать.

Конкретно по получателю и отправителю - не знаю, что вы отправляете, но обычно отправитель действительно один, а вот получателей как правило бывает несколько.
24 май 16, 12:11    [19211464]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
ru_efim
Member

Откуда:
Сообщений: 127
СПАСИБО.
Сижу второй день бьюсь с подобной схемой, то тут не так, то здесь не очень. А на запросе "при необязательном поле" совсем расстроился. И началось мне казаться что схема не такая ...
Короче, "Кот Матроскин " спасибо отдельно, ну вот забыл я как то про то что кроме INNER еще и внешние и не только есть.
24 май 16, 12:33    [19211653]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
Mr.Fontaine
Member

Откуда: у меня столько мыслей?
Сообщений: 661
Cane Cat Fisher, ну не знаю про обычно.... Вот например, отправил я посылку с велосипедом, на нескольких получателей. Один в Туле, другой в Магадане, третий вообще в какой-нибудь Нягани. И чё? Куда посылка поедет?
Я конечно согласен, что например спам по электронной почте отправляется обычно нескольким получателям.
Потому всё-таки слово "обычно" кажется мне лишним. "иногда" или "для некоторых типов отправлений" это кончено согласен

P.S. То есть как бы в общем случае требуется отдельная табличка - A_Receivers. Так бы и написали.
24 май 16, 12:36    [19211680]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
mini.weblab
Member

Откуда:
Сообщений: 632
ru_efim,

а "правильно" это как?
задачу вам какую поставили ?

24 май 16, 14:16    [19212436]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
softwarer
Member

Откуда: 127.0.0.1
Сообщений: 54322
Блог
ru_efim
Но с другой стороны какая то ерунда. Каскадное удаление, обновление связанных записей не допустимо

Может и не допустимо. А зачем оно нужно? Допустим, Вы одолжили мне сто рублей. Допустим, Вас пристрелили. Я ещё пойму постановку вопроса "в этом случае долг аннулируется, запись о нём нужно удалить", но решительно протестую против "в этом случае нужно каскадно удалить из реальности и меня тоже". Так что ерунда вовсе не в таблицах :)

ru_efim
Запросы с "вытаскиванием через связь", в данном случае Фамилий, ... какие то ... конкретно в этом примере нормально, но ... Если связь будет "длиннее", например через FK через таблицу A_RUser(как "промежуточную") в свою очередь, так же через FK придется "тащить" еще что нибудь из третей таблицы то такая "этажерка" получится.

(пожимая плечами) Два FK не имеют ровным счётом никакого отношения к этой проблеме. Допустим, остался только один FK. Что, "этажерка" станет меньше? Сколько этажей нагромоздил - такую этажерку получишь, закон жизни.

ru_efim
Короче вопрос, по моему "структура!" какая-то ущербная, то ли таблицы не хватает, то ли Чего?

Думаете, ещё одна промежуточная таблица сделает этажерку меньше?

Кардинально схем решения этой задачи две: проводки и полупроводки. Об их плюсах и минусах исписаны тысячи страниц, гугль даст миллионы ссылок. Какая из них лучше для Вашей задачи - по "упрощённой для безобразия" не скажешь.
25 май 16, 00:34    [19215471]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34331
ru_efim
vmag, спасибо. Но мне КАЖЕТСЯ что в данной схеме именно что-то не так.....
Вот мне и КАЖЕТСЯ что проблема не в умении строить sql-запросы, а именно в схеме, по этому и написал в данную ветку.


когда кажется, надо что делать?
Правильно, надо перекреститься и работать спокойно дальше.
Все у тебя ок со структурой, несколько fk из одной таблицы - нормальное явление.

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

Эту ситуацию необходимо отличать от другой, когда родителей (в смысле связи таблиц) может быть переменное количество. в таком случае нужно делать дополнительную таблицу связи.
26 май 16, 06:48    [19220900]     Ответить | Цитировать Сообщить модератору
 Re: В одной таблице два FK на один PK другой таблицы  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34331
ru_efim
Предположим поле A_Transfer.User_Receiver не является обязательным (ну вот передал в некуда и все (предположим, по пустому полю мы определяем например утерю)!). Я вот, сходу, не могу придумать, как построить запрос, возвращающий такой же набор, как приведенный запрос выше. Хотя всего ДВЕ таблицы.



ты еще и SQL не знаешь...
Вот тебе и кажется все.
Короче, для тебя специально - когда кажется, перекрестись и учи SQL.

А тут надо LEFT JOIN.
26 май 16, 06:52    [19220903]     Ответить | Цитировать Сообщить модератору
Все форумы / Проектирование БД Ответить