sql - 连续出现和缺席

时间:2014-12-27 08:21:17

标签: mysql sql

我正在为教堂开发一个考勤监控数据库应用程序,其目的是为每个成员提供连续的出席和缺席。但连续计数将以周为基础

例如,我们每周有3个服务(一个星期一,一个星期三,一个星期五),但这些服务是相同的,(唯一的区别是时间/日期)。所以会员可以参加任何会议(他们可以参加所有会议)

例如,我必须根据周找到每个成员的连续出席和缺席 如果我参加2014年12月的月份是:

     S   M   T   W   T   F   S
W1   -   P   -   P   -   -   -
W2   -   P   -   -   -   -   -
W3   -   P   -   P   -   P   -
W4   -   -   -   -   -   P   -
W5   -   P   -   -   -   -   -

我有5个连续出席 我每周只能计算一次出席率(任何其他出席都会被忽略)

这是表格

tbl_members

member_id  last_name  first_name ... and so on
1          SANTIAGO   JOHN KERNELLE

tbl_service_attendances

att_index  service_date  member_id
1          2014-12-01    1
2          2014-12-03    1
3          2014-12-08    1
4          2014-12-15    1
5          2014-12-17    1
6          2014-12-19    1
7          2014-12-26    1
8          2014-12-29    1

att_index是自动增量

每次参加会员时,我都会使用此查询:

INSERT INTO tbl_service_attendances(service_date, member_id) VALUES('2014-12-29', 1)

如果他们在一周内参加了8项服务,那么tbl_service_attendances将为每一项提供8行(唯一的区别是他们的日期)。但它只算作5个连续出席。 (每周一次)

    S   M   T   W   T   F   S
W1  -   P   -   P   -   -   -
W2  -   P   -   -   -   -   -
W3  -   P   -   P   -   P   -
W4  -   -   -   -   -   -   -
W5  -   -   -   -   -   -   -

在这种情况下,我有2个连续吸收,

我还必须知道连任是否存在

请提前帮助,请提供帮助

到目前为止,我通过循环查询完成了我的目标,但我认为循环多个查询是不可取的

2 个答案:

答案 0 :(得分:1)

首先,这种问题在支持窗口函数的DBMS中更容易处理,但这里有一个可以与MySQL一起使用的想法。让我们首先创建一个视图,以简化问题:

create view wa as select distinct member_id, week(service_date) as wk 
                  from service_attendances; 

我在这里假设我们正在处理一年的数据。如果不是年份必须包含在视图和下面的查询中。

根据这一观点,我们可以创建每周出勤的时间间隔:

select member_id, min(start_wk), end_wk 
from (
    select wa1.member_id, wa1.wk as start_wk, min(wa2.wk) as end_wk 
    from wa as wa1 
    join wa as wa2 
        on wa1.member_id = wa2.member_id 
       and wa2.wk > wa1.wk 
       and not exists ( 
           select 1 
           from wa wa3 
           where wa2.member_id = wa3.member_id 
             and wa3.wk = wa2.wk + 1
       ) 
    group by wa1.wk, wa1.member_id
) as x 
group by member_id, end_wk;

根据您在上面提供的数据,结果是:

+-----------+---------------+--------+
| member_id | min(start_wk) | end_wk |
+-----------+---------------+--------+
|         1 |            48 |     52 |
+-----------+---------------+--------+

可以很容易地从中得出差距。为这个表达式创建另一个视图是最容易的,但MySQL认为这是作弊:

ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause

假设start_wk为1且end_wk为年份为52,您可以使用与上述类似的技术查找每个成员的差距。

希望它有所帮助。

答案 1 :(得分:1)

解决方案是使用会话变量,如此fiddle

select IF (weekn = @prev + @n, 
           IF (@n := @n + 1, @prev, 1),
           IF (@n:=0 OR @prev := weekn, weekn, 2)) start_sequence
from (select distinct week(service_date) as weekn
  from   tbl_service_attendances
  where  member_id = 1
    and  year(service_date) = 2014
    and  month(service_date) = 12
  order by weekn) as presences
JOIN (SELECT @n := 0, @prev := week('2014-12-01')-2) AS setup;

连续几周被序列的第一周数替换。从这里,你可以" group by"在这个查询上,通过start_sequence," count"本周发生的次数,并丢弃仅发生一次的那些。

它还没有返回缺席,但这可以通过

来完成

a)使用您想要的所有周数的查找表进行正确连接

b)使用负周数表示缺席数周