【问题标题】:Return only one row from the right-most table for every row in the left-most table对于最左侧表中的每一行,仅返回最右侧表中的一行
【发布时间】:2011-03-19 19:43:59
【问题描述】:

我有两张桌子。我想以这样一种方式加入它们,即最左边表中的每条记录只返回右表中的一条记录。我在下面提供了一个示例。我想避免子查询和临时表,因为实际数据约为 4M 行。我也不关心最右边表中的哪条记录匹配,只要匹配一个或没有匹配。谢谢!

表用户:

-------------
| id | name |
-------------
| 1  | mike |
| 2  | john |
| 3  | bill |
-------------

表交易:

---------------
| uid | spent | 
---------------
| 1   | 5.00  |
| 1   | 5.00  |
| 2   | 5.00  |
| 3   | 5.00  |
| 3   | 10.00 |
---------------

预期输出:

---------------------
| id | name | spent |
---------------------
| 1  | mike | 5.00  |
| 2  | john | 5.00  |
| 3  | bill | 5.00  |
---------------------

【问题讨论】:

  • 为什么每个人都按 user.id(主键)和 user.name 分组?按主键分组后,您真的不需要其他任何东西。是我遗漏了什么,还是我们都只是抄袭@OMG Ponies?
  • @TheJacobTaylor:标准 SQL 要求您在 GROUP BY 中包含未包装在聚合中的列。如果涉及到不必要的子分组,ANSI 标准不支持定义所有列 - MySQL 支持这一点,但它不适用于大多数其他数据库。
  • @TheJacobTaylor:MySQL 不需要所有的分组列;几乎所有其他 DBMS 都这样做,SQL 标准也是如此。
  • 太好了,谢谢!这是我倾向于尝试运行、阅读错误、拍前额、调整查询并再次运行的事情之一。

标签: sql mysql join


【解决方案1】:

用途:

  SELECT u.id,
         u.name,
         MIN(t.spent) AS spent
    FROM USERS u
    JOIN TRANSACTIONS t ON t.uid = u.id
GROUP BY u.id, u.name

请注意,这只会返回至少有一个 TRANSACTIONS 记录的用户。如果您想查看没有支持记录的用户以及有支持记录的用户,请使用:

   SELECT u.id,
          u.name,
          COALESCE(MIN(t.spent), 0) AS spent
     FROM USERS u
LEFT JOIN TRANSACTIONS t ON t.uid = u.id
 GROUP BY u.id, u.name

【讨论】:

  • 啊!当然。有时我变得如此短视。撇开一个问题不谈,在早期版本的 MySQL 中不是有一个 JOIN 可以自然地做到这一点吗?
  • 是的,它被称为左连接。 :) 右连接将强制匹配。左连接将包括匹配项,但不需要它们。
  • @Mike Sherov:ANSI-92 有一个自然连接,由MySQL since 3.23 支持,但它只是一个内部连接。不知道你想多早……
  • 我认为这里不需要COALESCE(MIN(t.spent), 0)LEFT JOIN 正在努力“查看没有支持记录的用户以及有支持记录的用户”。 COALESCE 在这里所做的就是将 NULL 值替换为 0 值,这可能有用也可能没有帮助,具体取决于查询的目的。
  • MIN() 聚合方法也适用于文本字段,至少适用于 postgres。
【解决方案2】:

如果您不关心返回的特定行。

select id, name, spent
from users
left join transactions on users.id = transactions.uid
group by id

这将为每个用户返回一行。这将是第一个匹配的交易。

【讨论】:

    【解决方案3】:

    如果这并不能真正回答您的问题,我深表歉意。看起来您正在尝试查看哪些用户至少有一笔交易。您可以这样做,并在此过程中通过执行以下操作查看每个用户花费了多少:

    选择 u.id, 你的名字, SUM(t.spent) AS 总计 从 用户 内部联接交易 ON t.uid = u.id 通过...分组 u.id , 你的名字

    【讨论】:

    • 他们在问题中明确指出,匹配或不匹配都可以。
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 2012-06-19
    • 2021-12-12
    • 2020-04-27
    相关资源
    最近更新 更多