我有一个名为Trucks
的表格,其中包含两个日期列:Arrival
和Released
。我可以像这样计算这些日期之间的平均天数:
SELECT avg(julianday(released) - julianday(arrival))
FROM Trucks
但是,我只想计算工作日 - 也就是说,我想忽略星期六和星期日。在SQLite中有什么办法吗?我已经看到了更强大的RDBMS(如Oracle和MSSQL)的解决方案,但没有一个适用于SQLite。
答案 0 :(得分:3)
天数的原始差异必须根据{仅} arrival
和released
天的工作日进行调整:
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
这个数字可以用一个简单的表达式计算(这里:内部CASE表达式):
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。)
答案 1 :(得分: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))
仅用于测试目的,以表明新计算的平均值实际上小于两个日期之间差异的平均值。)
答案 2 :(得分: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')