0

So i have this problem of printing out table data from 3 different tables as a matrix. And after searching internet, i fanally found a solution to my problem. But i have no idea, how does that mysql statement work. This is a example that i want to do

and i think i found a solution so if some one could help explaining me of how it works?

SELECT names.codename,
s1.score AS "Score1", s1.comment AS "Comments1",
s2.score AS "Score2", s2.comment AS "Comments2",
SUM(st.score) AS "Total"
FROM students names 
LEFT JOIN scores s1 ON s1.act_id=1 AND names.id=s1.student_id 
LEFT JOIN scores s2 ON s2.act_id=2 AND names.id=s2.student_id 
LEFT JOIN scores st ON names.id=st.student_id
WHERE names.codename <> ''
GROUP BY names.codename
ORDER BY names.codename;

students table:
+----+---------------+
| id | codename      |
+----+---------------+
|  1 | Budy          |
+----+---------------+

assignments table:
+--------+------------+
| act_id | name       |
+--------+------------+
|      1 | Activity 1 |
|      2 | Activity 2 |
+--------+------------+

scores table:
+------------+--------+-------+
| student_id | act_id | score |
+------------+--------+-------+
|          1 |      1 |    10 |
|          1 |      2 |    10 |
+------------+--------+-------+

Now the problem was, I wanted to have the assignments listed across the top, and the scores next to the names. Something like this:

+---------------+------------+------------+-------+
| codename      | Activity 1 | Activity 2 | Total |
+---------------+------------+------------+-------+
|          budy |         10 |         10 |    20 |
+---------------+------------+------------+-------+
Nikos
  • 3,267
  • 1
  • 25
  • 32
  • You can loop through the data and build an array accordingly. – Sougata Bose Sep 22 '15 at 09:18
  • Could you be more specific? – Audrius Jurevičius Sep 22 '15 at 09:40
  • If you want an arbitrary number of activities, read about [pivoting](http://stackoverflow.com/tags/pivot/info) to transpose activity name values to column names. See also [this re predicates](http://stackoverflow.com/a/24425914/3404097) then [this re SQL](http://stackoverflow.com/a/27682724/3404097) re composing queries. – philipxy Sep 22 '15 at 10:39

1 Answers1

0

Try this

SELECT s.codename, SUM(IF(act.act_id=1, act.score, 0)) AS 'Activity 1', SUM(IF(act.act_id=2, act.score, 0)) AS 'Activity 2', total.score AS 'total' 
FROM
    students s
    INNER JOIN (SELECT student_id, act_id, SUM(score) AS score FROM scores GROUP BY 1, 2) act ON s.id=act.student_id
    INNER JOIN (SELECT student_id, SUM(score) AS score FROM scores GROUP BY 1) total ON s.id=total.student_id
GROUP BY 1

This will return results for only the students having records in the scores table. If you want to list all students, you'll have to change INNER JOIN to LEFT OUTER JOIN

UPDATE

I've updated the query and removed the first sub-query

SELECT student_id, act_id, SUM(score) AS score FROM scores GROUP BY 1, 2

this is not needed if student_id and act_id are a composite key so we can use the scores table directly. This way the query becomes

SELECT s.codename, SUM(IF(act.act_id=1, act.score, 0)) AS 'Activity 1', SUM(IF(act.act_id=2, act.score, 0)) AS 'Activity 2', total.score AS 'total' 
FROM
    students s
    INNER JOIN scores as 'act' ON s.id=act.student_id
    INNER JOIN (SELECT student_id, SUM(score) AS score FROM scores GROUP BY 1) total ON s.id=total.student_id
GROUP BY 1

Explanation

The JOIN between student and scores fetches all scores for all students (I added another student with id 2 and name Pal), e.g.

+----+----------+------------+--------+-------+
| id | codename | student_id | act_id | score |
+----+----------+------------+--------+-------+
|  1 | Buddy    |          1 |      1 |    10 |
|  1 | Buddy    |          1 |      2 |    10 |
|  2 | Pal      |          2 |      1 |    15 |
|  2 | Pal      |          2 |      2 |    10 |
+----+----------+------------+--------+-------+

The sub-query

SELECT student_id, SUM(score) AS score FROM scores GROUP BY 1

fetches sum of scores for each student like this

+------------+-------+
| student_id | score |
+------------+-------+
|          1 |    20 |
|          2 |    25 |
+------------+-------+

And we put the results together in the main SELECT part using

SELECT s.codename, SUM(IF(act.act_id=1, act.score, 0)) AS 'Activity 1', SUM(IF(act.act_id=2, act.score, 0)) AS 'Activity 2', total.score AS 'total'...

we add scores if act_id=1 in column 'Activity 1', similarly we add scores in column 'Activity 2' if act_id=2 and lastly we use the sum from sub-query as 'total'

I hope this clarifies your questions

mynawaz
  • 1,599
  • 1
  • 9
  • 16
  • This would be really helpfull if it would be written for these tables [link](https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit#gid=0). Or you could just explain that statement that you wrote with comments, that i could modify it to fit my tables – Audrius Jurevičius Sep 22 '15 at 12:16
  • @AudriusJurevičius, please see updated answer with explanation – mynawaz Sep 22 '15 at 12:35
  • when i try to rewrite your code to work on my database like this one [link for my visualized tables that i want to use this code with](https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit#gid=0) its does'nt work... And if would have stages of series_DB.stageQ - size, how should i try to update the statement...? :/ – Audrius Jurevičius Sep 22 '15 at 14:35
  • Its difficult to answer without knowing which table/field maps to which table/field in your question – mynawaz Sep 22 '15 at 14:48
  • does this link works for you? [https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit#gid=0](https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit#gid=0), there i made tables that i have, and in the right bottom is a table that i need to generate – Audrius Jurevičius Sep 22 '15 at 15:32
  • What is info_db? Will this be a table in your db with same values? Or is it only to give an idea of relations? Is it possible that you can create a new question with your actual tables and values? Its very hard to comprehend from the sheet only. You dont have to accept my answer there – mynawaz Sep 22 '15 at 15:50
  • info_db stores position of each player that participaten in n-th stage of a m-th serries. i can try to create another question with more details :/ – Audrius Jurevičius Sep 22 '15 at 16:08
  • grey color columns are primary keys – Audrius Jurevičius Sep 22 '15 at 16:23
  • @AudriusJurevičius, can you please allow write access to the sheet? Nearly there – mynawaz Sep 23 '15 at 08:29
  • https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit?usp=sharing here :) – Audrius Jurevičius Sep 23 '15 at 10:33
  • @AudriusJurevičius, please check the cell A30 in sheet – mynawaz Sep 23 '15 at 10:51
  • everything works, but when I add more rows to player_DB table, they are added to the printed out table without puting new rows to info_DB table, how could I fix this? So that the finished table would only contain information for serries_ID=1 – Audrius Jurevičius Sep 23 '15 at 15:42
  • Plz share sample data and expecred output – mynawaz Sep 23 '15 at 19:01
  • @nymawaz i have updated https://docs.google.com/spreadsheets/d/13dtDwjfujkwj4eJmKXSwqFOUajeHiWnyV6mtkJkXyzo/edit?usp=sharing – Audrius Jurevičius Sep 24 '15 at 09:39
  • @AudriusJurevičius. If you want the result to use data of `series_ID=1` only, then adding ` AND s.series_ID=1` to WHERE part of sub-queries of i1, i2 & i3 will do it. I've added this in the sheet – mynawaz Sep 24 '15 at 09:48
  • don't know why but it does'nt help @nymawaz – Audrius Jurevičius Sep 24 '15 at 10:03