1

I have a multiple choice application with items, options, answers, and user tables:

  • An item is basically a question. Each item belongs to one of three categories. The category is stored as a string in the category field.
  • Each item has several options linked to it. Each option has item_id and points fields.
  • Whenever a user selects an option, an answer is created. It has user_id, item_ id, and option_id fields. There's exactly one answer per item/user pair.

What I need

I'd like to have a query that summarizes the results for each user, one user per row. Each row should contain three columns containing the sum of points the user scored in that category:

Name | Points in Cat1 | Points in Cat2 | Points in Cat3
John | 3              | 1.5            | 2 
Jane | 2              | 2              | 1.5

What I have

I can output points grouped by user and category in separate rows:

SELECT
  u.id,
  u.first_name,
  i.category,
  sum(o.points)

FROM 
  answers a,
  options o,
  items i,
  users u

WHERE a.user_id = u.id
  AND a.option_id = o.id
  AND o.item_id = a.item_id
  AND i.id = a.item_id

GROUP BY u.id, i.category;

# Output:
# John   Cat1   3
# John   Cat2   1.5
# John   Cat3   2
# Jane   Cat1   2
# etc.

I need help modifying the query in the second code listing in a way that gives me the same data, but in a format as I sketched out in the first listing.

Pida
  • 928
  • 9
  • 32
  • Instead of the answer provided below, seriously consider handling issues of data display in application code. – Strawberry Mar 13 '19 at 11:30
  • Thanks! Actually that's just what I'm going to do when I refactor the app and integrate it with another one. It's just that atm there's no backend at all and I don't want to invest much time into this version. – Pida Mar 13 '19 at 17:17

1 Answers1

1

use conditional aggregation with case when expression

select firstname,
       max(case when category='Cat1' then p end) "Points in Cat1"
       max(case when category='Cat2' then p end) "Points in Cat2",
       max(case when category='Cat3' then p end) "Points in Cat3"
from
(
SELECT
  u.id,
  u.first_name,
  i.category,
  sum(o.points) as p
FROM 
  answers a join users u on a.user_id = u.id join options o on a.option_id = o.id
  join items i on i.id = a.item_id
GROUP BY u.id, i.category, u.id,u.first_name
)AA group by firstname
Fahmi
  • 37,315
  • 5
  • 22
  • 31
  • 1
    Thanks, that's just what I needed. There's a typo, though: "firstname" must be "first_name", and I used "group by id" instead of "group by firstname" because names might not be unique. – Pida Mar 13 '19 at 17:13