基于轴承移动的查询 - 他们工作了多少班次?

时间:2017-04-27 05:15:05

标签: sql sql-server

我在一家制造业同事轮班工作的公司工作。换挡系统可能每个月都不同。所以这些人可能只在晚上工作一周,但下周早,晚,晚。

现在我有了一个数据库,在那里我可以看到,同事们每天都在制作什么。基本上,我只能看到轴承运动。从理论上讲,我现在可以说“好吧,在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

这可能吗?

1 个答案:

答案 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。 表别名shiftdaysmonthdays是必需的,以免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)。

所以是的,这是可能的。适应它,你很高兴。