Как обрабатывать NULL в подзапросе SQL? - PullRequest
0 голосов
/ 22 февраля 2012

Я дергаю себя за такую ​​простую вещь ...

Я записываю количество дней, когда член посещает спортзал.По умолчанию я предполагаю, что участник посещает каждый день.Когда они болеют, я записываю даты и общее количество дней, отсутствующих в таблице (то есть DateFrom, DateEnd, TotalDays).Общее количество отсутствующих дней - это разница между DateFrom и DateEnd.

Теперь иногда я не знаю, когда участник возвращается в спортзал.Просто они перестали посещать в определенный день.Следовательно, DateEnd и TotalDays неизвестны.Таким образом, общее количество дней рассчитывается с учетом разницы между DateFrom и сегодняшней датой.

Table: InactiveOnProgram
Columns: PersonId, DateFrom, DateEnd, TotalDays

Данные:

1,01/01/2012,05/01/2012,5 
1,05/01/2012,08/01/2012,3
2,01/02/2012,05/02/2012,5 
2,05/02/2012,08/02/2012,3
2,20/02/2012,null,null

Мой запрос ниже работает нормальнодля personId = 2.Общее количество отсутствующих дней составляет 8 + 2 = 10 дней (2 дня с 20.02.2012 по 22.02.2012 = сегодня).Но для personId = 1 он возвращает ноль вместо 8 дней!

sql:

(SELECT   
    case (  isnull(sum(TotalDays), 0) ) 
        when 0 then 0
        else CAST(SUM(TotalDays)  as DECIMAL(20,2))
    end 
FROM InactiveOnProgram  
)    
+   
(SELECT 
    case (  isnull( DateFrom, 0) ) 
        when null then 0
        when 0 then 0
        else CAST(datediff(day,DateFrom, getdate()) as DECIMAL(20,2))
    end  
FROM  InactiveOnProgram   
WHERE (TotalDays is null or TotalDays =0) 
AND  DateTo is null 
)

Есть идеи, что мне здесь не хватает ?!Насколько я могу догадаться, вторая часть sql возвращает ноль и поэтому игнорирует первую часть!

Любая помощь очень ценится.

Спасибо

Ответы [ 4 ]

2 голосов
/ 22 февраля 2012

Вы можете написать это как один запрос:

declare @InactiveOnProgram table
(PersonId int, DateFrom datetime, DateEnd datetime, TotalDays int)

insert into @InactiveOnProgram (PersonId , DateFrom , DateEnd , TotalDays)
select 1,'20120101','20120105',5 union all
select 1,'20120105','20120108',3 union all
select 2,'20120201','20120205',5 union all
select 2,'20120205','20120208',3 union all
select 2,'20120220',null,null

select PersonId,SUM(COALESCE(TotalDays,DATEDIFF(day,DateFrom,CURRENT_TIMESTAMP)))
from @InactiveOnProgram group by PersonId

Я не очень доволен хранением TotalDays, но, учитывая ваш набор данных, это кажется необходимым, поскольку, по-видимому, с 1 по 5 = 5 дней, но с 5 по 8 = 3 дня.

1 голос
/ 22 февраля 2012

Вы только предполагаете, что вторая часть возвращает ноль, или вы это знаете?Потому что, насколько я вижу, первая часть возвращает что-то неопределенное.

Вам нужно использовать SUM () и ISNULL () в другом порядке, например:

select cast(sum(isnull(TotalDays, 0)) as decimal(20,2)) as totdays

И во второйЕсли вы можете использовать следующее:

datediff(day, isnull(DateFrom, getdate()), getdate())

Таким образом, вы можете исключить нулевые значения перед вычислением / преобразованием.

0 голосов
/ 22 февраля 2012

Может быть, это ваше решение:

select personid, sum( closed + unclosed) 
from (
    SELECT personid
    , CAST(SUM(isnull(nullif(TotalDays,0),0)) as DECIMAL(20,2)) as closed
    , case when min(isnull(nullif(DateFrom,0),0))=0 OR (SUM(isnull(nullif(TotalDays,0),0)) >0 AND min(isnull(nullif(dateend,0),0)) >0)  then 0 else min(CAST(datediff(day,DateFrom, getdate()) as DECIMAL(20,2)))  end  as unclosed
    FROM test 
    group by personid
    --WITH ROLLUP 
) as test
group by personid
WITH ROLLUP 
0 голосов
/ 22 февраля 2012

Проблема в основном в том, что в SQL термин null в вычислениях приводит к null.

Убедитесь, что null невозможно в ваших результатах.

КстатиВаша логика слишком сложна - упростите ее

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...