J'ai deux tables liées par une autre (plusieurs à plusieurs)
Ceci est un extrait de schéma:
CREATE TABLE user (
user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE
);
CREATE TABLE alias (
alias_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
address TEXT NOT NULL UNIQUE
);
CREATE TABLE alias_member (
alias_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
PRIMARY KEY(alias_id, user_id),
FOREIGN KEY(alias_id) REFERENCES alias(alias_id) ON DELETE CASCADE,
FOREIGN KEY(user_id) REFERENCES user(user_id) ON DELETE CASCADE
);
J'ai cette requête qui répond à mes besoins:
SELECT email
FROM
user,
alias,
alias_member
WHERE
user.user_id = alias_member.user_id
AND alias.alias_id = alias_member.alias_id
AND alias.address = '[email protected]';
Un ami m'a suggéré une autre requête qui fonctionne aussi mais je ne l'ai pas:
SELECT
email
FROM
user
INNER JOIN
(alias INNER JOIN alias_member ON alias.alias_id = alias_member.alias_id) ON user.user_id = alias_member.user_id
WHERE address='[email protected]';
Quelqu'un pourrait-il l'expliquer pour moi?
Votre version utilise une très ancienne syntaxe JOIN
des normes ANSI-89 - comme en 1989. En 1992, la norme a été mise à jour pour adopter le JOIN...ON
syntaxe. Vous pouvez lire sur les différences et leur adoption dans cette question SO .
Le problème avec la liste des tables dans un FROM
puis la liste des conditions dans le WHERE
est qu'il est très facile d'oublier une condition quelque part. Comment serait-il facile d'écrire accidentellement:
SELECT email
FROM
user,
alias,
alias_member
WHERE
user.user_id = alias_member.user_id
AND alias.address = '[email protected]';
Maintenant, la version de votre ami utilise également une convention bizarre (la "nested" JOIN
). Ici, il essaie de vous aider avec le fait que vous avez alias_member
comme dernière table dans JOIN
, mais nécessaire pour connecter les 2 autres tables. Si alias_member
est le premier tableau, la syntaxe devient un peu plus claire:
SELECT
email
FROM
alias_member
INNER JOIN
user
ON alias_member.user_id = user.user_id
INNER JOIN
alias
ON alias_member.alias_id = alias.alias_id
WHERE address='[email protected]';
Ce n'est pas réellement une autre requête - c'est une réécriture de la requête existante, pour la rendre plus explicite ce qui se passe.
Votre clause FROM
d'origine, avec une liste de trois tables séparées par des virgules, est en fait un INNER JOIN
des trois tables, avec les critères de JOIN
spécifiés dans la clause WHERE
. Il est généralement considéré comme un meilleur codage pour rendre vos JOIN
s explicites et pour inclure les critères des JOIN
s dans la clause ON de la jointure. Cela permet de comprendre plus facilement comment les tables sont censées s'emboîter.
Le seul critère qui n'est pas spécifique à un JOIN
est laissé dans la clause WHERE
. Cela ne limite pas les données en fonction de la façon dont les différentes tables sont liées, mais en fonction de la correspondance d'un champ dans une table, quelle que soit la relation.