【问题标题】:MySQL INNER JOIN select only one row from second tableMySQL INNER JOIN 从第二个表中只选择一行
【发布时间】:2012-09-13 14:53:17
【问题描述】:

我有一个users 表和一个payments 表,对于每个有付款的用户,payments 表中可能有多个关联的付款。我想选择所有有付款的用户,但只选择他们最近一次付款。我正在尝试这个 SQL,但我以前从未尝试过嵌套的 SQL 语句,所以我想知道我做错了什么。感谢帮助

SELECT u.* 
FROM users AS u
    INNER JOIN (
        SELECT p.*
        FROM payments AS p
        ORDER BY date DESC
        LIMIT 1
    )
    ON p.user_id = u.id
WHERE u.package = 1

【问题讨论】:

    标签: mysql sql select inner-join


    【解决方案1】:

    您需要有一个子查询来获取每个user ID 的最新日期。

    SELECT  a.*, c.*
    FROM users a 
        INNER JOIN payments c
            ON a.id = c.user_ID
        INNER JOIN
        (
            SELECT user_ID, MAX(date) maxDate
            FROM payments
            GROUP BY user_ID
        ) b ON c.user_ID = b.user_ID AND
                c.date = b.maxDate
    WHERE a.package = 1
    

    【讨论】:

    • @Fluffeh 你有一个很好的答案Part 1 - Joins and Unions。 :) 已收藏!
    • 谢谢伙计,写它只是为了这种情况,用正确的 SQL 弹出一个快速答案,然后建议一个链接到那个怪物深度阅读,以便人们可以理解 建议的代码。计划添加它以进一步扩展它。喜欢的欢迎加入,我真的应该为代码弹出一个小提琴......
    • @JohnWoo 感谢您的回答,效果很好。感谢 Fluffeh 的问答,我会研究一下!
    • 我认为我的答案更简单而且速度更快,因为我只使用了一个内部联接。也许我错了?
    • 有没有办法在没有内部连接的情况下执行此查询?如果没有行匹配,我想从表 c 返回最大值或返回 null。将 JOIN 更改为 LEFT JOIN 显然不起作用。
    【解决方案2】:
    SELECT u.*, p.*
    FROM users AS u
    INNER JOIN payments AS p ON p.id = (
        SELECT id
        FROM payments AS p2
        WHERE p2.user_id = u.id
        ORDER BY date DESC
        LIMIT 1
    )
    

    或者

    SELECT u.*, p.*
    FROM users AS u
    INNER JOIN payments AS p ON p.user_id = u.id
    WHERE NOT EXISTS (
        SELECT 1
        FROM payments AS p2
        WHERE
            p2.user_id = p.user_id AND
            (p2.date > p.date OR (p2.date = p.date AND p2.id > p.id))
    )
    

    这些解决方案比accepted answer 更好,因为它们在使用相同用户和日期进行多次付款时可以正常工作。你可以try on SQL Fiddle

    【讨论】:

    • 这是您使用的好方法。但我对针对一种产品获取一张图片有疑问。一种产品有很多 (4) 张图片,但我只想针对该产品显示一张图片。
    • 你不觉得用起来会很慢吗?因为您正在处理子查询中的每条记录以进行内部连接。经过细微调整后,接受的答案可能是最好的答案。
    • @HameesA.Khan,我还没有检查查询的执行情况。您可能是对的,但公认的解决方案会进行 3 维连接,这也可能很慢。恐怕调整不会是次要(这是问题的主题)。
    • 事实上,这有助于我完成另一项任务。投票赞成。精通SQL,非常感谢。尊重。
    【解决方案3】:
    SELECT u.*, p.*, max(p.date)
    FROM payments p
    JOIN users u ON u.id=p.user_id AND u.package = 1
    GROUP BY u.id
    ORDER BY p.date DESC
    

    看看这个sqlfiddle

    【讨论】:

    • limit 1 子句只会返回 1 个用户,这不是 OP 想要的。
    • @MateiMihai ,这不起作用。该查询仅给出最大日期,而不是具有最大日期的整行。您可以在小提琴中看到它:date column is different from max(p.date)。如果您在payments 表中添加更多列(例如cost),则所有这些列都不会来自需要的行
    【解决方案4】:
       SELECT u.* 
            FROM users AS u
            INNER JOIN (
                SELECT p.*,
                 @num := if(@id = user_id, @num + 1, 1) as row_number,
                 @id := user_id as tmp
                FROM payments AS p,
                     (SELECT @num := 0) x,
                     (SELECT @id := 0) y
                ORDER BY p.user_id ASC, date DESC)
            ON (p.user_id = u.id) and (p.row_number=1)
            WHERE u.package = 1
    

    【讨论】:

      【解决方案5】:

      您的查询有两个问题:

      1. 每个表和子查询都需要一个名称,因此您必须将子查询命名为INNER JOIN (SELECT ...) AS p ON ...
      2. 您拥有的子查询仅返回一个行期间,但您实际上希望为每个用户提供一行。为此,您需要一个查询来获取最大日期,然后自行返回以获取整行。

      假设payments.date 没有关联,请尝试:

          SELECT u.*, p.* 
          FROM (
              SELECT MAX(p.date) AS date, p.user_id 
              FROM payments AS p
              GROUP BY p.user_id
          ) AS latestP
          INNER JOIN users AS u ON latestP.user_id = u.id
          INNER JOIN payments AS p ON p.user_id = u.id AND p.date = latestP.date
          WHERE u.package = 1
      

      【讨论】:

      • 这是您使用的好方法。但我对针对一种产品获取一张图片有疑问。一种产品有很多 (4) 张图片,但我只想针对该产品显示一张图片。
      • 我发现这个速度最快。我所做的唯一更改是在子查询中添加 where 子句以仅过滤选定的用户数据 From payments as p Where p.user_id =@user_id,因为查询正在对整个表进行分组。
      【解决方案6】:

      @John Woo 的回答帮助我解决了类似的问题。我还通过设置正确的顺序改进了他的答案。这对我有用:

      SELECT  a.*, c.*
      FROM users a 
          INNER JOIN payments c
              ON a.id = c.user_ID
          INNER JOIN (
              SELECT user_ID, MAX(date) as maxDate FROM
              (
                  SELECT user_ID, date
                  FROM payments
                  ORDER BY date DESC
              ) d
              GROUP BY user_ID
          ) b ON c.user_ID = b.user_ID AND
                 c.date = b.maxDate
      WHERE a.package = 1
      

      不过,我不确定这有多有效。

      【讨论】:

        【解决方案7】:

        你可以试试这个:

        SELECT u.*, p.*
        FROM users AS u LEFT JOIN (
            SELECT *, ROW_NUMBER() OVER(PARTITION BY userid ORDER BY [Date] DESC) AS RowNo
            FROM payments  
        ) AS p ON u.userid = p.userid AND p.RowNo=1
        

        【讨论】:

        • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
        【解决方案8】:
        SELECT U.*, V.* FROM users AS U 
        INNER JOIN (SELECT *
        FROM payments
        WHERE id IN (
        SELECT MAX(id)
        FROM payments
        GROUP BY user_id
        )) AS V ON U.id = V.user_id
        

        这将使它工作

        【讨论】:

          【解决方案9】:

          Matei Mihai 给出了一个简单有效的解决方案,但只有在 SELECT 部分输入 MAX(date) 后才会起作用,因此此查询将变为:

          SELECT u.*, p.*, max(date)
          FROM payments p
          JOIN users u ON u.id=p.user_id AND u.package = 1
          GROUP BY u.id
          

          order by 不会对分组产生任何影响,但它可以对 group by 提供的最终结果进行排序。我试过了,它对我有用。

          【讨论】:

            【解决方案10】:

            如果您在 ORDER BY 子句中需要多个列,我的回答直接来自 @valex 非常有用。

                SELECT u.* 
                FROM users AS u
                INNER JOIN (
                    SELECT p.*,
                     @num := if(@id = user_id, @num + 1, 1) as row_number,
                     @id := user_id as tmp
                    FROM (SELECT * FROM payments ORDER BY p.user_id ASC, date DESC) AS p,
                         (SELECT @num := 0) x,
                         (SELECT @id := 0) y
                    )
                ON (p.user_id = u.id) and (p.row_number=1)
                WHERE u.package = 1
            

            【讨论】:

              【解决方案11】:

              这很简单,内部连接,然后按 user_id 分组,并在 payment_id 中使用 max 聚合函数,假设您的表是用户并且付款查询可以是

              SELECT user.id, max(payment.id)
              FROM user INNER JOIN payment ON (user.id = payment.user_id)
              GROUP BY user.id
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2018-06-15
                • 1970-01-01
                • 1970-01-01
                • 2013-03-02
                • 1970-01-01
                • 2010-12-21
                • 2020-03-01
                • 2015-02-14
                相关资源
                最近更新 更多