LEFT JOIN但是使用WHERE标准,行会丢失

时间:2014-11-02 20:25:13

标签: mysql database left-join

我有一个包含三个表的简单数据库。在数据库中,我有一个用于我的系统用户的表,一个用于竞赛的应用程序的表,以及一个允许我跟踪哪些用户选择了哪些应用程序来查看的中间表。

表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

1 个答案:

答案 0 :(得分:1)

您的数据库架构中有一个所谓的连接表。在你的情况下,它被称为picks。这样,您就可以在usersapplications之间创建多对多关系。

要正确使用该连接表,您需要连接所有三个表。如果使用表别名(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操作将保留应用程序行,您将看到picksusers表中列的NULL值。

现在,如果您为此查询添加WHERE p.something = somethingu.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 个对象,而不是创建像这样的查询的俱乐部三明治。在愚蠢的奇思妙想中,它不被称为结构化查询语言,是吗?这些子查询有时可以是结构的元素。