Как включить пустые строки в один SQL-запрос GROUP BY DAY (date_field)? - PullRequest
5 голосов
/ 27 февраля 2009

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

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

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 ]

7 голосов
/ 27 февраля 2009

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

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 ..

0 голосов
/ 27 февраля 2009

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

0 голосов
/ 27 февраля 2009

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

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 литералов даты, выбранных из «dual», или некоторого табличного выражения, которое гарантирует одну строку (в терминах Informix, SELECT MDY(2,28,2009) FROM "informix".systables WHERE tabid = 1 UNION ...).

0 голосов
/ 27 февраля 2009

Можете ли вы создать табличную переменную с нужными вам датами, а затем 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

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

...