2016-05-20 16 views
0

Danke stackoverflow community! Ich habe über die Jahre so viel von dir gelernt und ich habe kürzlich einen Account erstellt. Ich hoffe, die Antwort auf diese Frage ist nicht offensichtlich irgendwo schon, aber ich werde mit gekreuzten Augen gehen, wenn ich einen anderen Beitrag lese. Hier ist mein Problem:Nested SELECT, um den höchsten Wert zu finden und 0 anzuzeigen, falls nicht gefunden

Ich habe vor kurzem eine verschachtelte SELECT verwendet, um die höchste Punktzahl für jeden meiner Schüler aus einer Tabelle zu bekommen. Ich tat es durch einen kleinen Trick, den ein anderer Post mir beibrachte. Ich kann den genauen Post nicht finden, von dem ich es gelernt habe, aber hier ist ein Ausschnitt, der im Wesentlichen der gleiche Trick ist. Ich stelle mir vor, wenn Sie gut in SQL auskennen, es ist nichts Neues für Sie:

SELECT id, authorId, answer, votes 
FROM ( SELECT id, authorId, answer, votes 
     FROM answers 
     ORDER BY votes DESC) AS h 
GROUP BY authorId 

Die ORDER BY ____ DESC macht den letzten Wert, der höchste alle bisherigen überschreiben, so dass Sie mit nur es am Ende ... wenn ich richtig verstehe. Also, das war großartig und ich habe es auf meine Bedürfnisse zugeschnitten. Das einzige Problem ist, dass ich jetzt noch ein weiteres Feature hinzufügen möchte und meine Gehirnzellen darüber zerreiße. Ich hoffe, dass ein großzügiger Mensch mich gerade aufrichten wird. Ich möchte eine vollständige Liste der Schüler von meinem "Dienstplan" -Tisch bekommen, und wenn es für einen bestimmten Schüler keine Punkte gibt, möchte ich in meiner "Halter" -Tabelle eine "0" anzeigen. Hier ist, was ich habe, und ich weiß nicht genau, wie es zwicken genau das zu tun:

SELECT * 
FROM (
     SELECT 
     holder.id, 
     #IFNULL(holder.score, 0) AS score, 
     holder.score AS score, 
     holder.total, 
     holder.student_id AS stu_id, 
     holder.date AS date, 
     users.firstname AS first, 
     users.lastname AS last, 
     users.stu_number AS stuno, 
     assignments.name AS test, 
     rosters.p_id, 
     preps.period AS period, 
     preps.user 

     FROM holder 

     JOIN rosters 
     ON rosters.stu_id = holder.student_id 

     JOIN users 
     ON users.id = holder.student_id 

     JOIN assignments 
     ON assignments.id = holder.t_id 

     JOIN preps 
     ON preps.id = rosters.p_id 

     WHERE holder.visible = 0 
     AND preps.user = 1 
     AND assignments.user = 1 
     AND holder.t_id = 1 
     AND preps.period = 2 
     ORDER BY score DESC 
    ) x 
GROUP BY stuno 
ORDER BY last 

Sie diese Zeile sehen kann ich auf Kommentar ist eine meiner schwachen Versuche, um es ein "angezeigt 0 "wenn NULL, aber es funktioniert nicht. Ich bekomme eine vollständige Liste, aber wenn der Punktestand für einen Schüler nicht gefunden wird, wird dieser Schüler nicht in meiner Liste angezeigt. Hat jemand eine Lösung/Idee, die ich ausprobieren kann?

Übertreibe ich JOINs und mache mein Leben härter als es sein muss? Ich bin größtenteils Autodidakt, also weiß ich, dass ich einige Lücken in den Grundlagen habe. Es hat mich zwar nicht davon abgehalten, einige verrückte coole Projekte zu kreieren ... aber hin und wieder bin ich mir sicher, dass ich mir unnötigen Kummer mache.

//////////////////////////////////////////////////

Hier ist, was ich mit der Antwort unten getan haben, so dass es Informationen meiner Tabellen packt:

SELECT au.stu_id, 
    COALESCE(t.id, 0) as id, 
    COALESCE(t.score , 0) as score    
FROM rosters au 
LEFT JOIN (
    SELECT * 
     FROM (
      SELECT a.*, 
       @rownum := if(@prev_value = student_id, 
       @rownum + 1, 
      1) rn, 
     @prev_value := student_id as prev  
     FROM holder a, 
     (SELECT @rownum := 0, @prev_value := '') r 
     ORDER BY student_id, score DESC 
    ) T 
    WHERE T.rn = 1) T 
