web-dev-qa-db-fra.com

Besoin d'explication SELECT requête sur plusieurs à plusieurs relation

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?

5
oneohthree

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]';
4
Steven Hibble

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 JOINs explicites et pour inclure les critères des JOINs 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.

2
RDFozz