Подход
@ mkuligowski близок, но вам нужно внешнее объединение между CTE, обеспечивающим все возможные значения состояния, а затем необходимо подсчитать записи, которые на самом деле соответствуют:
-- CTE to generate all possible status values
with stored_statuses (status) as (
select 'A' from dual
union all select 'L' from dual
union all select 'P' from dual
union all select 'S' from dual
union all select 'T' from dual
)
select ss.status, count(si.status)
from stored_statuses ss
left join student_info si on si.status = ss.status
group by ss.status;
STATUS COUNT(SI.STATUS)
------ ----------------
P 12
A 2
T 0
S 1
L 0
CTE действуетв качестве фиктивной таблицы, содержащей пять статусов, которые вы хотите посчитать.Это внешнее соединение с вашей реальной таблицей - внешнее соединение означает, что строки из CTE все еще включены, даже если совпадений нет - и затем подсчитываются строки, которые соответствуют в вашей таблице.Это позволяет включать нулевые значения.
Вы также можете сделать это с коллекцией:
select ss.status, count(si.status)
from (
select column_value as status from table(sys.odcivarchar2list('A','L','P','S','T'))
) ss
left join student_info si on si.status = ss.status
group by ss.status;
Было бы предпочтительно иметь физическую таблицу, которая содержит эти значения (и их описания).);тогда вы могли бы также иметь отношение первичного / внешнего ключа для принудительного применения разрешенных значений в вашей существующей таблице.
Если все значения состояния действительно отображаются в вашей таблице, но у вас есть фильтр, который исключаетвсе строки для некоторых из них, тогда вы можете получить список всех (использованных) значений из самой таблицы вместо жесткого ее кодирования.
Если ваш первоначальный запрос был чем-то вроде этого, с полностью сделаннымup filter:
select si.status, count(*)
from student_info si
where si.some_condition = 'true'
group by si.status;
тогда вы можете использовать подзапрос, чтобы получить все отличные значения из нефильтрованной таблицы, внешнее соединение из этой же таблицы и применить фильтр как часть условия внешнего соединения:
select ss.status, count(si.status)
from (
select distinct status from student_info
) ss
left join student_info si on si.status = ss.status
and si.some_condition = 'true'
group by ss.status;
Он не может оставаться в качестве предложения where
(по крайней мере, здесь, где он применяется к правой стороне внешнего соединения), потому что это переопределит внешнее соединение и эффективно повернетэто обратно во внутреннее соединение.