Je me demande si quelqu'un peut m'aider à améliorer ma compréhension des JOIN en SQL. (Si c'est important pour le problème, je pense spécifiquement à MS SQL Server).
Prenez 3 tables A, B [A lié à B par un certain A.AId], et C [B lié à C par un certain B.BId].
Si je compose une requête, par exemple
SELECT *
FROM A JOIN B
ON A.AId = B.AId
Tout va bien - je suis content de la façon dont cela fonctionne.
Que se passe-t-il lorsque la table C (ou une autre D, E, ....) est ajoutée ?
Dans la situation
SELECT *
FROM A JOIN B
ON A.AId = B.AId
JOIN C ON C.BId = B.BId
À quoi C se joint-il ? - Est-ce la table B (et les valeurs qu'elle contient) ? Ou est-ce un autre ensemble de résultats temporaire qui est le résultat de la jointure A+B à laquelle la table C est jointe ?
(L'implication étant que toutes les valeurs qui sont dans la table B ne seront pas nécessairement dans l'ensemble de résultats temporaires A+B basé sur la condition de jointure pour A,B).
Un exemple spécifique (et assez artificiel) de la raison pour laquelle je pose la question est que j'essaie de comprendre le comportement que je vois dans ce qui suit :
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
Conceptuellement, le solde de clôture d'une date est le solde d'ouverture du lendemain.
Si j'essayais de trouver une liste de tous les soldes d'ouverture et de fermeture d'un compte
Je pourrais faire quelque chose comme
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
Les choses fonctionnent comme prévu jusqu'à ce que le dernier JOIN apporte les jetons de solde de clôture - où je me retrouve avec des doublons dans le résultat.
[Je peux régler le problème avec un DISTINCT, mais j'essaie de comprendre pourquoi ce qui se passe se produit.]
On m'a dit que le problème est dû au fait que la relation entre Balance et BalanceToken est 1:M - et que lorsque j'introduis la dernière JOIN, j'obtiens des doublons parce que la 3ème JOIN a déjà introduit les BalanceIds plusieurs fois dans le jeu de résultats (je suppose) temporaire.
Je sais que les tables d'exemple ne sont pas conformes à la bonne conception des bases de données.
Toutes mes excuses pour la rédaction, merci pour tout éclaircissement :)
Modifier en réponse à la question de Marc
Conceptuellement, pour un compte, il ne devrait pas y avoir de doublons dans BalanceToken pour un compte (par AccountingDate) - je pense que le problème vient du fait qu'un compte / AccountingDates solde de clôture est ce compte solde d'ouverture pour le jour suivant - donc lorsque l'auto-jointure à Balance, BalanceToken plusieurs fois pour obtenir les soldes d'ouverture et de clôture, je pense que les soldes (BalanceId) sont introduits dans le "mélange de résultats" plusieurs fois. Si cela peut aider à clarifier le second exemple, considérez-le comme un rapprochement quotidien - d'où les jointures à gauche - un solde d'ouverture (et/ou) de clôture peut ne pas avoir été calculé pour une combinaison compte/date comptable donnée.
14 votes
+1 question détaillée et raisonnement propre.
1 votes
Un peu hors sujet mais qui vaut la peine d'être mentionné : codeproject.com/KB/database/Visual_SQL_Joins.aspx