Подтвердить что ты не робот

MySQL INNER JOIN выбирает только одну строку из второй таблицы

У меня есть таблица 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
4b9b3361

Ответ 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

Ответ 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
)

Это решение лучше, чем принятый ответ, потому что оно работает правильно, когда есть платежи с тем же пользователем и датой.

Ответ 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

Ответ 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

В вашем запросе есть две проблемы:

  • Для каждой таблицы и подзапроса требуется имя, поэтому вы должны указать подзапрос INNER JOIN (SELECT ...) AS p ON ....
  • Подзапрос, который у вас есть, возвращает только один период строки, но вам действительно нужна одна строка для каждого пользователя. Для этого вам нужен один запрос, чтобы получить максимальную дату, а затем самосоединиться, чтобы получить всю строку.

Предполагая, что для 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

Ответ 6

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

И порядок не будет иметь никакого значения для группировки, но он может заказать конечный результат, предоставленный группой. Я попробовал, и это сработало для меня.

Ответ 7

@Ответ Джона Ву помог мне решить аналогичную проблему. Я улучшил его ответ, установив правильный порядок. Это сработало для меня:

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

Я не уверен, насколько это эффективно.

Ответ 8

Мой ответ, вдохновленный @valex, очень полезен, если вам нужно несколько столбцов в предложении ORDER BY.

    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

Ответ 9

Вы можете попробовать это:

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