Интересно, может ли кто-нибудь помочь улучшить мое понимание JOINs в SQL. [Если это важно для проблемы, я думаю, MS SQL Server конкретно.]
Возьмем 3 таблицы A, B [A, связанные с некоторыми A.AId], и C [B, связанные с C некоторым B.BId]
Если я составляю запрос, например,
SELECT *
FROM A JOIN B
ON A.AId = B.AId
Все хорошо - я доволен тем, как это работает.
Что происходит, когда таблица C (или добавляются другие D, E,....)
В ситуации
SELECT *
FROM A JOIN B
ON A.AId = B.AId
JOIN C ON C.BId = B.BId
К чему присоединяется C? - это таблица B (и значения в таблице B?) Или это какой-то другой временный результирующий набор, являющийся результатом объединения A + B, к которому привязана таблица C?
[Импликация - это не все значения, которые находятся в таблице B, обязательно будут во временном результирующем наборе A + B на основе условия соединения для A, B]
Конкретный (и довольно надуманный) пример того, почему я спрашиваю, заключается в том, что я пытаюсь понять поведение, которое я вижу в следующем:
Tables
Account (AccountId, AccountBalanceDate, OpeningBalanceId, ClosingBalanceId)
Balance (BalanceId)
BalanceToken (BalanceId, TokenAmount)
Where:
Account->Opening, and Closing Balances are NULLABLE
(may have opening balance, closing balance, or none)
Balance->BalanceToken is 1:m - a balance could consist of many tokens
Концептуально, итоговый баланс даты, будет означать открытие баланса
Если я пытался найти список всех открытых и закрывающих балансов для учетной записи
Я мог бы сделать что-то вроде
SELECT AccountId
, AccountBalanceDate
, Sum (openingBalanceAmounts.TokenAmount) AS OpeningBalance
, Sum (closingBalanceAmounts.TokenAmount) AS ClosingBalance
FROM Account A
LEFT JOIN BALANCE OpeningBal
ON A.OpeningBalanceId = OpeningBal.BalanceId
LEFT JOIN BALANCE ClosingBal
ON A.ClosingBalanceId = ClosingBal.BalanceId
LEFT JOIN BalanceToken openingBalanceAmounts
ON openingBalanceAmounts.BalanceId = OpeningBal.BalanceId
LEFT JOIN BalanceToken closingBalanceAmounts
ON closingBalanceAmounts.BalanceId = ClosingBal.BalanceId
GROUP BY AccountId, AccountBalanceDate
Вещи работают так, как я ожидал бы до тех пор, пока последний JOIN не привнесет токены с закрытием - где я получаю дубликаты в результате.
[Я могу исправить с помощью DISTINCT - но я пытаюсь понять, почему происходит то, что происходит]
Мне сказали, что проблема в том, что отношения между Balance и BalanceToken равны 1: M - и что, когда я привожу последний JOIN, я получаю дубликаты, потому что третий JOIN уже несколько раз вводил BalanceIds в ( Я предполагаю) временный набор результатов.
Я знаю, что таблицы примеров не соответствуют хорошему дизайну БД
Извинения за эссе, спасибо за любое восстание:)
Изменить в ответ на вопрос Marc
Концептуально для учетной записи не должно быть дубликатов в BalanceToken для учетной записи (на учетную дату). Я думаю, проблема возникает из-за того, что 1 баланс счета/счета-счетов-счетов является тем, что баланс счета начинается на следующий день - поэтому, когда я присоединяюсь к Баланс, BalanceToken несколько раз, чтобы получить открывающие и закрывающие балансы. Думаю, балансы (BalanceId's) несколько раз приводятся в "результат". Если это поможет прояснить второй пример, подумайте об этом как о ежедневной сверке - следовательно, о левом соединении - закрытие счета открытия (и/или) может не быть рассчитано для данной учетной записи/accountdate.