#sql #null
#sql #null
Вопрос:
У меня есть следующий запрос
SELECT ProgramDate, [CountVal]= COUNT(ProgramDate)
FROM ProgramsTbl
WHERE (Type = 'Type1' AND ProgramDate = '10/18/11' )
GROUP BY ProgramDate
Что происходит, так это то, что если нет записи, соответствующей типу и ProgramDate, я не получаю никаких возвращенных записей.
То, что я хотел бы вывести в приведенном выше примере, выглядит примерно следующим образом, если возвращаемых значений нет. Обратите внимание, что для CountVal у нас есть 0, даже если нет возвращенных записей, которые соответствуют условию соответствия:
ProgramDate CountVal
10/18/11 0
Комментарии:
1. Не могли бы вы уточнить, чего вы хотите? Вы группируете по ProgramDate. как вы можете группировать то, что равно нулю?
Ответ №1:
Это немного сложнее, чем хотелось бы, однако это вполне возможно. Сначала вам нужно будет создать временную таблицу дат. Например, приведенный ниже запрос создает диапазон дат от 2011-10-11 до 2011-10-20
CREATE TEMPORARY TABLE date_stamps AS
SELECT (date '2011-10-10' new_number) AS date_stamp
FROM generate_series(1, 10) AS new_number;
Используя эту временную таблицу, вы можете выбрать из нее и слева присоединиться к вашей таблице ProgramsTbl. Например
SELECT date_stamp,COUNT(ProgramDate)
FROM date_stamps
LEFT JOIN ProgramsTbl ON ProgramsTbl.ProgramDate = date_stamps.date_stamp
WHERE Type = 'Type1'
GROUP BY ProgramDate;
Комментарии:
1. Вам не нужно объединяться, поскольку агрегация просто вернет 0, если в ProgramsTbl нет значений ProgramDate . Кроме того, вы хотите группировать по date_stamp, а не по ProgramDate . В основном то же самое решение, которое я предложил ранее.
2. Да, я не мог вспомнить Дерека. Я еще не пил кофе.
3. Для этого работает временная таблица, хотя существуют рекурсивные версии CTE, которые работают довольно хорошо. Однако большинству бизнес-приложений, вероятно, потребуется постоянный
Calendar
файл (особенно в отношении таких вещей, как финансовый календарь).
Ответ №2:
Select ProgramDate, [CountVal]= SUM(occur)
from
(
SELECT ProgramDate, 1 occur
FROM ProgramsTbl
WHERE (Type = 'Type1' AND ProgramDate = '10/18/11' )
UNION
SELECT '10/18/11', 0
)
GROUP BY ProgramDate
Ответ №3:
Поскольку каждый оператор SELECT на самом деле создает таблицу записей, вы можете использовать запрос SELECT для построения таблицы как с количеством программ, так и с количеством по умолчанию, равным нулю. Для этого потребуется два запроса SELECT (один для получения фактического количества, другой для получения количества по умолчанию) и использование ОБЪЕДИНЕНИЯ для объединения двух результатов SELECT в одну таблицу.
Оттуда вы можете ВЫБРАТЬ из объединенной таблицы для суммирования значений CountVals (если programDate встречается в ProgramTable, значение CountVal будет равно CountVal первого запроса, если он существует (> 0) CountVal второго запроса (= 0)).
Таким образом, даже если в ProgramTable нет записей для желаемой programDate, вы получите обратно запись с указанием количества 0.
Это будет выглядеть так:
SELECT ProgramDate, SUM(CountVal)
FROM
(SELECT ProgramDate, COUNT(*) AS CountVal
FROM ProgramsTbl
WHERE (Type = 'Type1' AND ProgramDate = '10/18/11' )
UNION
SELECT '10/18/11' AS ProgramDate, 0 AS CountVal) T1
Ответ №4:
Вот решение, которое работает на SQL Server; не уверен в других платформах БД:
DECLARE @Type VARCHAR(5) = 'Type1'
, @ProgramDate DATE = '10/18/2011'
SELECT pt.ProgramDate
, COUNT(pt2.ProgramDate)
FROM ( SELECT @ProgramDate AS ProgramDate
, @Type AS Type
) pt
LEFT JOIN ProgramsTbl pt2 ON pt.Type = pt2.Type
AND pt.ProgramDate = pt2.ProgramDate
GROUP BY pt.ProgramDate
Ответ №5:
Гранж, но простой и эффективный
SELECT '10/18/11' as 'Program Date', count(*) as 'count'
FROM ProgramsTbl
WHERE Type = 'Type1' AND ProgramDate = '10/18/11'
Ответ №6:
Попробуйте что-нибудь в этом роде. Это создаст строку с датой 18.10.11, которая обязательно вернется. Затем вы оставили соединение с вашими фактическими данными, чтобы получить желаемое количество (которое теперь может возвращать 0, если соответствующих строк нет).
Чтобы сделать это для более чем 1 даты, вам нужно создать таблицу дат, содержащую список всех дат, которые вы хотите запросить (поэтому замените «выбрать ‘18.10.11’» на «выбрать дату из DateTbl»).
SELECT ProgDt.ProgDate, [CountVal]= COUNT(ProgramsTbl.ProgramDate)
FROM (SELECT '10/18/11' as 'ProgDate') ProgDt
LEFT JOIN ProgramsTbl
ON ProgDt.ProgDate = ProgramsTbl.ProgramDate
WHERE (Type = 'Type1')
GROUP BY ProgDt.ProgDate
Чтобы создать таблицу дат, которую можно использовать для запросов, выполните следующие действия (предполагается, что SQL Server 2005 ):
create table Dates (MyDate datetime)
go
insert into Dates
select top 100000 row_number() over (order by s1.name)
from master..spt_values s1, master..spt_values s2
go
Комментарии:
1. Дерек, что касается меня, у меня есть диапазон дат, но некоторые даты могут быть нулевыми, и поэтому я не уверен, как заставить заполнить таблицу tmp всеми датами.
2. Вы можете просто создать статическую таблицу, в которой всегда есть все даты. Эти «служебные» таблицы могут быть очень полезны для упрощения ваших запросов. Я отредактирую некоторый код в ответ, чтобы включить это.