如何在SQL子查询中处理NULL?

时间:2012-02-22 12:32:24

标签: sql subquery

我把头发拉过来这么简单......

我正在记录会员参加健身俱乐部的天数。默认情况下,我假设会员每天都会参加。当他们生病时,我会记录表中没有的日期和总天数(即DateFromDateEndTotalDays)。缺席的总天数是DateFromDateEnd之间的差异。

现在有时候我不知道会员何时回到健身房。只是他们已经停止参加某一天。因此,DateEndTotalDays未知。因此,总天数是通过取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,它返回null,而不是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的第二部分返回null,因此忽略了第一部分!

非常感谢任何帮助。

由于

4 个答案:

答案 0 :(得分:2)

您可以将其编写为单个查询:

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 :(得分:1)

您是否只猜测第二部分返回null或者您知道吗?因为据我所知,第一部分是返回未定义的东西。

您需要以不同的顺序使用SUM()和ISNULL(),例如:

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

在第二种情况下,您可以使用下一个:

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

这样您就可以在计算/转换之前消除空值。

答案 2 :(得分:0)

问题基本上是在SQL中,计算中的null项导致null

确保结果中无法null

顺便说一下,你的逻辑太复杂了 - 简化它

答案 3 :(得分:0)

也许这是你的解决方案:

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