155 votes

MySQL INNER JOIN sélectionne une seule ligne de la deuxième table

J'ai une table users et une table payments , pour chaque utilisateur, 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
 

193voto

John Woo Points 132738

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
 

11voto

Matei Mihai Points 6312
 SELECT u.*, p.*
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 ce sqlfiddle

3voto

valex Points 16074
   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

2voto

lc. Points 50297

Votre requête pose deux problèmes:

  1. Chaque table et sous-requête a besoin d'un nom. Vous devez donc nommer la sous-requête INNER JOIN (SELECT ...) AS p ON ... .
  2. La sous-requête telle que vous la connaissez ne renvoie qu'une période de ligne, mais vous souhaitez en réalité une ligne pour chaque utilisateur . Pour cela, vous avez besoin d’une requête pour obtenir la date maximale, puis de la même jointure pour obtenir la ligne entière.

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
 

1voto

hassan Points 13

Matei Mihai a donné une solution simple et efficace, mais cela ne fonctionnera que si vous mettez une partie MAX(date) dans 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 ordre par ne fera aucune différence dans le regroupement mais il peut ordonner le résultat final fourni par groupe par. J'ai essayé et cela a fonctionné pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X