ON au.stu_id = T.student_id 

also, dieser große funktioniert, außer es Studenten nicht zeigen, die dies nicht tun haben Punkte für einen gegebenen Test. Wenn ihr Ergebnis nicht in der "Halter" -Tabelle gefunden wird, möchte ich, dass es als "0" angezeigt wird.

/////////////////

Warten Sie eine Minute! Ich habe vielleicht falsch ... Ich denke, es funktioniert richtig. Ich muss ein paar Dinge zwicken und zu dir zurückkommen. Übrigens, vielen Dank, dass Sie sich die Zeit genommen haben, mir zu helfen!

Antwort

1

Ihr erster Ansatz funktioniert nur, weil ein schlechtes Design auf MySQL.

Das sollte Recht aproach

SQL Fiddle Demo

SELECT a.id, a.authorId, a.answer, a.votes 
FROM ( SELECT authorId, 
       MAX(votes) as votes 
     FROM answers 
     GROUP BY authorId) AS h 
JOIN answers a 
    ON a.authorId = h.authorId 
AND a.votes = h.votes; 

OUTPUT

| id | authorId | answer | votes | 
|----|----------|--------|-------| 
| 2 |  a |  x2 | 21 | 
| 4 |  b |  x1 | 23 | ==> 
| 5 |  b |  x2 | 23 | ==> duplicates max value are possible 

Aber dieses Problem haben, wenn mehrere Antwort gleiche Punktzahl hat. Sie müssen eine Logik einbeziehen, um zu entscheiden, welche angezeigt werden soll.

Sie können auch Variable verwenden, um die höchste Punktzahl zu erhalten.

SELECT * 
FROM (
     SELECT a.*, 
      @rownum := if(@prev_value = authorId, 
          @rownum + 1, 
          1) rn, 
      @prev_value := authorId as prev  
     FROM answers a, 
      (SELECT @rownum := 0, @prev_value := '') r 
     ORDER BY authorId, votes DESC 
    ) T 
WHERE T.rn = 1; 

OUTPUT

| id | authorId | answer | votes | rn | prev | 
|----|----------|--------|-------|----|------| 
| 4 |  b |  x1 | 23 | 1 | b | => only one is show but would  
| 2 |  a |  x2 | 21 | 1 | a | be random unless you specify some rule. 

Jetzt für Ihre Frage müssen Sie auch LEFT JOIN statt JOIN zu bekommen die Schüler ohne Noten verwenden.

So etwas

SELECT au.authorId, 
     COALESCE(t.id, 0) as id, 
     COALESCE(t.answer , 0) as answer , 
     COALESCE(t.votes , 0) as votes    
FROM authors au 
LEFT JOIN (
      SELECT * 
      FROM (
        SELECT a.*, 
         @rownum := if(@prev_value = authorId, 
             @rownum + 1, 
             1) rn, 
         @prev_value := authorId as prev  
        FROM answers a, 
         (SELECT @rownum := 0, @prev_value := '') r 
        ORDER BY authorId, votes DESC 
       ) T 
      WHERE T.rn = 1) T 
     ON au.authorId = T.authorId 

OUTPUT

| authorId | id | answer | votes | 
|----------|----|--------|-------| 
|  a | 2 |  x2 | 21 | 
|  b | 4 |  x1 | 23 | 
|  c | 0 |  0 |  0 | 
+0

@Strawberry ich den 'COALESCE' aber was alias Im fehlenden enthalten kann? –

+0

Okay, ich muss sagen, deine SQL-Schreibfähigkeiten sind weit jenseits meiner schwachen Ebene. Ich war fast zu eingeschüchtert, um alles zu modifizieren, um dem "Schema" oder was auch immer an meinen Tischen zu entsprechen, aber ich war tatsächlich erfolgreich. Es spuckt jetzt alles aus wie es soll mit einer Ausnahme. Wenn der Schüler in meiner Pinnwand vorhanden ist, aber keine Punktzahl in der Haltetabelle hat, erscheint der Schüler einfach nicht in der Liste. –

+0

Versuchen Sie, Ihr Schema in sqlFiddle zu erstellen, und ich werde später einen Blick darauf werfen. –