优化模式以捕获考勤数据的最佳方法是什么

时间:2010-07-07 08:47:18

标签: database-design scheduling time-and-attendance

我们有一个运动训练营,该城市的各个团队定期参加。我们每天有一个会话,时间跨度为2小时(上午9-11点),不同团队的时段可能会有所不同。我们希望了解每天参加训练营的人员。

我们到达以下模型以捕获出勤率。 (id,user_id,date,present)。假设用户每天参加营地(比如每月30天),您将在数据库中看到许多记录。

假设我们只对找到用户参加营地的天数感兴趣,是否有更好的方法来标记特定用户的存在与否(可能只有一行一个月并标记所有个别日子如(P,P,P,A,...,A,P).P =现在,A =缺席

4 个答案:

答案 0 :(得分:2)

你应该问问自己为什么要那样做。

有一些可能性,但很可能您的数据库架构无法完全规范化。

首先,你想达到什么目的,原因是什么?

一些可能性:

  • 有些DBMS提供了这样的能力 创建用户定义的类型
  • 您可以使用按位方法(在mysql中最简单的方法是使用the SET datatype

但是又一次:你目前的问题是什么,因为找出某人出现的天数只不过是加入适当的表格,并用计数函数汇总

答案 1 :(得分:2)

您在问题标题中使用“优化”一词,而不解释您想要优化的内容

如果您正在谈论查询性能,那么您就没有问题。您可以拥有的记录数量取决于您每天的会话数量(因为只有一个团队可以参加任何给定的会话)。如果你每天运行十次会话,每月三百条记录。如果你每天运行一百个会话,即每月三千条记录。这些不是大量的数据。因此,您通过扭曲数据库设计做出错误的决定,以避免出现性能问题。

您在其中一条评论中提到过电子表格。这不是一个糟糕的设计。沿着最上面一行有会话,旁边有团队,小组显示团队是否出席会议。这些映射到三个数据库表:SESSIONS,TEAMS和交集表TEAM_SESSIONS。当团队参加会议时,您只需要TEAM_SESSIONS中的记录。

作为概念证明,我在Oracle中敲了三张桌子。

SQL> desc teams
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 NAME                                               VARCHAR2(20 CHAR)

SQL> desc sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 SSN_DAY                                            DATE
 SSN_START                                          NUMBER(4,2)
 SSN_END                                            NUMBER(4,2)

SQL> desc team_sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TEAM_ID                                   NOT NULL NUMBER
 SESSION_ID                                NOT NULL NUMBER

SQL>

Oracle 11g中引入的PIVOT功能使得打开矩阵变得简单(不同类型的DBMS将有不同的方法来解决这个问题)。如你所见,三支队伍今天已经预定了会议,没有人想在午餐时间训练,而且Bec United热衷于芥末(或需要训练)!

SQL> select * from (
  2      select t.name as team_name
  3             , trim(to_char(s.ssn_start))||'-'||trim(to_char(s.ssn_end)) as ssn
  4             , case when ts.team_id is not null then 1 else 0 end as present
  5      from   sessions s
  6             cross join teams t
  7             left outer join team_sessions ts
  8                  on (ts.team_id = t.id
  9                      and ts.session_id = s.id )
 10      where s.ssn_day = trunc(sysdate)
 11      )
 12  pivot
 13      ( sum (present)
 14        for ssn in ( '9-11', '11-13', '13-15', '15-17', '17-19')
 15      )
 16  order by team_name
 17  /

TEAM_NAME                '9-11'    '11-13'    '13-15'    '15-17'    '17-19'
-------------------- ---------- ---------- ---------- ---------- ----------
Balham Blazers                0          1          0          0          0
Bec United                    1          0          0          0          1
Dinamo Tooting                0          0          0          0          0
Melchester Rovers             0          0          0          1          0

SQL>

无论如何,这种数据模型的优点在于它具有灵活性。我们可以计算团队参加的频率,他们参加的时间,他们参加的一周中的哪一天,总是预订的会话,很少预订的会话等等。此外,管理数据也很容易。特别是,三表解决方案优于两个表的优点是更容易防止双重预订和非标准或重叠时隙。

你知道,规范化不仅仅是我们用来愚弄无辜的月亮语言,它提供了真正的实际好处。很少有情况下,至少开车到BCNF不是最好的主意。

答案 2 :(得分:1)

AttMst
  id | date

AttDet
  attdetid | id | userid

通过这种方式,您需要在Att Mst中存储日期,当天的当前用户将存储在Att Det中。

答案 3 :(得分:0)

恕我直言,每个用户每月拥有一行,并且有大量的连接字符,并不比拥有大量单行字符的行更好,特别是如果你不得不拆分它每次要在另一个应用程序上显示数据时都会出现字符串。

如果您只想弄清楚用户参加营地的天数,为什么不专门为此创建一个表?每次您记录用户的出勤时,您只需要通过增加用户参加的天数来更新该表。因此,此值不会即时计算,也不会给您带来任何性能问题。

所以,我的建议包括两个表:

id | user_id | date | present

user_id | month | attendance

你也应该在user_id字段上有一些索引,以提高系统的性能。

干杯