67 votes

Comprendre comment les JOINDRE fonctionne lorsque 3 ou plusieurs tables sont impliqués. [SQL]

Je me demande si quelqu'un peut aider à améliorer ma compréhension de Jointures en SQL. [Si elle est significative pour le problème, je pense, MS SQL Serveur en particulier.]

Prendre 3 tableaux A, B [Un liés à certains A. Aide] et C [B liées à C par certains B. Offre]

Si je compose une requête d'e.g

SELECT *
FROM A JOIN B 
ON A.AId = B.AId

Tous les bon - je suis doux, avec de comment cela fonctionne.

Ce qui se passe lors de la Table C (Ou une autre D,E, .... est ajouté)

Dans la situation

SELECT *
FROM A JOIN B 
  ON A.AId = B.AId
JOIN C ON C.BId = B.BId

Qu'est-ce que C de se joindre à l'? - est-ce que B tableau (et les valeurs dans la B tableau?) Ou est-ce une temporaire du résultat qui est le résultat de A+B à Rejoindre la table C est joint à?

[L'implication est pas toutes les valeurs qui sont dans le B tableau sera forcément dans le résultat temporaire ensemble A+B basé sur la condition de jointure pour A,B]

Spécifique (et assez artificiel) exemple de pourquoi je demande c'est parce que je suis en train d'essayer de comprendre le comportement que je vois dans le texte suivant:

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

Sur le plan conceptuel, Solde de Clôture d'une date, serait lendemains solde d'ouverture

Si j'essayais de trouver une liste de tous les d'ouverture et de clôture des soldes pour 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 j'attendrais jusqu'à ce que la JOINTURE dernier apporte le solde de clôture des jetons - où je me retrouve avec des doublons dans le résultat.

[Je peux le fixer avec un DISTINCTES - mais je suis en train d'essayer de comprendre pourquoi ce qui se passe se passe]

J'ai été dit que le problème, c'est parce que la relation entre l'Équilibre et BalanceToken est de 1:M - et quand je l'ai amener dans le dernier REJOINDRE je suis à la présence de doublons parce que le 3ème JOINDRE a déjà apporté BalanceIds plusieurs fois dans l' (je suppose) temporaire jeu de résultats.

Je sais que les tables ne sont pas conformes aux bonnes DB design

Les excuses de la rédaction, merci pour tout elightenment :)

Edit en réponse à la question de Marc

Sur le plan conceptuel pour un compte il ne devrait pas avoir de doublons dans BalanceToken pour Un Compte (par AccountingDate) - je pense que le problème vient de parce que 1 Compte / AccountingDates solde de clôture est que les Comptes de bilan d'ouverture pour le lendemain - lorsque l'adhésion à l'Équilibre, BalanceToken plusieurs fois afin d'obtenir l'ouverture et la fermeture des soldes, je pense que les Soldes (BalanceId) sont amenés dans le résultat du mélange " plusieurs fois. Si elle contribue à clarifier le deuxième exemple, le considèrent comme un rapprochement quotidien - d'où left join - une ouverture (et/ou) solde à la clôture peuvent ne pas avoir été calculé pour un compte / accountingdate combinaison.

40voto

WW. Points 11335

Conceptuellement, voici ce qui se passe lorsque vous vous joignez à trois tables.

  1. L'optimiseur arrive avec un plan, qui comprend un ordre de jointure. Il pourrait être A, B, C, ou C, B, A ou l'une des combinaisons
  2. Le moteur d'exécution de requête s'applique tout prédicats (WHERE clause) à la première table qui n'implique pas les autres tables. Il sélectionne les colonnes mentionnées dans l' JOIN conditions ou l' SELECT de liste ou de l' ORDER BY de la liste. Appel ce résultat à Un
  3. Il se joint à cet ensemble de résultats de la deuxième table. Pour chaque ligne, il se joint à la seconde table, l'application de tous les prédicats qui peuvent s'appliquer à la deuxième table. Cette résultats dans une autre entreprise de jeu de résultats.
  4. Puis il se joint à la table finale et s'applique à l' ORDER BY

C'est conceptuellement ce qui se passe. Enfait il y a de nombreuses optimisations possibles le long du chemin. L'avantage du modèle relationnel est que le son de base mathématique fait diverses transformations de plan possible, tout en ne changeant pas l'exactitude.

Par exemple, il n'est vraiment pas nécessaire pour générer le résultat complet des ensembles le long de la voie. L' ORDER BY au lieu de cela peut être fait par le biais de l'accès aux données à l'aide d'un indice dans la première place. Il y a beaucoup de types de jointures qui peut être fait ainsi.

5voto

Marc Gravell Points 482669

Nous savons que les données provenant B va être filtré par l' (intérieure) de se joindre à l' A (données en A est également filtrée). Donc, si nous (intérieure) de joindre B de C, donc l'ensemble C est également filtré par la relation d' A. Et notez également que toutes les doublons à partir de la jointure sera inclus.

Cependant, ce que l'ordre de ce qui se passe dans l'est jusqu'à l'optimiseur; il peut décider de faire l' B/C rejoignez d'abord, puis introduire A, ou de toute autre séquence (probablement basé sur l'estimation du nombre de lignes de chaque jointure et l'index appropriés).


CEPENDANT, plus tard dans votre exemple vous utilisez un LEFT OUTER rejoindre; donc, Account n'est pas filtré à tous, et peut-eh bien, mon dupliqué si les autres tables ont des correspondances multiples.

Sont t-il des doublons (par compte) en BalanceToken?

1voto

Bernhard Hofmann Points 4741

Souvent, je trouve que ça aide pour afficher le plan d'exécution. Dans l'analyseur de requête/management studio, vous pouvez activer ce paramètre pour les requêtes dans le menu Requête, ou utilisez Ctrl+M). Après l'exécution de la requête, le plan a été exécuté est montré dans un autre onglet résultat. À partir de cela, vous verrez que C et B sont des joints d'abord, et puis le résultat est joint avec A. Le plan peut varier en fonction de l'information le SGBD est parce que les deux jointures intérieure, faisant d'elle A-et-B-et-C Ce que je veux dire est que le résultat sera le même, peu importe qui est rejoint en premier, mais le temps peut varier considérablement, et c'est là que l'optimiseur et des conseils entrent en jeu.

