I have an employee table that looks like this:
| id | name | q1 | q2 | q3 | q4 |
+----+------+----+----+----+----+
| 1 | John | 20 | 30 | 10 | 4 |
| 2 | Ram
I would use a CASE statement to compare the greatest value against each column until a match is found
Not perfect as it won't be fast and will also just find the first column when more than one share the same max value:-
SELECT id,
name,
LEAST(q1, q2, q3, q4) AS minValue,
CASE LEAST(q1, q2, q3, q4)
WHEN q1 THEN 'q1'
WHEN q2 THEN 'q2'
WHEN q3 THEN 'q3'
ELSE 'q4'
END,
GREATEST(q1, q2, q3, q4) AS maxValue,
CASE GREATEST(q1, q2, q3, q4)
WHEN q1 THEN 'q1'
WHEN q2 THEN 'q2'
WHEN q3 THEN 'q3'
ELSE 'q4'
END
FROM employee
WHERE id = 4;
EDIT - using a join, and I suspect this will be far worse:-
SELECT a0.id,
a0.name,
LEAST(a0.q1, a0.q2, a0.q3, a0.q4) AS minValue,
CASE
WHEN a1.id IS NULL THEN 'q1'
WHEN a2.id IS NULL THEN 'q2'
WHEN a3.id IS NULL THEN 'q3'
ELSE 'q4'
END,
GREATEST(a0.q1, a0.q2, a0.q3, a0.q4) AS maxValue,
CASE GREATEST(q1, q2, q3, q4)
WHEN a15.id IS NULL THEN 'q1'
WHEN a16.id IS NULL THEN 'q2'
WHEN a17.id IS NULL THEN 'q3'
ELSE 'q4'
END
FROM employee a0
LEFT OUTER JOIN employee a1 ON a0.id = a1.id AND LEAST(a0.q1, a0.q2, a0.q3, a0.q4) = a1.q1
LEFT OUTER JOIN employee a2 ON a0.id = a2.id AND LEAST(a0.q1, a0.q2, a0.q3, a0.q4) = a2.q2
LEFT OUTER JOIN employee a3 ON a0.id = a3.id AND LEAST(a0.q1, a0.q2, a0.q3, a0.q4) = a3.q3
LEFT OUTER JOIN employee a4 ON a0.id = a4.id AND LEAST(a0.q1, a0.q2, a0.q3, a0.q4) = a4.q4
LEFT OUTER JOIN employee a11 ON a0.id = a11.id AND GREATEST(a0.q1, a0.q2, a0.q3, a0.q4) = a1.q11
LEFT OUTER JOIN employee a12 ON a0.id = a12.id AND GREATEST(a0.q1, a0.q2, a0.q3, a0.q4) = a2.q12
LEFT OUTER JOIN employee a13 ON a0.id = a13.id AND GREATEST(a0.q1, a0.q2, a0.q3, a0.q4) = a3.q13
LEFT OUTER JOIN employee a14 ON a0.id = a14.id AND GREATEST(a0.q1, a0.q2, a0.q3, a0.q4) = a4.q14
WHERE a0.id = 4;
You can use a case
statement:
CASE
WHEN LEAST(q1, q2, q3, q4) = q1 THEN 'q1'
WHEN LEAST(q1, q2, q3, q4) = q2 THEN 'q2'
WHEN LEAST(q1, q2, q3, q4) = q3 THEN 'q3'
ELSE 'q4'
END as minQuestion
(Note: it will lose information over ties.)
If you're interested in ties, approaching it with a subquery and arrays will do the trick:
with employee as (
select id, q1, q2, q3, q4
from (values
(1, 1, 1, 3, 4),
(2, 4, 3, 1, 1)
) as rows (id, q1, q2, q3, q4)
)
SELECT least(q1, q2, q3, q4),
array(
select q
from (values (q1, 'q1'),
(q2, 'q2'),
(q3, 'q3'),
(q4, 'q4')
) as rows (v, q)
where v = least(q1, q2, q3, q4)
) as minQuestions
FROM employee e
WHERE e.id = 1;
Below will show max and min values. It will also show shared max and min values. It will fall down if max and min values happen to be the same. (eg all values are the same)
SELECT
employee.id, x.name,
CASE
WHEN employee.q1 = x.minVal THEN 'minval'
WHEN employee.q1 = x.maxVal THEN 'maxval'
ELSE ''
END AS q1,
CASE
WHEN employee.q2 = x.minVal THEN 'minval'
WHEN employee.q2 = x.maxVal THEN 'maxval'
ELSE '' END AS q2,
CASE
WHEN employee.q3 = x.minVal THEN 'minval'
WHEN employee.q3 = x.maxVal THEN 'maxval'
ELSE '' END AS q3,
CASE
WHEN employee.q4 = x.minVal THEN 'minval'
WHEN employee.q4 = x.maxVal THEN 'maxval'
ELSE '' END AS q4,
x.minVal,
x.maxVal
FROM employee
INNER JOIN
(
SELECT e.id, e.name,
LEAST(e.q1, e.q2, e.q3, e.q4) AS minVal,
GREATEST(e.q1, e.q2, e.q3, e.q4) AS maxVal
FROM employee e
WHERE e.id = 4
) x
ON employee.id=x.id
Use a "simple" or "switched" CASE statement:
SELECT CASE LEAST(q1, q2, q3, q4)
WHEN q1 THEN 'q1'
WHEN q2 THEN 'q2'
WHEN q3 THEN 'q3'
ELSE 'q4'
END as chosen_item
In case of ties, the first item in the list will be reported.