Jointure interne, jointure externe, jointure croisée ? Qu'est-ce que ça donne ?
C'est une question valable. J'ai vu une fois un code Visual Basic avec des codes T-SQL intégrés. Le code VB récupère les enregistrements de table avec plusieurs instructions SELECT, un SELECT * par table. Ensuite, il combine plusieurs ensembles de résultats dans un ensemble d'enregistrements. Absurde ?
Pour les jeunes développeurs qui l'ont fait, ce n'était pas le cas. Mais lorsqu'ils m'ont demandé d'évaluer pourquoi le système était lent, ce problème a été le premier à attirer mon attention. C'est exact. Ils n'ont jamais entendu parler des jointures SQL. En toute honnêteté envers eux, ils étaient honnêtes et ouverts aux suggestions.
Comment décrivez-vous les jointures SQL ? Peut-être vous souvenez-vous d'une chanson - Imagine par John Lennon :
Vous pouvez dire que je suis un rêveur, mais je ne suis pas le seul.
J'espère qu'un jour vous nous rejoindrez et que le monde ne fera plus qu'un.
Dans le contexte de la chanson, rejoindre c'est unir. Dans une base de données SQL, la combinaison d'enregistrements de 2 tables ou plus dans un ensemble de résultats forme une jointure .
Cet article est le début d'une série en 3 parties sur les jointures SQL :
- JOINTURE INTERNE
- OUTER JOIN, qui inclut LEFT, RIGHT et FULL
- JOINTURE CROISÉE
Mais avant de commencer à parler de INNER JOIN, décrivons les jointures en général.
En savoir plus sur SQL JOIN
Les jointures apparaissent juste après la clause FROM. Dans sa forme la plus simple, cela ressemble à la norme SQL-92 :
FROM <table source> [<alias1>]
<join type> JOIN <table source> [<alias2>] [ON <join condition>]
[<join type> JOIN <table source> [<alias3>] [ON <join condition>]
<join type> JOIN <table source> [<aliasN>] [ON <join condition>]]
[WHERE <condition>]
Décrivons les choses quotidiennes entourant le JOIN.
Sources du tableau
Vous pouvez ajouter jusqu'à 256 sources de tables, selon Microsoft. Bien sûr, cela dépend des ressources de votre serveur. Je n'ai jamais rejoint plus de 10 tables dans ma vie, sans parler de 256. Quoi qu'il en soit, les sources de table peuvent être l'une des suivantes :
- Tableau
- Afficher
- Synonyme de tableau ou de vue
- Variable de tableau
- Fonction table
- Table dérivée
Alias de table
Un alias est facultatif, mais il raccourcit votre code et minimise la saisie. Cela vous aide également à éviter les erreurs lorsqu'un nom de colonne existe dans deux ou plusieurs tables utilisées dans un SELECT, UPDATE, INSERT ou DELETE. Cela ajoute également de la clarté à votre code. C'est facultatif, mais je vous recommande d'utiliser des alias. (Sauf si vous aimez taper les sources de table par leur nom.)
Condition de jointure
Le mot-clé ON précède la condition de jointure qui peut être une seule jointure ou des colonnes à 2 clés des 2 tables jointes. Ou il peut s'agir d'une jointure composite utilisant plus de 2 colonnes clés. Il définit la manière dont les tables sont liées.
Cependant, nous utilisons la condition de jointure uniquement pour les jointures INNER et OUTER. L'utiliser sur un CROSS JOIN déclenchera une erreur.
Puisque les conditions de jointure définissent les relations, elles ont besoin d'opérateurs.
L'opérateur de condition de jointure le plus courant est l'opérateur d'égalité (=). D'autres opérateurs comme> ou
La plupart des jointures peuvent être réécrites sous forme de sous-requêtes et vice-versa. Consultez cet article pour en savoir plus sur les sous-requêtes par rapport aux jointures.
L'utilisation de tables dérivées dans une jointure ressemble à ceci :
Il se joint à partir du résultat d'une autre instruction SELECT, et il est parfaitement valide.
Vous aurez plus d'exemples, mais parlons d'une dernière chose à propos de SQL JOINS. C'est ainsi que les processus de l'optimiseur de requêtes de SQL Server se joignent.
Pour comprendre le fonctionnement du processus, vous devez connaître les deux types d'opérations impliquées :
Un seul mot :performances.
Une chose est de savoir comment former des requêtes avec des jointures pour produire des résultats corrects. Une autre consiste à le faire fonctionner aussi vite que possible. Vous devez vous préoccuper davantage de cela si vous voulez une bonne réputation auprès de vos utilisateurs.
Alors, que devez-vous rechercher dans le plan d'exécution pour ces opérations logiques ?
Les indicateurs de jointure sont nouveaux dans SQL Server 2019. Lorsque vous les utilisez dans vos jointures, ils indiquent à l'optimiseur de requête d'arrêter de décider ce qui convient le mieux à la requête. Vous êtes le patron quand il s'agit de la jointure physique à utiliser.
Maintenant, arrêtez-vous, juste là. En réalité, l'optimiseur de requête sélectionne généralement la meilleure jointure physique pour votre requête. Si vous ne savez pas ce que vous faites, n'utilisez pas d'indicateurs de jointure.
Les conseils possibles que vous pouvez spécifier sont LOOP, MERGE, HASH ou REMOTE.
Je n'ai pas utilisé d'indicateurs de jointure, mais voici la syntaxe :
INNER JOIN renvoie les lignes avec des enregistrements correspondants dans les deux tables, en fonction d'une condition. C'est aussi la jointure par défaut si vous ne spécifiez pas le mot-clé INNER :
Comme vous le voyez, les lignes correspondantes de Table1 et Table2 sont renvoyés à l'aide de Key1 comme condition de jointure. Le Table1 enregistrement ayant Key1 ='C' est exclu car il n'y a pas d'enregistrements correspondants dans Table2 .
Chaque fois que je forme une requête, mon premier choix est INNER JOIN. OUTER JOIN n'intervient que lorsque les exigences l'imposent.
Il existe deux syntaxes INNER JOIN prises en charge dans T-SQL :SQL-92 et SQL-89.
La première syntaxe de jointure que j'ai apprise était SQL-89. Lorsque SQL-92 est finalement arrivé, j'ai pensé que c'était trop long. J'ai aussi pensé que le résultat était le même, pourquoi s'embêter à taper plus de mots-clés ? Un concepteur de requêtes graphique avait le code généré SQL-92, et je l'ai changé en SQL-89. Mais aujourd'hui, je préfère SQL-92 même si je dois taper plus. Voici pourquoi :
Les raisons ci-dessus sont les miennes. Vous pouvez avoir vos raisons pour lesquelles vous préférez SQL-92 ou pourquoi vous le détestez. Je me demande quelles sont ces raisons. Faites-le moi savoir dans la section Commentaires ci-dessous.
Mais nous ne pouvons pas terminer cet article sans exemples et explications.
Voici un exemple de 2 tables jointes à l'aide de INNER JOIN dans la syntaxe SQL-92.
Vous ne spécifiez que les colonnes dont vous avez besoin. Dans l'exemple ci-dessus, 4 colonnes sont spécifiées. Je sais que c'est trop long que SELECT * mais gardez ceci à l'esprit :c'est la meilleure pratique.
Notez également l'utilisation d'alias de table. Le Produit et ProductSubcategory les tables ont une colonne nommée [Nom ]. Si vous ne spécifiez pas l'alias, une erreur sera déclenchée.
En attendant, voici la syntaxe SQL-89 équivalente :
Ils sont identiques à l'exception de la condition de jointure mélangée dans la clause WHERE avec un mot-clé AND. Mais sous le capot, sont-ils vraiment les mêmes ? Examinons le jeu de résultats, les E/S STATISTIQUES et le plan d'exécution.
Voir le jeu de résultats de 9 enregistrements :
Ce ne sont pas seulement les résultats, mais les ressources requises par SQL Server sont également les mêmes.
Voir les lectures logiques :
Enfin, le plan d'exécution révèle le même plan de requête pour les deux requêtes lorsque leur QueryPlanHashes sont égaux. Remarquez également les opérations en surbrillance dans le diagramme :
Sur la base des résultats, le traitement des requêtes SQL Server est le même, qu'il s'agisse de SQL-92 ou de SQL-89. Mais comme je l'ai dit, la clarté dans SQL-92 est bien meilleure pour moi.
La figure 7 montre également une jointure de boucle imbriquée utilisée dans le plan. Pourquoi? L'ensemble de résultats est petit.
Découvrez la requête ci-dessous en utilisant 3 tables jointes.
Vous pouvez également joindre 2 tableaux en utilisant 2 clés pour le relier. Découvrez l'exemple ci-dessous. Il utilise 2 conditions de jointure avec un opérateur AND.
Dans l'exemple ci-dessous, le Produit table a 9 enregistrements - un petit ensemble. La table jointe est SalesOrderDetail – un grand ensemble. L'optimiseur de requête utilisera une jointure de boucle imbriquée, comme illustré à la figure 8.
L'exemple ci-dessous utilise une jointure par fusion car les deux tables d'entrée sont triées par SalesOrderID.
L'exemple suivant utilisera une jointure par hachage :
Dans l'exemple ci-dessous, le Vendeur la table a un index ColumnStore non clusterisé sur TerritoryID colonne. L'optimiseur de requête a opté pour une jointure de boucle imbriquée, comme illustré à la figure 11.
Considérez cette déclaration avec une sous-requête imbriquée :
Les mêmes résultats peuvent apparaître si vous le remplacez par INNER JOIN, comme ci-dessous :
Une autre façon de le réécrire consiste à utiliser une table dérivée comme source de table pour INNER JOIN :
Les 3 requêtes génèrent les mêmes 48 enregistrements.
La requête suivante utilise une boucle imbriquée :
Si vous voulez le forcer à une jointure par hachage, voici ce qui se passe :
Cependant, notez que STATISTICS IO montre que les performances se dégradent lorsque vous le forcez à une jointure par hachage.
Pendant ce temps, la requête ci-dessous utilise une jointure par fusion :
Voici ce qu'il devient lorsque vous le forcez sur une boucle imbriquée :
Lors de la vérification des STATISTICS IO des deux, le forcer à une boucle imbriquée nécessite plus de ressources pour traiter la requête :
Ainsi, l'utilisation d'indicateurs de jointure devrait être votre dernier recours lorsque vous peaufinez les performances. Laissez votre serveur SQL le gérer pour vous.
Vous pouvez également utiliser INNER JOIN dans une instruction UPDATE. Voici un exemple :
Puisqu'il est possible d'utiliser une jointure dans un UPDATE, pourquoi ne pas essayer en utilisant DELETE et INSERT ?
Alors, quel est le problème avec la jointure SQL ?
Pendant ce temps, ce post a montré 10 exemples de INNER JOINs. Ce ne sont pas seulement des exemples de codes. Certains d'entre eux incluent également une inspection du fonctionnement du code de l'intérieur. Ce n'est pas seulement pour vous aider à coder, mais pour vous aider à être attentif aux performances. En fin de compte, les résultats ne doivent pas seulement être corrects, mais également livrés rapidement.
Nous n'avons pas encore fini. Le prochain article traitera des JOINS EXTERNES. Restez à l'écoute.
Les jointures SQL vous permettent d'extraire et de combiner des données de plusieurs tables. Regardez cette vidéo pour en savoir plus sur les jointures SQL.SQL JOIN vs sous-requêtes
Joints et tables dérivées
FROM table1 a
INNER JOIN (SELECT y.column3 from table2 x
INNER JOIN table3 y on x.column1 = y.column1) b ON a.col1 = b.col2
Comment SQL Server traite les jointures
Pourquoi devons-nous nous embêter avec ça ?
Conseils d'adhésion
<join type> <join hint> JOIN <table source> [<alias>] ON <join condition>
Tout sur la jointure interne
Syntaxe INNER JOIN
JOINTURE INTERNE SQL-92
FROM <table source1> [<alias1>]
INNER JOIN <table source2> [<alias2>] ON <join condition1>
[INNER JOIN <table source3> [<alias3>] ON <join condition2>
INNER JOIN <table sourceN> [<aliasN>] ON <join conditionN>]
[WHERE <condition>]
JOINTURE INTERNE SQL-89
FROM <table source1> [alias1], <table source2> [alias2] [, <table source3> [alias3], <table sourceN> [aliasN]]
WHERE (<join condition1>)
[AND (<join condition2>)
AND (<join condition3>)
AND (<join conditionN>)]
Quelle syntaxe INNER JOIN est la meilleure ?
10 exemples de jointures internes
1. Joindre 2 tables
-- Display Vests, Helmets, and Light products
USE AdventureWorks
GO
SELECT
p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p
INNER JOIN Production.ProductSubcategory ps ON P.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE P.ProductSubcategoryID IN (25, 31, 33); -- for vest, helmet, and light
-- product subcategories
-- Display Vests, Helmets, and Light products
USE AdventureWorks
GO
SELECT
p.ProductID
,P.Name AS [Product]
,ps.ProductSubcategoryID
,ps.Name AS [ProductSubCategory]
FROM Production.Product p, Production.ProductSubcategory ps
WHERE P.ProductSubcategoryID = ps.ProductSubcategoryID
AND P.ProductSubcategoryID IN (25, 31, 33);
2. Rejoindre plusieurs tables
-- Get the total number of orders per Product Category
USE AdventureWorks
GO
SELECT
ps.Name AS ProductSubcategory
,SUM(sod.OrderQty) AS TotalOrders
FROM Production.Product p
INNER JOIN Sales.SalesOrderDetail sod ON P.ProductID = sod.ProductID
INNER JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
INNER JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
WHERE soh.OrderDate BETWEEN '1/1/2014' AND '12/31/2014'
AND p.ProductSubcategoryID IN (1,2)
GROUP BY ps.Name
HAVING ps.Name IN ('Mountain Bikes', 'Road Bikes')
3. Jointure composite
SELECT
a.column1
,b.column1
,b.column2
FROM Table1 a
INNER JOIN Table2 b ON a.column1 = b.column1 AND a.column2 = b.column2
4. INNER JOIN Utilisation d'une jointure physique de boucle imbriquée
USE AdventureWorks
GO
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
5. INNER JOIN Utilisation d'une jointure physique de fusion
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
6. INNER JOIN Utilisation d'une jointure physique par hachage
SELECT
s.Name AS Store
,SUM(soh.TotalDue) AS TotalSales
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.Store s ON soh.SalesPersonID = s.SalesPersonID
GROUP BY s.Name
7. INNER JOIN Utilisation de la jointure physique adaptative
SELECT
sp.BusinessEntityID
,sp.SalesQuota
,st.Name AS Territory
FROM Sales.SalesPerson sp
INNER JOIN Sales.SalesTerritory st ON sp.TerritoryID = st.TerritoryID
WHERE sp.TerritoryID BETWEEN 1 AND 5
8. Deux façons de réécrire une sous-requête en INNER JOIN
SELECT [SalesOrderID], [OrderDate], [ShipDate], [CustomerID]
FROM Sales.SalesOrderHeader
WHERE [CustomerID] IN (SELECT [CustomerID] FROM Sales.Customer
WHERE PersonID IN (SELECT BusinessEntityID FROM Person.Person
WHERE lastname LIKE N'I%' AND PersonType='SC'))
SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.lastname LIKE N'I%'
SELECT o.[SalesOrderID], o.[OrderDate], o.[ShipDate], o.[CustomerID]
FROM Sales.SalesOrderHeader o
INNER JOIN (SELECT c.CustomerID, P.PersonType, P.LastName
FROM Sales.Customer c
INNER JOIN Person.Person p ON c.PersonID = P.BusinessEntityID
WHERE p.PersonType = 'SC'
AND p.LastName LIKE N'I%') AS q ON o.CustomerID = q.CustomerID
9. Utilisation des conseils de jointure
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
SELECT
sod.SalesOrderDetailID
,sod.ProductID
,P.Name
,P.ProductNumber
,sod.OrderQty
FROM Sales.SalesOrderDetail sod
INNER HASH JOIN Production.Product p ON sod.ProductID = p.ProductID
WHERE P.ProductSubcategoryID IN(25, 31, 33);
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
SELECT
soh.SalesOrderID
,soh.OrderDate
,sod.SalesOrderDetailID
,sod.ProductID
,sod.LineTotal
FROM Sales.SalesOrderHeader soh
INNER LOOP JOIN sales.SalesOrderDetail sod ON soh.SalesOrderID = sod.SalesOrderID
10. Utiliser INNER JOIN dans UPDATE
UPDATE Sales.SalesOrderHeader
SET ShipDate = getdate()
FROM Sales.SalesOrderHeader o
INNER JOIN Sales.Customer c on o.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE p.PersonType = 'SC'
Partage SQL Join et INNER JOIN
Voir aussi