Reputation: 1554
I have two tables, image
and gradeReason
. Each image is awarded a grade for it's quality and the user can select up 4 different reasons (reasonID_1
, reasonID_2
, reasonID_3
, reasonID_4
) by using selecting a reasonID
. The breakdown of the reason is stored in the gradeReason
table.
image
imageID auditID reasonID_1 reasonID_2 reasonID_3 reasonID_4
------- ------- ---------- ---------- ---------- ----------
1 123 1 13 7 3
2 124 8 13 8 6
4 125 3 2 5 6
5 125 7 4 2 3
gradeReason
reasonID category name
-------- -------- ----
1 exposure overexposed
2 exposure underexposed
3 patient patient moved
4 equipment sensor too big
5 equipment sensor too small
What I would like is a query that will return the number of times each reasonID has been used in an audit and what the name of gradeReason was
e.g.
audit 125 -
reasonID 3 was used twice - name 'patient moved',
reasonID 2 used twice - name 'underexposed'.
I'll be honest and say I have struggled with this for days and I can't even think where to begin.
Upvotes: 0
Views: 76
Reputation: 21513
Another option using UNIONS:-
SELECT auditId, ReasonId, category, name, SUM(cnt)
FROM
(
SELECT ir.auditId, gr.ReasonId, gr.category, gr.name, count(*) as cnt
FROM image ir
INNER JOIN gradeReason gr
ON ir.reasonID_1 = gr.ReasonId
WHERE ir.auditId = 123
GROUP BY ir.auditId, gr.ReasonId, gr.category, gr.name
UNION ALL
SELECT ir.auditId, gr.ReasonId, gr.category, gr.name, count(*) as cnt
FROM image ir
INNER JOIN gradeReason gr
ON ir.reasonID_2 = gr.ReasonId
WHERE ir.auditId = 123
GROUP BY ir.auditId, gr.ReasonId, gr.category, gr.name
UNION ALL
SELECT ir.auditId, gr.ReasonId, gr.category, gr.name, count(*) as cnt
FROM image ir
INNER JOIN gradeReason gr
ON ir.reasonID_3 = gr.ReasonId
WHERE ir.auditId = 123
GROUP BY ir.auditId, gr.ReasonId, gr.category, gr.name
UNION ALL
SELECT ir.auditId, gr.ReasonId, gr.category, gr.name, count(*) as cnt
FROM image ir
INNER JOIN gradeReason gr
ON ir.reasonID_4 = gr.ReasonId
WHERE ir.auditId = 123
GROUP BY ir.auditId, gr.ReasonId, gr.category, gr.name
) Sub1
GROUP BY auditId, ReasonId, category, name
Upvotes: 0
Reputation: 2020
For your select, you have to join gradeReason once for every foreign key to gradeReason:
SELECT imageID
, auditID
, r1.name
, r2.name
, r3.name
, r4.name
FROM image i
LEFT JOIN gradeReason r1 on i.reasonID_1 = r1.reasonID
LEFT JOIN gradeReason r2 on i.reasonID_2 = r2.reasonID
LEFT JOIN gradeReason r3 on i.reasonID_3 = r3.reasonID
LEFT JOIN gradeReason r4 on i.reasonID_4 = r4.reasonID
Your example data is not sensible, as the foreign keys to gradeReason in your table image is not in gradeReason, but I guess you have more gradeReasons up your sleeve.
Moreover,your structure is not normalized: gradeReason has duplicate entries in rows for category. This is not too bad, but it would be good practice to have a separate gradeReasonCategories table.
Upvotes: 0
Reputation: 1269693
This is harder because your data is not properly normalized. The following approach first normalizes the data, then does the join and aggregation:
select ir.auditId, gr.ReasonId, gr.category, gr.name, count(*) as cnt
from (select i.imageID, i.auditID,
(case when n.n = 1 then ReasonID_1
when n.n = 2 then ReasonID_2
when n.n = 3 then ReasonID_3
when n.n = 4 then ReasonID_4
end) as ReasonId
from image i cross join
(select 1 as n union all select 2 union all select 3 union all select 4
) n
) ir join
gradeReason gr
on ir.ReasonId = gr.ReasonId
group by ir.auditId, gr.ReasonId, gr.category, gr.name
order by cnt desc;
Upvotes: 5