Оператор Select возвращает 0, если значение равно нулю

#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. Вы можете просто создать статическую таблицу, в которой всегда есть все даты. Эти «служебные» таблицы могут быть очень полезны для упрощения ваших запросов. Я отредактирую некоторый код в ответ, чтобы включить это.