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