J'ai une table users
et une table payments
. Pour chaque utilisateur, ceux qui ont des paiements peuvent avoir plusieurs paiements associés dans la table payments
. Je souhaite sélectionner tous les utilisateurs qui ont des paiements, mais uniquement leur dernier paiement. J'essaie ce SQL mais je n'ai jamais essayé d'instructions SQL imbriquées auparavant, alors je veux savoir ce que je fais de travers. Apprécier l'aide
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
Vous devez avoir une sous-requête pour obtenir leur dernière date par 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
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
Découvrez ceci sqlfiddle
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
)
Cette solution est meilleure que la réponse acceptée car elle fonctionne correctement lorsque certains paiements ont le même utilisateur et la même date.
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
La réponse de @John Woo m'a aidé à résoudre un problème similaire. J'ai amélioré sa réponse en définissant également le bon ordre. Cela a fonctionné pour moi:
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
Je ne sais pas si c'est efficace, cependant.
Matei Mihai a donné une solution simple et efficace, mais cela ne fonctionnera pas tant que vous n'aurez pas mis une MAX(date)
dans la partie SELECT. Cette requête deviendra alors:
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
Et l'ordre de ne fera aucune différence dans le regroupement mais il peut ordonner le résultat final fourni par le groupe. J'ai essayé et cela a fonctionné pour moi.
Votre requête pose deux problèmes:
INNER JOIN (SELECT ...) AS p ON ...
. En supposant qu'il n'y ait pas de liens pour payments.date
, essayez:
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
Ma réponse directement inspirée de @valex est très utile si vous avez besoin de plusieurs colonnes dans la clause 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