我想知道是否有人可以帮助提高我对SQL中JOIN的理解.[如果它对问题很重要,我正在考虑MS SQL Server.]
取3个表A,B [A由某些A.AId相关]和C [B与某些B.BId相关的C]
如果我撰写查询,例如
SELECT *
FROM A JOIN B
ON A.AId = B.AId
Run Code Online (Sandbox Code Playgroud)
一切都很好 - 我对它的运作方式很满意.
当表C(或其他一些D,E,......被添加)时会发生什么
在这种情况下
SELECT *
FROM A JOIN B
ON A.AId = B.AId
JOIN C ON C.BId = B.BId
Run Code Online (Sandbox Code Playgroud)
什么是C加入? - 是B表(以及B表中的值吗?)或者是C表加入的A + B Join的结果是否是其他临时结果集?
[暗示并非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
Run Code Online (Sandbox Code Playgroud)
从概念上讲,关闭日期的平衡,将是明天的平衡
如果我正在尝试查找帐户的所有期初和期末余额列表
我可能会做类似的事情
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
Run Code Online (Sandbox Code Playgroud)
事情按照我的预期工作,直到最后一次JOIN带来结束余额令牌 - 我最终在结果中重复.
[我可以用DISTINCT修复 - 但我试图理解为什么发生的事情正在发生]
我被告知问题是因为Balance和BalanceToken之间的关系是1:M - 当我引入最后一个JOIN时我得到重复,因为第3个JOIN已经多次将BalanceIds引入(我假设)临时结果集.
我知道示例表不符合良好的数据库设计
为这篇文章道歉,感谢任何提高:)
编辑以回应Marc提出的问题
从概念上来说,账户中的BalanceToken不应该有重复(每个AccountingDate) - 我认为问题是因为1账户/会计日期的期末余额是第二天的账户期初余额 - 所以当自我加入Balance,BalanceToken多次获得期初和期末余额我认为Balances(BalanceId)被多次带入'结果组合'.如果它有助于澄清第二个示例,将其视为每日对帐 - 因此左联接 - 可能尚未计算给定帐户/会计日期组合的期初(和/或)期末余额.
WW.*_*WW. 42
从概念上讲,这是将三个表连接在一起时会发生什么.
WHERE
子句)应用于不涉及任何其他表的第一个表.它选择JOIN
条件或SELECT
列表或ORDER BY
列表中提到的列.调用此结果A.ORDER BY
这在概念上会发生什么.事实上,在此过程中有许多可能的优化.关系模型的优点在于,良好的数学基础使得计划的各种变换成为可能,同时不改变正确性.
例如,实际上不需要沿途生成完整的结果集.在ORDER BY
可以替代地经由访问利用在第一位置的索引数据来完成.有许多类型的连接也可以完成.
我们知道来自B
(内部)连接的数据将被过滤A
(数据输入A
也被过滤).因此,如果我们(内部)从加盟B
到C
,这样的设定C
是还通过关系来过滤A
.另请注意,将包含来自联接的任何重复项.
然而; 这种情况发生的顺序取决于优化器; 它可以决定先B
/ C
join然后引入A
,或任何其他序列(可能基于每个连接的估计行数和适当的索引).
然而; 在后面的例子中,你使用了一个LEFT OUTER
连接; 所以Account
根本没有过滤,如果任何其他表有多个匹配,我可能会重复.
是否有重复(每个帐户)BalanceToken
?