оператор select должен возвращать count как ноль, если ни одна строка не возвращается, используя выражение group by - PullRequest
0 голосов
/ 28 марта 2019

У меня есть таблица student_info, в ней есть столбец «status», статус может быть P (присутствует), A (отсутствует), S (плохо), T (передача), L (слева).

Я ищу ожидаемый результат, как показано ниже.

status  count(*)
P       12
S       1
A       2
T       0
L       0

Но вывод идет как показано ниже:

Status   Count(*)
P          12
S           1
A           2

нам также нужны строки со статусами T и L с нулевым счетом, хотя в БД нет записей.

Ответы [ 2 ]

1 голос
/ 28 марта 2019
Подход

@ 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 (по крайней мере, здесь, где он применяется к правой стороне внешнего соединения), потому что это переопределит внешнее соединение и эффективно повернетэто обратно во внутреннее соединение.

0 голосов
/ 28 марта 2019

Вы должны хранить где-нибудь свои статусы (ферапсы в другой таблице). В противном случае вы перечисляете их, используя подзапрос:

with stored_statuses as (
  select 'P' code, 'present' description from dual
  union all 
  select 'A' code, 'absent' description from dual
  union all 
  select 'S' code, 'ill' description from dual
  union all 
  select 'T' code, 'transfer' description from dual
  union all 
  select 'L' code, 'left' description from dual
)
select ss.code, count(*) from student_info si
left join stored_statuses ss on ss.code = si.status
group by ss.code
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...