Join (SQL) - Join (SQL)
Une clause de jointure en SQL - correspondant à une opération de jointure en algèbre relationnelle - combine les colonnes d'une ou plusieurs tables dans une nouvelle table. ANSI -STANDARD SQL cinq types de JOIN
: INNER
, LEFT OUTER
, RIGHT OUTER
, FULL OUTER
et CROSS
.
Exemples de tableaux
Pour expliquer les types de jointure, le reste de cet article utilise les tableaux suivants :
Nom de famille | ID de département |
---|---|
Rafferty | 31 |
Jones | 33 |
Heisenberg | 33 |
Robinson | 34 |
Forgeron | 34 |
Williams |
NULL
|
ID de département | Nom du département |
---|---|
31 | Ventes |
33 | Ingénierie |
34 | Clérical |
35 | Commercialisation |
Department.DepartmentID
est la clé primaire de la Department
table, alors qu'il Employee.DepartmentID
s'agit d'une clé étrangère .
Notez que dans Employee
, "Williams" n'a pas encore été affecté à un département. De plus, aucun employé n'a été affecté au département "Marketing".
Voici l'instruction SQL pour créer les tables ci-dessus :
CREATE TABLE department(
DepartmentID INT PRIMARY KEY NOT NULL,
DepartmentName VARCHAR(20)
);
CREATE TABLE employee (
LastName VARCHAR(20),
DepartmentID INT REFERENCES department(DepartmentID)
);
INSERT INTO department
VALUES (31, 'Sales'),
(33, 'Engineering'),
(34, 'Clerical'),
(35, 'Marketing');
INSERT INTO employee
VALUES ('Rafferty', 31),
('Jones', 33),
('Heisenberg', 33),
('Robinson', 34),
('Smith', 34),
('Williams', NULL);
Jointure croisée
CROSS JOIN
renvoie le produit cartésien des lignes des tables de la jointure. En d'autres termes, il produira des lignes qui combinent chaque ligne du premier tableau avec chaque ligne du deuxième tableau.
Employé.Nom | Employee.DepartmentID | Département.NomDépartement | Department.DepartmentID |
---|---|---|---|
Rafferty | 31 | Ventes | 31 |
Jones | 33 | Ventes | 31 |
Heisenberg | 33 | Ventes | 31 |
Forgeron | 34 | Ventes | 31 |
Robinson | 34 | Ventes | 31 |
Williams | NULL |
Ventes | 31 |
Rafferty | 31 | Ingénierie | 33 |
Jones | 33 | Ingénierie | 33 |
Heisenberg | 33 | Ingénierie | 33 |
Forgeron | 34 | Ingénierie | 33 |
Robinson | 34 | Ingénierie | 33 |
Williams | NULL |
Ingénierie | 33 |
Rafferty | 31 | Clérical | 34 |
Jones | 33 | Clérical | 34 |
Heisenberg | 33 | Clérical | 34 |
Forgeron | 34 | Clérical | 34 |
Robinson | 34 | Clérical | 34 |
Williams | NULL |
Clérical | 34 |
Rafferty | 31 | Commercialisation | 35 |
Jones | 33 | Commercialisation | 35 |
Heisenberg | 33 | Commercialisation | 35 |
Forgeron | 34 | Commercialisation | 35 |
Robinson | 34 | Commercialisation | 35 |
Williams | NULL |
Commercialisation | 35 |
Exemple de jointure croisée explicite :
SELECT *
FROM employee CROSS JOIN department;
Exemple de jointure croisée implicite :
SELECT *
FROM employee, department;
La jointure croisée peut être remplacée par une jointure interne avec une condition toujours vraie :
SELECT *
FROM employee INNER JOIN department ON 1=1;
CROSS JOIN
n'applique lui-même aucun prédicat pour filtrer les lignes de la table jointe. Les résultats de a CROSS JOIN
peuvent être filtrés à l'aide d'une WHERE
clause, qui peut alors produire l'équivalent d'une jointure interne.
Dans la norme SQL:2011 , les jointures croisées font partie du package facultatif F401, "Table jointe étendue".
Les utilisations normales sont pour vérifier les performances du serveur.
Jointure interne
Une jointure interne nécessite que chaque ligne des deux tables jointes ait des valeurs de colonne correspondantes et est une opération de jointure couramment utilisée dans les applications, mais ne doit pas être considérée comme le meilleur choix dans toutes les situations. La jointure interne crée une nouvelle table de résultats en combinant les valeurs de colonne de deux tables (A et B) en fonction du prédicat de jointure. La requête compare chaque ligne de A avec chaque ligne de B pour trouver toutes les paires de lignes qui satisfont le prédicat de jointure. Lorsque le prédicat de jointure est satisfait en faisant correspondre des valeurs non NULL, les valeurs de colonne pour chaque paire de lignes correspondantes de A et B sont combinées dans une ligne de résultat.
Le résultat de la jointure peut être défini comme le résultat de la première prise du produit cartésien (ou jointure croisée ) de toutes les lignes des tables (combinaison de chaque ligne de la table A avec chaque ligne de la table B), puis du renvoi de toutes les lignes qui satisfont à la joindre le prédicat. Les implémentations SQL réelles utilisent normalement d'autres approches, telles que les jointures de hachage ou les jointures de tri-fusion , car le calcul du produit cartésien est plus lent et nécessiterait souvent une quantité de mémoire prohibitive à stocker.
SQL spécifie deux manières syntaxiques différentes d'exprimer les jointures : la "notation de jointure explicite" et la "notation de jointure implicite". La "notation de jointure implicite" n'est plus considérée comme une bonne pratique, bien que les systèmes de base de données la prennent toujours en charge.
La "notation de jointure explicite" utilise le JOIN
mot - clé, éventuellement précédé du INNER
mot - clé, pour spécifier la table à joindre, et le ON
mot - clé pour spécifier les prédicats de la jointure, comme dans l'exemple suivant :
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee
INNER JOIN department ON
employee.DepartmentID = department.DepartmentID;
Employé.Nom | Employee.DepartmentID | Département.NomDépartement |
---|---|---|
Robinson | 34 | Clérical |
Jones | 33 | Ingénierie |
Forgeron | 34 | Clérical |
Heisenberg | 33 | Ingénierie |
Rafferty | 31 | Ventes |
La "notation de jointure implicite" répertorie simplement les tables à joindre, dans la FROM
clause de l' SELECT
instruction, en utilisant des virgules pour les séparer. Ainsi, il spécifie une jointure croisée et la WHERE
clause peut appliquer des prédicats de filtre supplémentaires (qui fonctionnent de manière comparable aux prédicats de jointure dans la notation explicite).
L'exemple suivant est équivalent au précédent, mais cette fois en notation de jointure implicite :
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID;
Les requêtes données dans les exemples ci-dessus joindront les tables Employee et Department à l'aide de la colonne DepartmentID des deux tables. Lorsque le DepartmentID de ces tables correspond (c'est-à-dire que le prédicat de jointure est satisfait), la requête combinera les colonnes LastName , DepartmentID et DepartmentName des deux tables dans une ligne de résultat. Lorsque le DepartmentID ne correspond pas, aucune ligne de résultat n'est générée.
Ainsi le résultat de l' exécution de la requête ci-dessus sera :
Employé.Nom | Employee.DepartmentID | Département.NomDépartement |
---|---|---|
Robinson | 34 | Clérical |
Jones | 33 | Ingénierie |
Forgeron | 34 | Clérical |
Heisenberg | 33 | Ingénierie |
Rafferty | 31 | Ventes |
L'employé "Williams" et le département "Marketing" n'apparaissent pas dans les résultats d'exécution de la requête. Ni l'un ni l'autre n'a de ligne correspondante dans l'autre tableau respectif : « Williams » n'a aucun service associé et aucun employé n'a l'ID de service 35 (« Marketing »). Selon les résultats souhaités, ce comportement peut être un bogue subtil, qui peut être évité en remplaçant la jointure interne par une jointure externe .
Jointure interne et valeurs NULL
Les programmeurs doivent faire particulièrement attention lorsqu'ils joignent des tables sur des colonnes pouvant contenir des valeurs NULL , car NULL ne correspondra à aucune autre valeur (pas même NULL elle-même), à moins que la condition de jointure utilise explicitement un prédicat de combinaison qui vérifie d'abord que les colonnes jointes sont NOT NULL
avant d'appliquer la ou les conditions de prédicat restantes. La jointure interne ne peut être utilisée en toute sécurité que dans une base de données qui applique l' intégrité référentielle ou où les colonnes de jointure sont garanties de ne pas être NULL. De nombreuses bases de données relationnelles de traitement des transactions reposent sur les normes de mise à jour des données Atomity, Cohérence, Isolation, Durabilité (ACID) pour garantir l'intégrité des données, faisant des jointures internes un choix approprié. Cependant, les bases de données de transaction ont généralement également des colonnes de jointure souhaitables autorisées à être NULL. De nombreux entrepôts de données et de bases de données relationnelles de reporting utilisent des mises à jour par lots d' extraction, de transformation, de chargement (ETL) à grand volume qui rendent l'intégrité référentielle difficile ou impossible à appliquer, ce qui entraîne des colonnes de jointure potentiellement NULL qu'un auteur de requête SQL ne peut pas modifier et qui entraînent l'omission des jointures internes données sans indication d'erreur. Le choix d'utiliser une jointure interne dépend de la conception de la base de données et des caractéristiques des données. Une jointure externe gauche peut généralement être remplacée par une jointure interne lorsque les colonnes de jointure d'une table peuvent contenir des valeurs NULL.
Toute colonne de données pouvant être NULL (vide) ne doit jamais être utilisée comme lien dans une jointure interne, sauf si le résultat souhaité est d'éliminer les lignes avec la valeur NULL. Si les colonnes de jointure NULL doivent être délibérément supprimées du jeu de résultats , une jointure interne peut être plus rapide qu'une jointure externe car la jointure de table et le filtrage sont effectués en une seule étape. À l'inverse, une jointure interne peut entraîner un ralentissement désastreux des performances ou même un blocage du serveur lorsqu'elle est utilisée dans une requête de grand volume en combinaison avec des fonctions de base de données dans une clause SQL Where. Une fonction dans une clause SQL Where peut faire en sorte que la base de données ignore les index de table relativement compacts. La base de données peut lire et joindre les colonnes sélectionnées des deux tables avant de réduire le nombre de lignes à l'aide du filtre qui dépend d'une valeur calculée, ce qui entraîne une quantité relativement énorme de traitement inefficace.
Lorsqu'un ensemble de résultats est produit en joignant plusieurs tables, y compris les tables principales utilisées pour rechercher des descriptions en texte intégral de codes d'identification numériques (une table de recherche ), une valeur NULL dans l'une des clés étrangères peut entraîner l'élimination de la ligne entière à partir du jeu de résultats, sans indication d'erreur. Une requête SQL complexe qui inclut une ou plusieurs jointures internes et plusieurs jointures externes présente le même risque de valeurs NULL dans les colonnes de lien de jointure interne.
Un engagement envers le code SQL contenant des jointures internes suppose que les colonnes de jointure NULL ne seront pas introduites par les modifications futures, y compris les mises à jour des fournisseurs, les modifications de conception et le traitement en masse en dehors des règles de validation des données de l'application telles que les conversions de données, les migrations, les importations en masse et les fusions.
On peut en outre classer les jointures internes en équi-jointures, en jointures naturelles ou en jointures croisées.
Equi-joindre
Une équi-jointure est un type spécifique de jointure basée sur un comparateur, qui utilise uniquement des comparaisons d' égalité dans le prédicat de jointure. L'utilisation d'autres opérateurs de comparaison (tels que <
) disqualifie une jointure en tant qu'équi-jointure. La requête ci-dessus a déjà fourni un exemple d'équi-jointure :
SELECT *
FROM employee JOIN department
ON employee.DepartmentID = department.DepartmentID;
Nous pouvons écrire équi-jointure comme ci-dessous,
SELECT *
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID;
Si les colonnes d'une équi-jointure ont le même nom, SQL-92 fournit une notation abrégée facultative pour exprimer les équi-jointures, au moyen de la USING
construction :
SELECT *
FROM employee INNER JOIN department USING (DepartmentID);
La USING
construction est plus qu'un simple sucre syntaxique , cependant, puisque l'ensemble de résultats diffère de l'ensemble de résultats de la version avec le prédicat explicite. Plus précisément, toutes les colonnes mentionnées dans la USING
liste n'apparaîtront qu'une seule fois, avec un nom non qualifié, plutôt qu'une seule fois pour chaque table de la jointure. Dans le cas ci-dessus, il y aura une seule DepartmentID
colonne et non employee.DepartmentID
ou department.DepartmentID
.
La USING
clause n'est pas prise en charge par MS SQL Server et Sybase.
Jointure naturelle
La jointure naturelle est un cas particulier d'équi-jointure. La jointure naturelle (⋈) est un opérateur binaire qui s'écrit ( R ⋈ S ) où R et S sont des relations . Le résultat de la jointure naturelle est l'ensemble de toutes les combinaisons de tuples dans R et S qui sont égales sur leurs noms d'attributs communs. Par exemple, considérons les tables Employee et Dept et leur jointure naturelle :
|
|
|
Cela peut également être utilisé pour définir la composition des relations . Par exemple, la composition de Employee et Dept est leur jointure comme indiqué ci-dessus, projetée sur tout sauf l'attribut commun DeptName . Dans la théorie des catégories , la jointure est précisément le produit de la fibre .
La jointure naturelle est sans doute l'un des opérateurs les plus importants puisqu'elle est la contrepartie relationnelle du ET logique. Notez que si la même variable apparaît dans chacun des deux prédicats qui sont connectés par AND, alors cette variable représente la même chose et les deux apparences doivent toujours être remplacées par la même valeur. En particulier, la jointure naturelle permet la combinaison de relations qui sont associées par une clé étrangère . Par exemple, dans l'exemple ci-dessus, une clé étrangère contient probablement de Employee . DeptName à Dept . DeptName , puis la jointure naturelle de Employee et Dept combine tous les employés avec leurs départements. Cela fonctionne car la clé étrangère est conservée entre des attributs portant le même nom. Si ce n'est pas le cas comme dans la clé étrangère de Dept . gestionnaire à l' employé . Name puis ces colonnes doivent être renommées avant que la jointure naturelle ne soit prise. Une telle jointure est parfois également appelée équi-jointure .
Plus formellement, la sémantique de la jointure naturelle est définie comme suit :
- ,
où Fun est un prédicat qui est vrai pour une relation r si et seulement si r est une fonction. Il est généralement exigé que R et S aient au moins un attribut commun, mais si cette contrainte est omise et que R et S n'ont pas d'attributs communs, alors la jointure naturelle devient exactement le produit cartésien.
La jointure naturelle peut être simulée avec les primitives de Codd comme suit. Soit c 1 , …, c m les noms d'attributs communs à R et S , r 1 , …, r n les noms d'attributs uniques à R et soit s 1 , …, s k les attributs uniques à S . De plus, supposons que les noms d'attributs x 1 , …, x m ne sont ni dans R ni dans S . Dans un premier temps, les noms d'attributs communs dans S peuvent maintenant être renommés :
Ensuite, nous prenons le produit cartésien et sélectionnons les tuples à joindre :
Une jointure naturelle est un type d'équi-jointure où le prédicat de jointure apparaît implicitement en comparant toutes les colonnes des deux tables qui ont les mêmes noms de colonnes dans les tables jointes. La table jointe résultante contient une seule colonne pour chaque paire de colonnes portant le même nom. Dans le cas où aucune colonne portant le même nom n'est trouvée, le résultat est une jointure croisée .
La plupart des experts s'accordent à dire que les NATURAL JOIN sont dangereux et déconseillent donc fortement leur utilisation. Le danger vient de l'ajout par inadvertance d'une nouvelle colonne, nommée de la même manière qu'une autre colonne dans l'autre table. Une jointure naturelle existante peut alors "naturellement" utiliser la nouvelle colonne pour les comparaisons, en effectuant des comparaisons/correspondances en utilisant des critères différents (de différentes colonnes) qu'auparavant. Ainsi, une requête existante pourrait produire des résultats différents, même si les données des tables n'ont pas été modifiées, mais seulement augmentées. L'utilisation de noms de colonnes pour déterminer automatiquement les liens de table n'est pas une option dans les grandes bases de données avec des centaines ou des milliers de tables où elle placerait une contrainte irréaliste sur les conventions de nommage. Les bases de données du monde réel sont généralement conçues avec des données de clé étrangère qui ne sont pas renseignées de manière cohérente (les valeurs NULL sont autorisées), en raison des règles métier et du contexte. Il est courant de modifier les noms de colonnes de données similaires dans différentes tables et ce manque de cohérence rigide relègue les jointures naturelles à un concept théorique de discussion.
L'exemple de requête ci-dessus pour les jointures internes peut être exprimé comme une jointure naturelle de la manière suivante :
SELECT *
FROM employee NATURAL JOIN department;
Comme pour la USING
clause explicite , une seule colonne DepartmentID apparaît dans la table jointe, sans qualificateur :
ID de département | Employé.Nom | Département.NomDépartement |
---|---|---|
34 | Forgeron | Clérical |
33 | Jones | Ingénierie |
34 | Robinson | Clérical |
33 | Heisenberg | Ingénierie |
31 | Rafferty | Ventes |
PostgreSQL, MySQL et Oracle prennent en charge les jointures naturelles ; Microsoft T-SQL et IBM DB2 ne le font pas. Les colonnes utilisées dans la jointure sont implicites, le code de jointure n'indique donc pas quelles colonnes sont attendues et une modification des noms de colonnes peut modifier les résultats. Dans la norme SQL:2011 , les jointures naturelles font partie du package facultatif F401, "Table jointe étendue".
Dans de nombreux environnements de bases de données, les noms de colonnes sont contrôlés par un fournisseur externe, et non par le développeur de requêtes. Une jointure naturelle suppose la stabilité et la cohérence des noms de colonnes qui peuvent changer lors des mises à niveau de version mandatées par le fournisseur.
Jointure externe
La table jointe conserve chaque ligne, même si aucune autre ligne correspondante n'existe. Les jointures externes se subdivisent en jointures externes gauches, jointures externes droites et jointures externes complètes, selon les lignes de la table retenues : gauche, droite ou les deux (dans ce cas, gauche et droite font référence aux deux côtés du JOIN
mot - clé). Comme les jointures internes , on peut en outre sous-catégoriser tous les types de jointures externes en équi-jointures , jointures naturelles , ( θ -join ), etc.
ON <predicate>
Aucune notation de jointure implicite pour les jointures externes n'existe dans le SQL standard.
Jointure externe gauche
Le résultat d'une jointure externe gauche (ou simplement jointure gauche ) pour les tables A et B contient toujours toutes les lignes de la table "gauche" (A), même si la condition de jointure ne trouve aucune ligne correspondante dans la table "droite" (B). Cela signifie que si la ON
clause correspond à 0 (zéro) ligne dans B (pour une ligne donnée dans A), la jointure renverra toujours une ligne dans le résultat (pour cette ligne) - mais avec NULL dans chaque colonne de B. A à gauche la jointure externe renvoie toutes les valeurs d'une jointure interne plus toutes les valeurs de la table de gauche qui ne correspondent pas à la table de droite, y compris les lignes avec des valeurs NULL (vides) dans la colonne de lien.
Par exemple, cela nous permet de trouver le service d'un employé, mais affiche toujours les employés qui n'ont pas été affectés à un service (contrairement à l'exemple de jointure interne ci-dessus, où les employés non affectés ont été exclus du résultat).
Exemple de jointure externe gauche (le OUTER
mot-clé est facultatif), avec la ligne de résultat supplémentaire (par rapport à la jointure interne) en italique :
SELECT *
FROM employee
LEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID;
Employé.Nom | Employee.DepartmentID | Département.NomDépartement | Department.DepartmentID |
---|---|---|---|
Jones | 33 | Ingénierie | 33 |
Rafferty | 31 | Ventes | 31 |
Robinson | 34 | Clérical | 34 |
Forgeron | 34 | Clérical | 34 |
Williams | NULL |
NULL |
NULL
|
Heisenberg | 33 | Ingénierie | 33 |
Syntaxes alternatives
Oracle prend en charge la syntaxe déconseillée :
SELECT *
FROM employee, department
WHERE employee.DepartmentID = department.DepartmentID(+)
Sybase prend en charge la syntaxe ( Microsoft SQL Server a déprécié cette syntaxe depuis la version 2000) :
SELECT *
FROM employee, department
WHERE employee.DepartmentID *= department.DepartmentID
IBM Informix prend en charge la syntaxe :
SELECT *
FROM employee, OUTER department
WHERE employee.DepartmentID = department.DepartmentID
Jointure externe droite
Une jointure externe droite (ou jointure droite ) ressemble beaucoup à une jointure externe gauche, sauf que le traitement des tables est inversé. Chaque ligne du tableau "de droite" (B) apparaîtra au moins une fois dans le tableau joint. S'il n'existe aucune ligne correspondante de la table "gauche" (A), NULL apparaîtra dans les colonnes de A pour les lignes qui n'ont aucune correspondance dans B.
Une jointure externe droite renvoie toutes les valeurs de la table de droite et les valeurs correspondantes de la table de gauche (NULL en cas d'absence de prédicat de jointure correspondant). Par exemple, cela nous permet de trouver chaque employé et son département, mais toujours d'afficher les départements qui n'ont pas d'employés.
Vous trouverez ci-dessous un exemple de jointure externe droite (le OUTER
mot-clé est facultatif), avec la ligne de résultat supplémentaire en italique :
SELECT *
FROM employee RIGHT OUTER JOIN department
ON employee.DepartmentID = department.DepartmentID;
Employé.Nom | Employee.DepartmentID | Département.NomDépartement | Department.DepartmentID |
---|---|---|---|
Forgeron | 34 | Clérical | 34 |
Jones | 33 | Ingénierie | 33 |
Robinson | 34 | Clérical | 34 |
Heisenberg | 33 | Ingénierie | 33 |
Rafferty | 31 | Ventes | 31 |
NULL |
NULL |
Commercialisation | 35 |
Les jointures externes droite et gauche sont fonctionnellement équivalentes. Ni l'un ni l'autre ne fournit de fonctionnalité que l'autre n'offre, de sorte que les jointures externes droite et gauche peuvent se remplacer tant que l'ordre des tables est inversé.
Jointure externe complète
Conceptuellement, une jointure externe complète combine l'effet de l'application de jointures externes gauche et droite. Lorsque les lignes des tables FULL OUTER JOINed ne correspondent pas, le jeu de résultats aura des valeurs NULL pour chaque colonne de la table qui n'a pas de ligne correspondante. Pour les lignes qui correspondent, une seule ligne sera produite dans l'ensemble de résultats (contenant des colonnes renseignées à partir des deux tables).
Par exemple, cela nous permet de voir chaque employé qui est dans un département et chaque département qui a un employé, mais aussi de voir chaque employé qui ne fait pas partie d'un département et chaque département qui n'a pas d'employé.
Exemple de jointure externe complète (le OUTER
mot-clé est facultatif) :
SELECT *
FROM employee FULL OUTER JOIN department
ON employee.DepartmentID = department.DepartmentID;
Employé.Nom | Employee.DepartmentID | Département.NomDépartement | Department.DepartmentID |
---|---|---|---|
Forgeron | 34 | Clérical | 34 |
Jones | 33 | Ingénierie | 33 |
Robinson | 34 | Clérical | 34 |
Williams | NULL |
NULL |
NULL
|
Heisenberg | 33 | Ingénierie | 33 |
Rafferty | 31 | Ventes | 31 |
NULL |
NULL |
Commercialisation | 35 |
Certains systèmes de base de données ne prennent pas directement en charge la fonctionnalité de jointure externe complète, mais ils peuvent l'émuler grâce à l'utilisation d'une jointure interne et à la sélection par UNION ALL des "lignes de table unique" des tables de gauche et de droite respectivement. Le même exemple peut apparaître comme suit :
SELECT employee.LastName, employee.DepartmentID,
department.DepartmentName, department.DepartmentID
FROM employee
INNER JOIN department ON employee.DepartmentID = department.DepartmentID
UNION ALL
SELECT employee.LastName, employee.DepartmentID,
cast(NULL as varchar(20)), cast(NULL as integer)
FROM employee
WHERE NOT EXISTS (
SELECT * FROM department
WHERE employee.DepartmentID = department.DepartmentID)
UNION ALL
SELECT cast(NULL as varchar(20)), cast(NULL as integer),
department.DepartmentName, department.DepartmentID
FROM department
WHERE NOT EXISTS (
SELECT * FROM employee
WHERE employee.DepartmentID = department.DepartmentID)
Une autre approche pourrait être UNION ALL de la jointure externe gauche et de la jointure externe droite MOINS la jointure interne.
Auto-adhésion
Une auto-jointure consiste à joindre une table à elle-même.
Exemple
S'il y avait deux tables séparées pour les employés et une requête qui demandait des employés dans la première table ayant le même pays que les employés dans la seconde table, une opération de jointure normale pourrait être utilisée pour trouver la table de réponses. Cependant, toutes les informations sur les employés sont contenues dans un seul grand tableau.
Considérons un Employee
tableau modifié tel que le suivant :
ID de l'employé | Nom de famille | Pays | ID de département |
---|---|---|---|
123 | Rafferty | Australie | 31 |
124 | Jones | Australie | 33 |
145 | Heisenberg | Australie | 33 |
201 | Robinson | États Unis | 34 |
305 | Forgeron | Allemagne | 34 |
306 | Williams | Allemagne |
NULL
|
Un exemple de requête de solution pourrait être le suivant :
SELECT F.EmployeeID, F.LastName, S.EmployeeID, S.LastName, F.Country
FROM Employee F INNER JOIN Employee S ON F.Country = S.Country
WHERE F.EmployeeID < S.EmployeeID
ORDER BY F.EmployeeID, S.EmployeeID;
Ce qui entraîne la génération du tableau suivant.
ID de l'employé | Nom de famille | ID de l'employé | Nom de famille | Pays |
---|---|---|---|---|
123 | Rafferty | 124 | Jones | Australie |
123 | Rafferty | 145 | Heisenberg | Australie |
124 | Jones | 145 | Heisenberg | Australie |
305 | Forgeron | 306 | Williams | Allemagne |
Pour cet exemple :
-
F
etS
sont des alias pour les première et deuxième copies de la table des employés. - La condition
F.Country = S.Country
exclut les jumelages entre employés de pays différents. L'exemple de question ne voulait que des paires d'employés dans le même pays. - La condition
F.EmployeeID < S.EmployeeID
exclut les jumelages où leEmployeeID
du premier employé est supérieur ou égal à celuiEmployeeID
du deuxième employé. En d'autres termes, cette condition a pour effet d'exclure les appariements en double et les auto-appariements. Sans cela, le tableau suivant, moins utile, serait généré (le tableau ci-dessous n'affiche que la partie "Allemagne" du résultat) :
ID de l'employé | Nom de famille | ID de l'employé | Nom de famille | Pays |
---|---|---|---|---|
305 | Forgeron | 305 | Forgeron | Allemagne |
305 | Forgeron | 306 | Williams | Allemagne |
306 | Williams | 305 | Forgeron | Allemagne |
306 | Williams | 306 | Williams | Allemagne |
Un seul des deux appariements du milieu est nécessaire pour répondre à la question d'origine, et le plus haut et le plus bas n'ont aucun intérêt dans cet exemple.
Alternatives
L'effet d'une jointure externe peut également être obtenu en utilisant un UNION ALL entre un INNER JOIN et un SELECT des lignes de la table "principale" qui ne remplissent pas la condition de jointure. Par exemple,
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee
LEFT OUTER JOIN department ON employee.DepartmentID = department.DepartmentID;
peut aussi s'écrire comme
SELECT employee.LastName, employee.DepartmentID, department.DepartmentName
FROM employee
INNER JOIN department ON employee.DepartmentID = department.DepartmentID
UNION ALL
SELECT employee.LastName, employee.DepartmentID, cast(NULL as varchar(20))
FROM employee
WHERE NOT EXISTS (
SELECT * FROM department
WHERE employee.DepartmentID = department.DepartmentID)
Mise en œuvre
De nombreux travaux dans les systèmes de bases de données ont visé à une mise en œuvre efficace des jointures, car les systèmes relationnels demandent généralement des jointures, mais rencontrent des difficultés pour optimiser leur exécution efficace. Le problème se pose parce que les jointures internes fonctionnent à la fois de manière commutative et associative . En pratique, cela signifie que l'utilisateur fournit simplement la liste des tables à joindre et les conditions de jointure à utiliser, et le système de base de données a pour tâche de déterminer la manière la plus efficace d'effectuer l'opération. Un optimiseur de requête détermine comment exécuter une requête contenant des jointures. Un optimiseur de requêtes a deux libertés fondamentales :
- Ordre de jointure : étant donné qu'il joint les fonctions de manière commutative et associative, l'ordre dans lequel le système joint les tables ne modifie pas le jeu de résultats final de la requête. Cependant, l'ordre de jointure peut avoir un impact énorme sur le coût de l'opération de jointure, il est donc très important de choisir le meilleur ordre de jointure.
- Méthode de jointure : Étant donné deux tables et une condition de jointure, plusieurs algorithmes peuvent produire le jeu de résultats de la jointure. L'algorithme qui s'exécute le plus efficacement dépend de la taille des tables d'entrée, du nombre de lignes de chaque table qui correspondent à la condition de jointure et des opérations requises par le reste de la requête.
De nombreux algorithmes de jointure traitent leurs entrées différemment. On peut désigner les entrées d'une jointure comme les opérandes de jointure « externe » et « intérieure », ou « gauche » et « droite », respectivement. Dans le cas de boucles imbriquées, par exemple, le système de base de données analysera l'intégralité de la relation interne pour chaque ligne de la relation externe.
On peut classer les plans de requête impliquant des jointures comme suit :
- profond à gauche
- en utilisant une table de base (plutôt qu'une autre jointure) comme opérande interne de chaque jointure dans le plan
- droit-profond
- utiliser une table de base comme opérande externe de chaque jointure dans le plan
- broussailleux
- ni à gauche ni à droite ; les deux entrées d'une jointure peuvent elles-mêmes résulter de jointures
Ces noms dérivent de l'apparence du plan de requête s'il est dessiné sous la forme d'un arbre , avec la relation de jointure externe à gauche et la relation interne à droite (comme l'exige la convention).
Algorithmes de jointure
Il existe trois algorithmes fondamentaux pour effectuer une opération de jointure : la jointure par boucle imbriquée , la jointure par tri-fusion et la jointure par hachage .
Joindre des index
Les join index sont des index de base de données qui facilitent le traitement des requêtes de jointure dans les entrepôts de données : ils sont actuellement (2012) disponibles dans les implémentations par Oracle et Teradata .
Dans l'implémentation Teradata, les colonnes spécifiées, les fonctions d'agrégation sur les colonnes ou les composants des colonnes de date d'une ou plusieurs tables sont spécifiés à l'aide d'une syntaxe similaire à la définition d'une vue de base de données : jusqu'à 64 colonnes/expressions de colonne peuvent être spécifiées dans un seul rejoindre l'index. Facultativement, une colonne qui définit la clé primaire des données composites peut également être spécifiée : sur du matériel parallèle, les valeurs de colonne sont utilisées pour partitionner le contenu de l'index sur plusieurs disques. Lorsque les tables source sont mises à jour de manière interactive par les utilisateurs, le contenu du join index est automatiquement mis à jour. Toute requête dont la clause WHERE spécifie une combinaison de colonnes ou d'expressions de colonnes qui sont un sous-ensemble exact de celles définies dans un join index (une "requête de couverture") entraînera le join index, plutôt que les tables d'origine et leurs index, à consulter lors de l'exécution de la requête.
L'implémentation Oracle se limite à l'utilisation d' index bitmap . Un join index bitmap est utilisé pour les colonnes à faible cardinalité (c'est-à-dire les colonnes contenant moins de 300 valeurs distinctes, selon la documentation Oracle) : il combine les colonnes à faible cardinalité de plusieurs tables liées. L'exemple utilisé par Oracle est celui d'un système d'inventaire, où différents fournisseurs fournissent différentes pièces. Le schéma comporte trois tables liées : deux « tables maîtres », Pièce et Fournisseur, et une « table de détail », Inventaire. La dernière est une table plusieurs-à-plusieurs reliant le fournisseur à la pièce et contient le plus grand nombre de lignes. Chaque pièce a un type de pièce, et chaque fournisseur est basé aux États-Unis et possède une colonne État. Il n'y a pas plus de 60 états+territoires aux États-Unis, et pas plus de 300 types de pièces. L'index de jointure bitmap est défini à l'aide d'une jointure standard à trois tables sur les trois tables ci-dessus et en spécifiant les colonnes Part_Type et Supplier_State pour l'index. Cependant, il est défini sur la table d'inventaire, même si les colonnes Part_Type et Supplier_State sont "empruntées" à Supplier et Part respectivement.
Comme pour Teradata, un join index bitmap Oracle n'est utilisé pour répondre à une requête que lorsque la clause WHERE de la requête spécifie des colonnes limitées à celles qui sont incluses dans le join index.
Joindre directement
Certains systèmes de bases de données permettent à l'utilisateur de forcer le système à lire les tables d'une jointure dans un ordre particulier. Ceci est utilisé lorsque l'optimiseur de jointure choisit de lire les tables dans un ordre inefficace. Par exemple, dans MySQL, la commande STRAIGHT_JOIN
lit les tables exactement dans l'ordre indiqué dans la requête.
Voir également
Les références
Citations
Sources
- Pratt, Phillip J (2005), Un guide de SQL, septième édition , Thomson Course Technology, ISBN 978-0-619-21674-0
- Shah, Nilesh (2005) [2002], Database Systems Using Oracle – A Simplified Guide to SQL and PL/SQL Second Edition (International ed.), Pearson Education International, ISBN 0-13-191180-5
- Yu, Clément T.; Meng, Weiyi (1998), Principes du traitement des requêtes de base de données pour les applications avancées , Morgan Kaufmann, ISBN 978-1-55860-434-6, récupéré le 03-03-2009