我有两个通过另一个(多对多)相关的表
这是模式摘录:
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)
有人会为我解释一下吗?
您的版本使用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)