有条件地选择一列(奇怪的结果)

时间:2014-07-15 09:10:16

标签: sql sql-server-2008

在SQL请求中,我计算了一些东西。这个微积分需要一个表(DurationsLog)不为空(表必须包含行)。

所以我正在尝试处理这个表为空的情况。

所以我尝试在select中使用CASE来处理它但它不起作用(当DurationsLog为空时得到0行)。

以下是请求:

SELECT 
   o.Maint,
   CASE 
      WHEN EXISTS(SELECT * FROM DurationsLog)  
        THEN DATEADD(day, (p.CycleDuration - (c.TotalRotationCounter - o.LastActionCounter)) / AVG(d.RotationDuration), GetDate())  
        ELSE 'CALCUL IMPOSSIBLE'  
   END AS CalculProchaineDate
FROM 
   dbo.Operations o  
INNER JOIN 
   dbo.Periods As p ON o.PeriodId = p.Id,
    dbo.Counters c,  
    dbo.DurationsLog d  
WHERE 
   p.CycleDuration>0  
GROUP BY 
   o.Maint, p.CycleDuration, c.TotalRotationCounter, o.LastActionCounter

注意:DurationsLog没有加入另一个表

NB bis:当DurationsLog包含行时,它正常工作

注意3:SQL系统是Microsoft SQL Server 2008

编辑:好像我没有很好地解释我的问题,我会详细介绍一下:

dbo.Operations表包含有关维护操作的信息。它的主键是“Maint”,它在dbo.Periods表中包含一个外键“PeriodId”。

dbo.Periods表包含一个Id作为主键和一个用于微积分的字段“CycleDuration”

dbo.Counters没有主键。它包含机器使用的总计数器(它旋转了多少小时,产生......),这个表总是只包含一行

dbo.DurationsLog包含一个主键,它是一个日期。该表存储了我们的机器今天旋转和生产的时间。所以这个表包含一行/天

来自Periods的“CycleDuration”存储两次操作之间的时间(以小时为单位)(例如:我们需要每4000小时清理x,CycleDuration将为4000)

我们在上次执行此操作时存储在Operations表中。所以我估计下一次操作什么时候需要执行。

这就是我计算的原因:CycleDuration - (我上次执行操作的计数器)/每天的平均持续时间。有了这个,我可以估计下一次行动何时进行。

1 个答案:

答案 0 :(得分:0)

原因是,当DurationsLog表为空时,INNER JOIN将始终为空 正是在这里:

   INNER JOIN 
       dbo.Periods As p ON o.PeriodId = p.Id,
        dbo.Counters c,  
        dbo.DurationsLog d 

CountersDurationsLog和查询的其余部分之间没有连接条件。

解决方案是预先计算必要的值,而不是自己加入表格:

declare @AvgDuration float;
select 
  @AvgDuration = AVG( d.RotationDuration )
from dbo.DurationsLog d;

declare @TotalCounter int;
select 
  @TotalCounter = c.TotalRotationCounter
from dbo.Counters;

SELECT 
   o.Maint,
   CASE 
      WHEN @AvgDuration IS NOT NULL
        THEN DATEADD(day, (p.CycleDuration - 
             (@TotalCounter - o.LastActionCounter)) 
              / @AvgDuration, GetDate())  
        ELSE 'CALCUL IMPOSSIBLE'  
   END AS CalculProchaineDate
FROM 
   dbo.Operations o  
INNER JOIN 
   dbo.Periods As p ON o.PeriodId = p.Id
WHERE 
   p.CycleDuration>0  
GROUP BY 
   o.Maint, p.CycleDuration, o.LastActionCounter;