【问题标题】:LEFT JOIN but with WHERE criteria, rows getting lostLEFT JOIN 但使用 WHERE 条件,行丢失
【发布时间】:2014-11-03 20:21:51
【问题描述】:

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

表 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、酒吧、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,富,1
2、酒吧、空
3、阿尔法、空
4、测试版、空

我有第二个用户 (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、酒吧、1
3、Alpha、Null
4、Beta、Null

【问题讨论】:

  • 这是 mysql 还是 SQL-server?请仅命名适当的名称
  • 对不起 - 只是 mysql。无意中选择了sql-server。
  • 您应该加入 users 表以指定用户
  • 谢谢,约翰。我就是这么想的。有关如何编写查询的任何建议?
  • 哀悼!照顾好自己和家人!

标签: mysql database left-join


【解决方案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 子句转换为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 列详细信息值。这需要另一个连接,使用pick_id 的 MAX 值,就像这样

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

一些开发人员更喜欢为像这里这样的子查询创建VIEW 对象,而不是创建像这样的查询的俱乐部三明治。它不是一时兴起的结构化查询语言,对吧?这些子查询有时可以是结构的元素。

【讨论】:

  • StackOverflowians 再次救援!感谢您的出色回答,奥利。这就像一个魅力。我感谢您的帮助。 JL
  • Ollie - 对此进行快速跟进...在选择表中,用户可以选择或取消选择一个条目(在此活动发生时观看此活动非常有帮助)。然而,这意味着对于一个特定的应用程序(比如 application_id = 1),您可能有 3 票:select-unselect-select。使用您提出的后一个查询(效果很好),我现在得到了 application_id = 1 的三行。您认为仅显示最新选择的最简单方法是什么?我尝试使用 LIMIT 但无法弄清楚。感谢您的帮助!
  • Jean-Luc,您的意思是您将三个新行插入picks 以进行选择-取消选择-选择操作?如果是这样,您将需要具有最大 `id 值的那个。
  • 奥利 - 你就是那个男人。严重地。我试图自己解决这个问题(通过无数的 stackoverflow 线程进行梳理)并且永远无法理解如何在子查询中使用 MAX 和 GROUP BY。非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多