我在一家制造业同事轮班工作的公司工作。换挡系统可能每个月都不同。所以这些人可能只在晚上工作一周,但下周早,晚,晚。
现在我有了一个数据库,在那里我可以看到,同事们每天都在制作什么。基本上,我只能看到轴承运动。从理论上讲,我现在可以说“好吧,在2017-04-27,他们分三班工作,因为我们在上午6:00到下午2:00,下午2:00 - 晚上10:00和晚上10:00 - 6之间进行轴承运动:今天00点“。每小时有数百次轴承运动。
我现在要做的是:我想知道这些人每个月工作了多少班次。所以最好的结果是如果我能得到一个查询,它给了我月份数和下一列本月的班次数量。
我想查询必须检查一个月中的每一天,并检查每个可能的班次是否有条目,如果是,则计算一个计数器或其他东西。
表-架构:
TABLE_NAME lb
COLUMN_NAME DATA_TYPE
id int
date_ datetime
time_ time
doc varchar
pgroup int
piece varchar
amount decimal
name1 varchar
name2 varchar
name3 varchar
storage_location int
bs varchar
hash varchar
inserted datetime
edited datetime
示例数据(仅来自列ID,日期_,时间_)
ID date_ time_
1 2017-02-06 00:00:00.000 10:05:34.0000000
2 2017-02-02 00:00:00.000 09:15:31.0000000
3 2017-02-02 00:00:00.000 16:19:12.0000000
4 2017-01-30 00:00:00.000 14:15:01.0000000
5 2017-01-30 00:00:00.000 21:35:10.0000000
6 2017-01-31 00:00:00.000 05:33:20.0000000
7 2017-01-31 00:00:00.000 05:36:07.0000000
8 2017-01-31 00:00:00.000 14:33:56.0000000
9 2017-01-30 00:00:00.000 06:25:25.0000000
10 2017-01-30 00:00:00.000 10:05:29.0000000
11 2017-01-30 00:00:00.000 15:25:26.0000000
12 2017-01-30 00:00:00.000 17:35:29.0000000
13 2017-01-30 00:00:00.000 21:05:26.0000000
14 2017-01-31 00:00:00.000 00:45:44.0000000
15 2017-01-30 00:00:00.000 08:15:25.0000000
16 2017-01-30 00:00:00.000 10:05:32.0000000
17 2017-01-30 00:00:00.000 15:25:29.0000000
18 2017-01-30 00:00:00.000 17:35:32.0000000
19 2017-01-30 00:00:00.000 21:05:30.0000000
20 2017-01-31 00:00:00.000 00:45:53.0000000
基于样本数据的输出:
month shifts
2 3
1 4
这可能吗?
答案 0 :(得分:0)
你可以尝试这样的事情。
SELECT monthday AS "month", COUNT(monthday) AS "shifts" FROM
(SELECT date_trunc( 'month', date ) FROM
(SELECT DISTINCT date FROM lb
WHERE '06:00:00'::time <= time AND time < '14:00:00'::time
UNION ALL
SELECT DISTINCT date FROM lb
WHERE '14:00:00'::time <= time AND time < '22:00:00'::time
UNION ALL
SELECT DISTINCT date FROM lb
WHERE '22:00:00'::time <= time AND time < '06:00:00'::time
) shiftdays
) monthdays (monthday) GROUP BY monthday;
(出于移动原因,我没有时间检查语法是否正确)。 此外,这是PostgreSQL语法,使其适应您的SQL方言。
它是如何运作的? 这件作品选择了第一班的所有日子。每天只有一次(DISTINCT)。
SELECT DISTINCT date FROM lb
WHERE '06:00:00'::time <= time AND time < '14:00:00'::time
其他班次也一样。 然后这三个班次的日子被扔到同一个碗里。 如果你在同一天投两次,它也会在碗中两次(UNION ALL;我不想说组,因为GROUP在SQL中已经有不同的含义)。
现在我们有一天可以看到一年中所有可能的日子(或者至少是表格中的所有天数)。每天显示0 <= n <= 3
次,每天最多可计入3个班次,由临时表中的3天表示。
现在我们离开像2017-01-15&#39;使用date_trunc( 'month', date )
到月份(每天= 01)。
我们现在只能做到这一点,因为如果我们早点尝试,那么我们每天都不能阻止超过三班,这在假想碗中至少有三天。
最后,既然我们将日期与几个月对齐,我们就可以分组并使用count(*) = shifts
。
表别名shiftdays
和monthdays
是必需的,以免DBMS抱怨。
使用date_trunc(&#39; day&#39;,date)去除日期时间内的任何秒数(如果需要,上面没有显示;如果你的日期时间有毫秒不是0000)。
使用date_trunc(&#39; month&#39;,date)将所有日期减少到当月,然后计算它们。
确保列上有一个索引(时间,日期)(按此顺序;时间需要与范围&lt; =和&lt ;;和datetime一起用于同一索引上才能进行INDEX ONLY SCAN,因为你不要希望DMBS从堆中加载10列的元组。
三个班次的三个索引仅扫描应该没问题。
全表扫描可能是不可接受的。
您还可以混合使用一些WHERE
条款来获取单个月的轮班计数,即WHERE '2017-01-01' <= date AND date < '2017-02-01'
。索引(日期,时间)应该非常快。
另请注意上面的左包含范围(l&lt; = date AND date&lt; without = r)。
所以是的,这是可能的。适应它,你很高兴。