Как включить пустые строки в один 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)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 ...
).