2012-02-04 5 views
14

Supposons que j'ai les deux tableaux suivants:LEFT JOIN sur Max Valeur

STUDENT 
studentid lastname firstname 
1   Smith  John 
2   Drew  Nancy 

STUDENT_STORY 
studentid dateline storyid status 
1   1328313600 10  2 
1   1328313601 9   1 
2   1328313602 14  2 
2   1328313603 12  1 

Maintenant, je besoin d'une requête SQL qui sélectionnerait chaque étudiant ainsi que la dernière histoire pour cet étudiant dans le tableau de l'histoire des étudiants.

Je suis en train ceci:

SELECT s.*, ss.* 
FROM student AS s 
LEFT JOIN (
    SELECT * 
    FROM student_story 
    WHERE student_story.studentid = s.studentid 
    ORDER BY dateline DESC LIMIT 1 
) AS ss ON (ss.studentid = s.studentid) 

Cependant, cette requête ne fonctionne pas. Il se plaint que s.studentid soit un champ inconnu dans la clause where de la sous-requête.

S'il vous plaît suggérer comment je peux réaliser ce que je suis en train de faire.

Merci.

Répondre

17

Essayez quelque chose comme ceci:

SELECT 
    s.*, 
    ss.* 
FROM 
    student AS s 
LEFT JOIN 
    student_story AS ss 
ON (ss.studentid = s.studentid) 
WHERE ss.dateline = (
    SELECT 
    MAX(dateline) 
    FROM 
    student_story AS ss2 
    WHERE 
    ss2.studentid = s.studentid 
) 
+1

Maintenant, quand je pense à ce sujet, cela pourrait revenir le même étudiant deux fois s'il y avait plusieurs entrées avec le même horodatage, donc ne l'utilisez probablement pas. – Detheroc

+0

Cela ne devrait jamais être le cas, sauf si quelque chose ne va pas. Comment puis-je corriger cette requête afin qu'elle ne renvoie pas deux fois le même étudiant s'il y a plusieurs entrées avec le même horodatage? – akanevsky

+0

Si les ID de la table student_story sont également susceptibles d'augmenter avec le temps, vous pouvez sélectionner et comparer l'ID maximum. Cela ne semble pas être le cas dans votre exemple, donc le problème est probablement assez délicat. La solution de Vyktor n'a-t-elle pas fonctionné? Cela semble tout à fait raisonnable. – Detheroc

1

Cette jointure doit le faire:

SELECT s.*, ss.* 
FROM student_story AS ss 
LEFT JOIN student AS s 
    ON student_story.studentid = s.userid 
GROUP BY ss.studentid 

GROUP BY devrait prendre la dernière ligne, de sorte que la dernière histoire = dernière ligne, si elle ne fonctionne pas essayer de :

GROUP BY ss.studentid, ss.dateline DESC 

Je ne suis pas sûr à ce sujet, s'il vous plaît commenter avec un résultat

+0

Non "le serveur est libre de choisir n'importe quelle valeur de cette colonne non agrégée" https://dev.mysql.com/doc/refman/5.7/fr/group-by-modifiers.html –

4
SELECT s.*, ss.* 
FROM student AS s 
LEFT JOIN (

SELECT * FROM student_story  
ORDER BY dateline DESC LIMIT 1 
) 
AS ss ON (ss.studentid = s.studentid) 
+0

J'ai appris de toutes les réponses fournies mais le vôtre m'a donné un meilleur travail. –

+0

Cela ne fonctionne pas car la sous-sélection ne renvoie qu'un seul résultat pour tous les élèves qui ne peuvent pas être joints pour tous sauf la plus récente student_story. – Roben

0

Vous aurez besoin d'ajouter un auto et identifiant unique sur chaque ligne sur la table student_story.

alors vous les distinguerez. (Assumer studentstory.new_id)

select s.*, ss.* 
from student s 
left join student_story ss on ss.studentid = s.userid 
where ss.new_id = (select ss.new_id from student s 
    group by dateline 
    order by dateline desc 
    limit 1 
) 
1
SELECT 
    s.sale_id, 
    s.created_at, 
    p.created_at, 
    DATEDIFF(p.created_at, s.created_at) AS days 
FROM 
    pos_sales s 
     LEFT JOIN 
    pos_payments p ON p.sale_id = s.sale_id 
     AND 
    p.created_at = (SELECT 
      MAX(p2.created_at) 
     FROM 
      pos_payments p2 
     WHERE 
      p2.sale_id = p.sale_id) 
0

Une autre approche fait une LEFT JOIN avec une condition NOT EXISTS(). Selon le scénario, cela peut donner un peu plus de flexibilité; cependant, il montrera également des résultats en double s'il y a deux entrées avec le même dateline par étudiant:

SELECT s.*, ss.* 
FROM student AS s 
LEFT JOIN student_story AS ss ON ss.studentid = s.studentid AND NOT EXISTS 
    (SELECT * FROM student_story AS ss2 
    WHERE ss2.studentid = ss.studentid AND ss2.dateline > ss.dateline)