标题可能有点令人困惑,让我解释一下,;) 我有3张桌子:
[names]
n_id;name
1;Jeff
2;Adam
[books]
b_id;title
1;Book1
2;Book2
[read]
n_id;b_id
表格[读取]是一本包含阅读书籍的表格。 如果Adam读“Book1”,[read]中的项目如下所示:
2;1
到目前为止,这么好。
现在,有没有办法知道一个人没有读过哪些书?
我们知道只有亚当读了一本书“Book1”,所以查询应该输出这样的东西:
n_id;name;b_id;title
1;Jeff;1;Book1
1;Jeff;2;Book2
2;Adam;2;Book2
是否可以在1个查询中执行此操作,还是需要一些脚本?
答案 0 :(得分:2)
您可以使用CROSS JOIN
获取names
和books
的所有可能组合,然后使用read
IS NULL
LEFT JOIN
NULL
删除那里存在的行。
r.n_id IS NULL
为没有行的所有已加入列返回read
,因此请检查SELECT n.n_id, n.name, b.b_id, b.title
FROM names n
CROSS JOIN books b
LEFT JOIN read r ON ( r.n_id = n.n_id AND r.b_id = b.b_id )
WHERE r.n_id IS NULL
是否删除了{{1}}中连接实际找到行的那些行。
{{1}}
答案 1 :(得分:1)
您需要一个交叉联接来生成所有name
vs book
对,然后加入read
表并检查加入失败的位置。
SELECT names.n_id, names.name, books.b_id, books.title
FROM names
CROSS JOIN books
LEFT JOIN read
ON names.n_id = read.n_id AND books.b_id = read.b_id
WHERE read.n_id IS NULL
答案 2 :(得分:1)
您可以在名称和书籍之间进行笛卡尔联接以获取所有可能的名称/书籍组合,然后减去已阅读的名称/书籍组合:
SELECT n_id, b_id
FROM names, books
MINUS
SELECT n_id, b_id
FROM read
其他人建议进行交叉连接和左连接,这也可以很好地工作。可能想要尝试两者看看哪个在现实场景中更快 - 我怀疑左边加入其他建议会更快,但不是很确定。
答案 3 :(得分:0)
你的问题是,“有没有办法知道一个的人没看过哪些书?”但是你的样本查询结果显示了问题的答案,“有没有办法知道所有人都没有读过哪些书?”
如果你真的只想为特定的人运行查询,那么这样的事情应该有效:
SELECT b_id, title
FROM books --You said you're just looking for books
WHERE b_id NOT IN
(SELECT b_id
FROM read
WHERE n_id = @names_id) --pass in the names_id as a parameter