2012-02-04 29 views
14

Supponiamo di avere due tabelle seguenti:LEFT JOIN su Max Valore

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 

Ora, ho bisogno di una query SQL che seleziona ogni studente insieme alla più recente storia per quello studente nella tabella storia studente.

Sto provando questo:

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) 

Tuttavia, questa query non funziona. Si lamenta che s.studentid è un campo sconosciuto nella clausola where della subquery.

Si prega di suggerire come posso ottenere quello che sto cercando di fare.

Grazie.

risposta

17

provare qualcosa di simile:

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

Ora, quando penso a questo proposito, questo potrebbe restituire lo stesso studente due volte se ci fossero più voci con la stessa data e ora, quindi probabilmente non usare questo. – Detheroc

+0

Questo non dovrebbe mai essere il caso, a meno che qualcosa non sia seriamente sbagliato. Come posso risolvere questa query in modo che non restituisca lo stesso studente due volte se ci sono più voci con lo stesso timestamp? – akanevsky

+0

Se anche gli ID nella tabella student_story aumentano con il tempo, è possibile selezionare e confrontare l'ID massimo. Questo non sembra essere il caso nel tuo esempio, quindi il problema è probabilmente abbastanza complicato. La soluzione di Vyktor non funzionava? Sembra abbastanza ragionevole. – Detheroc

1

Questa unirsi dovrebbe farlo:

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 dovrebbe prendere nell'ultima fila, in modo da ultima storia = ultima fila, se non funziona provate a :

GROUP BY ss.studentid, ss.dateline DESC 

non sono sicuro a questo proposito, si prega di commento con esito

+0

No. "il server è libero di scegliere qualsiasi valore da questa colonna non aggregata" https://dev.mysql.com/doc/refman/5.7/en/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

Ho imparato da tutte le risposte fornite ma il tuo mi ha dato un lavoro migliore. –

+0

Questo non funziona perché la selezione secondaria restituisce solo un risultato per tutti gli studenti che non possono essere uniti per tutti tranne la singola student_story più recente. – Roben

0

Avrai bisogno di aggiungere un auto e id unica su ogni riga sul tavolo student_story.

quindi li distinguerai. (Assumere 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

Un altro approccio è fare un LEFT JOIN con una condizione NOT EXISTS(). A seconda dello scenario, questo può dare un po 'più di flessibilità; tuttavia, sarà anche mostrare i risultati duplicati se ci sono due voci con lo stesso dateline per studente:

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)