MySQL INNER JOIN只从第二个表中选择一行

问题描述 投票:74回答:8

我有一个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
8个回答
117
投票

您需要有一个子查询来获取每个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

12
投票
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


11
投票
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
)

这个解决方案比accepted answer更好,因为当有一些付款使用相同的用户和日期时,它可以正常工作。


3
投票
   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

1
投票

您的查询有两个问题:

  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

1
投票

Matei Mihai给出了一个简单而有效的解决方案,但是在将一个MAX(date)放入SELECT部分​​之后它将无法工作,因此该查询将变为:

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

并且顺序不会对分组产生任何影响,但它可以命令分组提供的最终结果。我试过了,它对我有用。


1
投票

@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

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


0
投票

如果您在ORDER BY子句中需要多个cols,那么我的答案直接受到@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
© www.soinside.com 2019 - 2024. All rights reserved.