我有一个包含三个表的简单数据库。在数据库中,我有一个用于我的系统用户的表,一个用于竞赛的应用程序的表,以及一个允许我跟踪哪些用户选择了哪些应用程序来查看的中间表。
表1 =用户(user_id,用户名,第一个,最后一个等等)
表2 =应用程序(application_id,company_name,url等...)
表3 =选择(pick_id,user_id,application_id,pick)
我正在尝试编写一个SQL查询,该查询将显示已提交的所有应用程序,如果用户选择了任何单个应用程序,则会显示已被“选中”(1 =已选中,0 =未选中) )。
所以对于user_id = 1,我想看看:
列名(application_id,company_name,pick)
1,Foo,1
2,Bar,1
3,Alpha,Null
4,Beta,Null
我使用以下查询尝试了它:
SELECT applications.application_id, applications.company_name, picks.picked
FROM applications
LEFT JOIN picks ON applications.application_id = picks.application_id
ORDER BY applications.application_id ASC
返回此内容:
1,Foo,1
1,Foo,1
2,Bar,null
3,Alpha,null
4,Beta,null
我有第二个用户(user_id = 2)也选择了应用程序1(“Foo”),我知道它正在返回第二行。
然后我尝试通过在此处指定user_id = 1来限制范围:
SELECT applications.application_id, applications.company_name, picks.picked
FROM applications
LEFT JOIN picks ON applications.application_id = picks.application_id
WHERE user_id = 1
ORDER BY applications.application_id ASC
现在我只得到:
1,Foo,1
有关如何获得我正在寻找的内容的任何建议?同样,理想情况下,我希望看到一个用户:
列名(application_id,company_name,pick)
1,Foo,1
2,Bar,1
3,Alpha,Null
4,Beta,Null
答案 0 :(得分:1)
您的数据库架构中有一个所谓的连接表。在你的情况下,它被称为picks
。这样,您就可以在users
和applications
之间创建多对多关系。
要正确使用该连接表,您需要连接所有三个表。如果使用表别名(applications AS a
等)
SELECT a.application_id, a.company_name, p.picked, u.user_id, u.username
FROM applications AS a
LEFT JOIN picks AS p ON a.application_id = p.application_id
LEFT JOIN users AS u ON p.user_id = u.user_id
ORDER BY a.application_id, u.user_id
这将为您提供制作它们的用户的所有应用程序的列表。如果没有用户与应用程序相关,LEFT JOIN
操作将保留应用程序行,您将看到picks
和users
表中列的NULL值。
现在,如果您为此查询添加WHERE p.something = something
或u.something = something
子句以尝试缩小演示文稿范围,则可以将LEFT JOIN
子句转换为{{1条款。也就是说,您不会保留其他表中没有匹配行的INNER JOIN
行。
如果要在结果集中保留那些不匹配的行,请将条件放在第一个applications
子句而不是ON
子句中,如下所示。
WHERE
编辑您的SELECT a.application_id, a.company_name, p.picked, u.user_id, u.username
FROM applications AS a
LEFT JOIN picks AS p ON a.application_id = p.application_id AND p.user_id = 1
LEFT JOIN users AS u ON p.user_id = u.user_id
ORDER BY a.application_id, u.user_id
表格中的许多连接表都使用复合主键设置,在您的示例picks
中。这确保了正在连接的表之间每个可能关系只有一行。在您的情况下,您可能会有多个此类行。
仅使用最新的行((application_id, user_id)
最高的行)需要更多的工作。您需要一个子查询(虚拟表)来提取它,并检索pick_id
的适当值,以便查询起作用。所以现在事情变得有趣了。
picked
检索唯一关系对。那很好。但接下来我们必须从这些行中获取SELECT MAX(pick_id) AS pick_id,
application_id, user_id
FROM picks
GROUP BY application_id, user_id
列详细信息值。这需要另一个连接,使用picked
的MAX值,就像这样
pick_id
因此,我们需要用这个小虚拟表(子查询)代替原始查询中的SELECT q.application_id, q.user_id, r.picked
FROM (
SELECT MAX(pick_id) AS pick_id,
application_id, user_id
FROM picks
GROUP BY application_id, user_id
) AS q
JOIN picks AS r ON q.pick_id = r.pick_id
表。看起来像这样。
pick AS p
有些开发人员喜欢为像这里的子查询创建SELECT a.application_id, a.company_name, p.picked, u.user_id, u.username
FROM applications AS a
LEFT JOIN (
SELECT q.application_id, q.user_id, r.picked
FROM (
SELECT MAX(pick_id) AS pick_id,
application_id, user_id
FROM picks
GROUP BY application_id, user_id
) AS q
JOIN picks AS r ON q.pick_id = r.pick_id
) AS p ON a.application_id = p.application_id AND p.user_id = 1
LEFT JOIN users AS u ON p.user_id = u.user_id
ORDER BY a.application_id, u.user_id
个对象,而不是创建像这样的查询的俱乐部三明治。在愚蠢的奇思妙想中,它不被称为结构化查询语言,是吗?这些子查询有时可以是结构的元素。