我想知道是否有人可以帮助我提高对 SQL 中 JOIN 的理解。 [如果它对问题很重要,我会特别考虑 MS SQL Server。]
取 3 个表 A、B [A 通过某些 A.AId 与 B 相关] 和 C [B 通过某些 B.BId 与 C 相关]
如果我编写一个查询,例如
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表(以及其中的值)吗? 或者是其他一些临时结果集,是 C 表连接到的 A+B 连接的结果?
[这意味着根据 A,B 的连接条件,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 中不应该有重复项(每个 AccountingDate) - 我认为问题的出现是因为 1 个 Account/AccountingDates 的期末余额是第二天的帐户期初余额 - 所以当 self 加入到多次使用 Balance、BalanceToken 来获取期初和期末余额,我认为余额(BalanceId)被多次纳入“结果组合”中。如果有助于澄清第二个示例,请将其视为每日对账 - 因此左连接 - 可能尚未计算给定帐户/会计日期组合的期初(和/或)期末余额。
最佳答案
概念上是将三个表连接在一起时会发生的情况。
- 优化器会提出一个计划,其中包括连接顺序。可以是 A、B、C 或 C、B、A 或任意组合
- 查询执行引擎将任何谓词(
WHERE
子句)应用于不涉及任何其他表的第一个表。它选择JOIN
条件或SELECT
列表或ORDER BY
列表中提到的列。将此结果称为 A - 它将此结果集连接到第二个表。对于每一行,它连接到第二个表,应用可能适用于第二个表的任何谓词。这会产生另一个临时结果集。
- 然后加入最终表并应用
ORDER BY
这就是概念上所发生的情况。事实上,在此过程中有许多可能的优化。关系模型的优点在于,良好的数学基础使得计划的各种变换成为可能,同时又不改变正确性。
例如,实际上没有必要一路生成完整的结果集。 ORDER BY 可以通过首先使用索引访问数据来完成。还可以执行多种类型的连接。
关于sql - 了解涉及 3 个或更多表时 JOIN 的工作原理。 [SQL],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1083676/