Как включить пустые строки в один SQL-запрос GROUP BY DAY (date_field)?

Я использую MS SQL Server, но приветствую сравнительные решения из других баз данных.

Это основная форма моего запроса. Возвращает количество звонков в день из таблицы incidentsm1:

SELECT 
  COUNT(*) AS "Calls",
  MAX(open_time),
  open_day
FROM 
  (
SELECT
 incident_id,
 opened_by,
 open_time - (9.0/24) AS open_time,
 DATEPART(dd, (open_time-(9.0/24))) AS open_day
   FROM incidentsm1 
   WHERE 
 DATEDIFF(DAY, open_time-(9.0/24), GETDATE())< 7

  ) inc1
GROUP BY open_day

Эти данные используются для построения гистограммы, но если в данный день недели не было звонков, нет строки результатов и, следовательно, полосы, и пользователь спрашивает: «Почему на графике только шесть дней и перейти с субботы на понедельник? "

Как-то мне нужно ОБЪЕДИНЯТЬ ВСЕ с пустой строкой из каждого дня или что-то в этом роде, но я не могу этого понять.

Я ограничен тем, что могу делать с одним оператором SQL, и у меня есть доступ только для чтения, поэтому я не могу создать временную таблицу или что-то еще.

Ответов (4)

Решение

Как насчет этого?

SELECT 
  COUNT(incident_id) AS "Calls",
  MAX(open_time),
  days.open_day
FROM
(
  select datepart(dd,dateadd(day,-6,getdate())) as open_day union
  select datepart(dd,dateadd(day,-5,getdate())) as open_day union
  select datepart(dd,dateadd(day,-4,getdate())) as open_day union
  select datepart(dd,dateadd(day,-3,getdate())) as open_day union
  select datepart(dd,dateadd(day,-2,getdate())) as open_day union
  select datepart(dd,dateadd(day,-1,getdate())) as open_day union
  select datepart(dd,dateadd(day, 0,getdate())) as open_day 
) days
left join 
(
 SELECT
   incident_id,
   opened_by,
   open_time - (9.0/24) AS open_time,
   DATEPART(dd, (open_time-(9.0/24))) AS open_day
 FROM incidentsm1 
 WHERE DATEDIFF(DAY, open_time-(9.0/24), GETDATE()) < 7
) inc1 ON days.open_day = incidents.open_day
GROUP BY days.open_day

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

Я бы посоветовал использовать таблицу дат . Имея существующую таблицу дат, вы можете выполнить ПРАВИЛЬНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ с таблицей дат, чтобы указать недостающие дни.

Можете ли вы создать табличную переменную с нужными вам датами, а затем RIGHT JOIN на нее? Например,

DECLARE @dateTable TABLE ([date] SMALLDATETIME)

INSERT INTO @dateTable
VALUES('26 FEB 2009')
INSERT INTO @dateTable
VALUES('27 FEB 2009')
-- etc

SELECT 
  COUNT(*) AS "Calls",
  MAX(open_time),
  open_day
FROM 
  (
SELECT
 incident_id,
 opened_by,
 open_time - (9.0/24) AS open_time,
 DATEPART(dd, (open_time-(9.0/24))) AS open_day
   FROM incidentsm1
   RIGHT JOIN @dateTable dates
   ON incidentsm1.open_day = dates.date
   WHERE 
 DATEDIFF(DAY, open_time-(9.0/24), GETDATE())< 7

  ) inc1
GROUP BY open_day

Однако более идеальной ситуацией было бы иметь объект таблицы с датами в

Можете ли вы создать набор дат как часть вашего запроса? Что-то вроде:

SELECT COUNT(*) AS Calls, ...
    FROM incidentsm1 RIGHT OUTER JOIN
         (SELECT date_values
            FROM TABLE(('27 Feb 2009'), ('28 Feb 2009'), ('1 Mar 2009'),
                       ('2 Mar 2009'), ('3 Mar 2009'), ('4 Mar 2009'),
                       ('5 Mar 2009')) AS date_list
         )
         ON ...

Это навеяно своего рода гибридом нотаций Informix и DB2 и практически гарантированно будет синтаксически некорректным в обоих. В принципе, есть ли в вашей СУБД способ создания литеральной таблицы на лету. Одна из возможностей - уродливая, но едва выполнимая - состоит в том, чтобы выполнить 7-стороннее UNION литералов даты, выбранных из 'двойного' или некоторого табличного выражения, которое гарантирует одну строку (в терминах Informix SELECT MDY(2,28,2009) FROM "informix".systables WHERE tabid = 1 UNION ... ).