1voto

Console Points 608

Joint peut être difficile, et beaucoup de ce comportement est évidemment dictée par la façon dont les données sont stockées dans les tables réelles.

Sans voir les tableaux, il est difficile de donner une réponse claire dans votre cas particulier, mais je pense que la question fondamentale est que vous êtes à la sommation sur plusieurs ensembles de résultats sont combinés en un seul.

Peut-être, au lieu de plusieurs jointures, vous devriez faire deux tables temporaires dans votre requête, l'une avec le accountID, la date et la somme de openingbalances, une seconde avec le accountID, la date et la somme des soldes de clôture, puis de rejoindre ces deux sur AccountID et la date.

Afin de savoir exactement ce qui se passe avec des jointures, aussi dans votre cas particulier, je voudrais faire le suivant:

Changement de la partie initiale

SÉLECTIONNEZ accountID Accountbalancedate, somme(...) comme openingbalance, somme(...) comme closingbalance DE

tout simplement

"SELECT * FROM"

L'étude de la table résultante, et vous verrez exactement ce que les données sont dupliquées. Retirez le joint, un par un et voir ce qui se passe. Cela devrait vous donner une idée de ce que c'est au sujet de vos données en particulier qui est à l'origine de dupes.

Si vous ouvrez la requête dans SQL server management studio (version Gratuite existe) vous pouvez modifier la requête dans le concepteur. La vue de la façon dont les tables sont jointes peuvent également vous aider à réaliser ce qu'il se passe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: