2013-11-01 53 views
0

我有一个表Trucks与两个日期列:ArrivalReleased。我可以计算天的这些日期之间的平均数字,像这样:SQLite:获取两个日期之间的平均工作日

SELECT avg(julianday(released) - julianday(arrival)) 
FROM Trucks 

不过,我只想计算平日 - 那就是,我想忽略星期六和星期日。有没有办法在SQLite中做到这一点?我已经看到了更健壮的RDBMS(如Oracle和MSSQL)的解决方案,但没有一个适用于SQLite。

回答

3

在天的原始差异必须进行调整取决于(只)上的arrivalreleased天一周天:

rel arr|0 1 2 3 4 5 6 
-------+-+-+-+-+-+-+- 
    0 |2 0 0 0 0 0 1 
    1 |2 2 0 0 0 0 1 
    2 |2 2 2 0 0 0 1 
    3 |2 2 2 2 0 0 1 
    4 |2 2 2 2 2 0 1 
    5 |2 2 2 2 2 2 1 
    6 |2 2 2 2 2 2 2 

此号码可以用一个简单的表达(在此计算:内壳体表达):

SELECT 
AVG(julianday(released) - julianday(arrival) - 
    CASE WHEN julianday(released) = julianday(arrival) THEN 0 
    ELSE (CAST((julianday(released) - julianday(arrival))/7 AS INTEGER) * 2 
     ) + 
     CASE WHEN strftime('%w', arrival) <= strftime('%w', released) THEN 2 
      ELSE strftime('%w', arrival) = '6' 
     END 
    END) 
FROM trucks 

(如x='6'返回0或1)

+0

心=吹。这将我的635行查询减少到97行。 (周末的逻辑会在更大的查询中重复使用几次。)谢谢! – penco

+0

作为一个轻微的附录,我不得不围绕AVG()语句包装'MAX()',因为由于四舍五入问题我偶尔会得到负数。所以它最终成为'MAX(AVG(...),0)'。 – penco

1

好吧,我想出了一个非常混乱的解决方案,使用大量嵌套的CASE语句。它会检查工作日号码released,然后检查工作日号码arrival并进行计算以确定已经过了多少个星期。在此之后,我添加0,1或2作为这两天之间必须经过的周末天数的基数(即从周五到周一始终为+2个周末日,即使经过了不到一整周的时间日期)。

这是,如果有人认为它有用。很可能是我写过的最丑陋的SQL。如果有人想出更好的办法,请告诉我。

(编辑基于CL的反馈简洁)

SELECT 
avg(
julianday(released) - julianday(arrival) - 

CASE WHEN julianday(released) = julianday(arrival) THEN 0 ELSE 
CASE strftime('%w', released) 
WHEN '0' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '1' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2) 
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '2' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)    
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)    
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)  
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '3' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)    
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)    
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '4' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 0)   
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '5' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 1) 
END 
WHEN '6' THEN 
CASE strftime('%w', arrival) 
WHEN '0' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)  
WHEN '1' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)   
WHEN '2' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '3' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '4' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '5' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2)    
WHEN '6' THEN ((cast((julianday(released)-julianday(arrival))/7 as int) * 2) + 2) 
END 
END 
END 

), avg(julianday(released)-julianday(arrival)) 
from trucks 

(注:avg(julianday(released)-julianday(arrival))末只是出于测试目的,以表明新计算出的平均值实际上是在小于直接平均值的两个日期之间的差异)。

+1

A [CASE表达式](http://www.sqlite.org/lang_expr.html#case)可以有多个WHEN分支。在这种情况下,要测试的表达式可以在CASE和WHEN之间写一次。 –

+0

谢谢!我重构了代码以使用分支CASE结构。现在更容易管理。 – penco

0

布尔表达式我发现这个职位搜索时看看SQLite是否有周日的功能。如果您使用最高的答案,那么您一周中的天数可能不会很稳定。这是我用于我的项目,其计算在Spiceworks还在票据建立和封闭之间的工作日的代码:

SELECT t.id 
,t.summary 
,t.category 
,u.email 
,(CAST(strftime('%j', t.closed_at) as INTEGER) - CAST(strftime('%j', t.created_at) as INTEGER) - /*I can't figure it out, but julianday() wasn't giving me the correct distances for some numbers. I used the day of the year, instead, which resolved things as expected*/ 
    CASE              
    WHEN CAST(strftime('%W', t.closed_at) as INTEGER) - CAST(strftime('%W', t.created_at) as INTEGER) = 0 THEN 0 /*If they are in the same week then there is no weekend to count. If you closed a ticket, that was opened on a Monday, on Saturday, then you must of worked on Saturday and therefore counts as work day the same as if you finished it on Monday*/ 
    WHEN CAST(strftime('%w', t.created_at) as INTEGER) = 0 THEN (CAST(strftime('%W', t.closed_at) as INTEGER) - CAST(strftime('%W', t.created_at) as INTEGER)) * 2 - 1 /*If they made their ticket on Sunday, don't count that Sunday*/ 
    WHEN CAST(strftime('%w', t.created_at) as INTEGER) = 6 THEN (CAST(strftime('%W', t.closed_at) as INTEGER) - CAST(strftime('%W', t.created_at) as INTEGER)) * 2 - 2 /*If they made their ticket on Saturday, don't count that Saturday*/ 
    ELSE (CAST(strftime('%W', t.closed_at) as INTEGER) - CAST(strftime('%W', t.created_at) as INTEGER)) * 2 /*Ignoring the possibility for closed dates that happen before open dates, take the number of weeks between each date and assume each had a Saturday and Sunday within them*/ 
    END) as 'Week Days Elapsed' /*This equation in full represents: Full_Distance_In_Days_Between - Number of weekend days calculated*/ 
    FROM Tickets as t 
    LEFT JOIN Users as u 
    on t.created_by = u.id 
    WHERE strftime('%Y-%m', t.created_at) = strftime('%Y-%m', 'now') 
相关问题