SQL возвращает только строки с данными, а не те, которые равны 0

#sql #tsql

#sql #tsql

Вопрос:

Я пытаюсь сообщить о том, сколько элементов находится в определенном статусе. Полученный мной код возвращает только те строки, в которых есть значение, а не те, в которых его нет.

 SELECT Department
       ,Status
       ,count(Department) AS "Number in status" 
       ,convert(VARCHAR, getdate(), 103) AS "Date report ran"
FROM [Server name].[xxx].[Database name]
WHERE STATUS NOT IN (
              'Closed'
              ,'Cancelled'
              )
       AND Department IN (
              'Department name'
              )
GROUP BY Department,Status

ORDER BY CASE 
              WHEN STATUS = 'Open'
                     THEN 1
              WHEN STATUS = 'In Progress'
                     THEN 2
              WHEN STATUS = 'Authorised'
                     THEN 3
              WHEN STATUS = 'Awaiting Auth'
                     THEN 4
              WHEN STATUS = 'Awaiting Collection'
                     THEN 5
              WHEN STATUS = 'Awaiting Delivery'
                     THEN 6
              WHEN STATUS = 'Awaiting Development'
                     THEN 7
              WHEN STATUS = 'Awaiting Engineer'
                     THEN 8
              WHEN STATUS = 'Awaiting Invoice/Credit'
                     THEN 9
              WHEN STATUS = 'Awaiting Quote'
                     THEN 10
              WHEN STATUS = 'Cancelled'
                     THEN 11
              WHEN STATUS = 'Chase End User'
                     THEN 12
              WHEN STATUS = 'Final Chase End User'
                     THEN 13
              WHEN STATUS = 'Closed'
                     THEN 14
              WHEN STATUS = 'Future Requirements'
                     THEN 15
              WHEN STATUS = 'In Test'
                     THEN 16
              WHEN STATUS = 'Next Release'
                     THEN 17
                     WHEN STATUS = 'On Hold'
                     THEN 18
                     WHEN STATUS = 'With End-User'
                     THEN 22
                     WHEN STATUS = 'With IIT'
                     THEN 23
                     WHEN STATUS = 'Processing Via Demand Management'
                     THEN 27
              END;
  

Результаты приведены ниже, но они не включают все другие состояния, ‘ которые могут иметь значение 0:

  ----------------- ---------------------------------- ---- ------------ 
|                 |                                  |    |            |
 ----------------- ---------------------------------- ---- ------------ 
| Department name | Open                             | 92 | 29/03/2019 |
| Department name | In Progress                      |  9 | 29/03/2019 |
| Department name | Awaiting Development             |  4 | 29/03/2019 |
| Department name | Future Requirements              |  1 | 29/03/2019 |
| Department name | In Test                          |  7 | 29/03/2019 |
| Department name | On Hold                          | 15 | 29/03/2019 |
| Department name | With End-User                    | 28 | 29/03/2019 |
| Department name | With IIT                         |  2 | 29/03/2019 |
| Department name | Processing Via Demand Management |  2 | 29/03/2019 |
 ----------------- ---------------------------------- ---- ------------ 
  

Комментарии:

1. Как говорится, «Строки нет». Каждая строка в вашем выводе является представлением группы, сформированной из 1 или более входных строк.

2. Вы могли бы создать таблицу со всеми возможными статусами и создать внешнее соединение.

Ответ №1:

Вам нужна таблица состояния, содержащая, по крайней мере, описание состояния и (возможно) порядок представления отчетов:

 CREATE TABLE Statuses (
    Status varchar(30) not null,
    ReportOrder int not null,
    ShowInReport bit not null,
    constraint PK_Statuses (Status)
)
  

И теперь вы можете написать свой запрос, используя LEFT JOIN из этой таблицы в вашу другую неназванную таблицу (поскольку ваш запрос в настоящее время утверждает, что запрашивает базу данных, а не таблицу в своем FROM предложении:

 SELECT Department
       ,s.Status
       ,count(Department) AS "Number in status" 
       ,convert(VARCHAR, getdate(), 103) AS "Date report ran"
FROM
    Statuses s
       left join
    unnamedTable t
       on
          s.Status = t.Status
WHERE s.ShowInReport = 1
       AND Department IN (
              'Department name'
              )
GROUP BY Department,s.Status
ORDER BY s.ReportOrder
  

Также может быть разумно иметь Departments таблицу, если вы все еще хотите, чтобы названия отделов в выходных данных для 0 строк использовались очень похоже на приведенные выше:

 ...
FROM
    Statuses s
       cross join
    Departments d
       left join
    unnamedTable t
       on
          s.Status = t.Status and
          d.Department = t.Department
...
  

(У вас также должно быть значение FK между безымянной таблицей и Statuses , чтобы убедиться, что все используемые в ней значения статуса являются допустимыми)

Ответ №2:

Если ваша база данных хорошо спроектирована, ваш статус и подразделение отображаются в отдельной таблице, которую вы объединили со своей записью. Итак, вместо выполнения естественного объединения вы хотите выполнить :

Статус отдела X -> Вы получаете все возможные комбинации отдела и статуса и выполняете ЛЕВОЕ объединение в результирующей таблице с вашей записью. Затем вы группируете по подразделению и статусу, как вы делаете, и выполняете подсчет.

Комментарии:

1. Смотрите ответ Damien_The_Unbeliever для получения более подробной информации.