2010-07-07 68 views
3

我们有一个运动训练营,经常有城市的各个团队参加。我们每天都有一场会议,时间跨度为2小时(上午9-11点),而且不同团队的时段可能会有所不同。我们想每天捕捉参加训练营的人员。什么是优化模式以获取考勤数据的最佳方式

我们到了以下模型以捕捉出席。 (id,user_id,date,present)。假设用户每天都参加露营(比如说一个月内30天),那么您会在数据库中看到很多记录。

假设我们只是想知道用户参加阵营的天数,有没有更好的方法来标记是否存在特定的用户(也许只有一个月的一个行,并标记所有(P,P,P,A,...,A,P)P =当前,A =缺席

回答

1
AttMst 
    id | date 

AttDet 
    attdetid | id | userid 

通过这种方式,您需要将日期存储在AttMst中,当天的用户将存储在AttDet中。

+0

正在转向这种模式。你如何查询一个月的所有用户出勤记录?你将如何加入AttMst表? – Sam 2010-07-07 09:24:03

+1

'select date,userid from AttMst am,AttDet ad where am.id = ad.id group by date'这将显示日期现在的用户。但它是未经测试的查询请检查它。 – Himadri 2010-07-07 09:39:42

0

恕我直言,每个用户每月有一个单行与大量连接字符不会比拥有大量带有单个字符的行更好,尤其是当您要在每次想要在另一个应用程序上显示数据时分割该字符串。

如果你只是想弄清楚数量用户参加你的营地的日子,为什么不专门为此创建一个表格?每次您记录用户出席时,您只需通过增加用户参加的天数来更新该表。因此,这个值不会被即时计算,它不应该给你任何性能问题。

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

id | user_id | date | present 

user_id | month | attendance 

您应该对USER_ID领域的一些指标还有,为了提高系统的性能。

干杯

+0

假设次表将用于每当被标记时递增或递减。所以你建议不要用数字(*)机制来达到玩家在场的总天数。我对么? – Sam 2010-07-07 09:36:06

+1

是的,主要是因为它可能会导致性能问题。但是,如果你有一个快速的服务器或不期望大量的用户,那么计数机制是好的。 无论哪种方式,忘记串接。 – 2010-07-07 10:05:37

2

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

有一些可能性,但很可能您的数据库架构不会完全标准化。

所以首先:你想达到什么目的?这是什么原因?

一些可能性:

  • 一些DBMS提供能力 创建用户定义类型
  • 你可以使用按位的方法(在MySQL最简单的方法是使用the SET datatype

但是,您目前遇到的问题是什么,因为找出某人出席的天数只不过是加入适当的表格,并与计数函数聚合在一起

+0

我同意,一张桌子就够了。数据库服务器速度很快,所以不需要非规范化。 – mb14 2010-07-07 09:22:35

+0

@ mb14但是当数据量很大时,对数据进行归一化将会有所帮助。 – Himadri 2010-07-07 09:28:33

+0

我不确定我们是否需要很多行来捕获考勤信息(如果您查看带有此类信息的Excel表,它就像一个网格,并且您有一整个月对用户的值,一天中的所有天月)。我试图模拟这一点。我同意这样一个事实,即在逗号分隔列表中标记是否存在玩家会很痛苦 – Sam 2010-07-07 09:32:45

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不是最好的主意。

相关问题