需要解释多对多关系的 SELECT 查询

one*_*ree 5 sqlite

我有两个通过另一个(多对多)相关的表

这是模式摘录:

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
);
Run Code Online (Sandbox Code Playgroud)

我有一个满足我需求的查询:

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 = 'foo@domain.tld';
Run Code Online (Sandbox Code Playgroud)

一位朋友向我建议了另一个也有效的查询,但我不明白:

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='foo@domain.tld';
Run Code Online (Sandbox Code Playgroud)

有人会为我解释一下吗?

Ste*_*ble 7

您的版本使用ANSI-89 标准中非常古老的语法 - 就像 1989 年一样。1992 年,该标准进行了更新以采用该语法。您可以在这个SO 问题中了解差异及其采用情况。JOINJOIN...ON

在 a 中列出表FROM,然后在 a 中列出条件的问题WHERE是很容易忘记某处的条件。不小心写下是多么容易:

SELECT email
FROM
    user,
    alias,
    alias_member
WHERE 
    user.user_id = alias_member.user_id
    AND alias.address = 'foo@domain.tld';
Run Code Online (Sandbox Code Playgroud)

现在,您朋友的版本还使用了一种奇怪的约定(“嵌套” JOIN)。在这里,它试图帮助您解决以下问题:您拥有alias_member中的最后一个表JOIN,但需要连接其他两个表。如果alias_member是第一个表,语法会变得更清晰一些:

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='foo@domain.tld';
Run Code Online (Sandbox Code Playgroud)