【问题标题】:How to design a data model that deals with the current employees and forecasted employees?如何设计一个处理当前员工和预测员工的数据模型?
【发布时间】:2012-04-27 20:53:34
【问题描述】:

我们正在创建一个应用程序来管理员工。员工可以是当前员工,也可以是未来将加入的员工(预测)。

除了管理员工外,我们还必须按月管理预测。

假设今天是四月,

截至 4 月 26 日,当前员工人数为 100。

今天,我预计 8 月将有 10 人加入。 20 将于 11 月加入。

当我说我预测时,我实际上会在系统中添加 10 和 20 名员工。我可能有也可能没有完整的信息。我什至可能没有名字,因为他们还没有被雇用。但我只是预测,8 月将有 10 名员工,11 月将有 20 名员工,与 4 月一样。

假设中间没有更多的离开者或加入者。我的员工人数到 8 月底将达到 110 人,到 11 月底将达到 130 人。

所以,8 月的 110 和 11 月的 130 是我对 4 月份的预测。

现在,我在 5 月得知,在 8 月加入的不是 10 名,而是只有 5 名,而在 11 月,将有 25 名加入,而不是 20 名,而且我们将在 12 月解雇 10 名现有员工。

所以我的员工人数预计在 5 月将是 8 月的 105 人、11 月的 130 人和 12 月的 120 人。

因此,我需要按月保存员工数据,即我在 4 月对未来每个月(即从 5 月到 12 月)的预测。

再次,我对 8 月到 12 月的预测是什么。

等等。

我还需要记住,现有员工的数据可能每分钟都在不断变化。

他们的头衔可能会改变,地址可能会改变,部门等。

因此,如果员工 A 在 4 月在 D1 部门,在 4 月之后在 D2 部门。

当我提取 4 月的报告时,它应该显示我为 D1,当我提取 6 月的报告时,它应该显示我他的部门为 D2。

请帮忙。


this previous question 中有一些额外的背景。

编辑:

请看下图。

我想知道每个后续月份中 3 月(For Month = March)预测的员工人数,即 for month = March ,3 月计数 = 400,4 月计数 = 405。

括号中的数字显示将在该月加入的新员工,例如(+10) & (-5) 显示当月离职的员工。因此,如果 3 月份员工总数为 400 人,4 月份有 10 人加入,5 人离职,那么 4 月份的总人数将是 405 人。

【问题讨论】:

  • 您真的应该阅读常见问题解答。 SO 的目的是为更广泛的互联网社区提供高质量答案的永久来源。坦率地说,没有人关心你是否迫切需要这个。
  • @Ashish,如果这很紧急,您应该考虑聘请顾问来提供帮助,而不是等待 SO 社区的善意。 (虽然我自己是一名顾问,但我有点偏见)。

标签: oracle database-design


【解决方案1】:

我可以看到您需要两个表的几个原因:

  • 真实员工必须有姓名、部门等,而预测员工可能只有这些属性
  • 会有一些只有真正的员工才能拥有的职责,因此您希望能够单独引用它们

但同时您要确保两个表之间的 ID 没有冲突,因为(希望)预测员工将成为实际员工。

实现这一点的方法是实现一个超类型/子类型结构。因此,您有一张表,即 EMPLOYEES,它保证单个主键,以及两张用于实际和预测员工的相关表。类型列的使用至关重要,因为它确保给定的员工只出现在一个子表中。

create table employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , constraint emp_pk primary key (emp_id)
      , constraint emp_uk unique (emp_id, emp_type)
      , constraint emp_type_ck check (emp_type in ('FORECAST', 'ACTUAL'));

create table actual_employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , name varchar2(30) not null
      , deptno number(2,0) not null
      , sal number(7,2) not null
      , hiredate date not null
      , constraint actemp_pk primary key (emp_id)
      , constraint actemp_type_ck check (emp_type = 'ACTUAL')
      , constraint actemp_emp_fk foreign key (emp_id, emp_type)
                   references emp (emp_id, emp_type) 
                   deferrable initially deferred ;

create table forecast_employees
    ( emp_id number not null
      , emp_type varchar2(8) not null
      , name varchar2(30) 
      , deptno number(2,0) 
      , sal number(7,2) 
      , predicted_joining_date date
      , constraint foremp_pk primary key (emp_id)
      , constraint foremp_type_ck check (emp_type = 'FORECAST')
      , constraint foremp_emp_fk foreign key (emp_id, emp_type)
                   references emp (emp_id, emp_type) 
                   deferrable initially deferred ;

所以键可能看起来有点奇怪。父表同时具有主键和复合唯一键。主键保证 EMP_ID 的单个实例。唯一键允许我们在引用 EMP_ID 和 EMP_TYPE 的子表上构建外键。结合对子 t 的检查约束 这是因为它们引用父表上的唯一键而不是其主键。这种安排能够确保员工可以在 FORECAST_EMPLOYEES 或 ACTUAL_EMPLOYEES 中,但不能同时在两者中。

外键可延迟,以允许将预测员工转换为实际员工。这需要三个活动:

  1. 从 FORECAST_EMPLOYEES 中删除记录
  2. 将记录插入 ACTUAL_EMPLOYEES
  3. 在 EMPLOYEES 中更改 EMP_TYPE(但不是 EMP_ID)。

使用延迟约束更容易同步操作 2 和 3。

另外,请注意引用 EMPLOYEES 的其他外键约束应该使用主键而不是唯一键。如果关系关心员工的类型,那么它可能应该链接到子表。


“有点头疼”

欢迎来到数据建模的世界。这是一个很大的头痛。因为试图将混乱的现实融入干净的数据模型是困难:你需要明确的要求才能让它正确,并了解最重要的事情,这样你才能做出明智的妥协。

我根据您的另一个问题提出了一种超类型/子类型的方法,因为这似乎是处理两组数据的最佳方法:真实员工和名义员工。我认为这两个群体需要区别对待。例如,我会坚持认为经理是真正的雇员。这很容易通过针对 ACTUAL_EMPLOYEES 的完整性约束来实现,而使用包含两种类型员工的单个表则更难实现。

确定有两个表意味着在同步它们的结构方面可能会产生更多的工作。所以呢?这在很大程度上是微不足道的,因为编写两个 ALTER TABLE 语句的工作量几乎不比一个多。此外,新列很可能仅适用于实际员工,对预测员工没有意义(例如 EARNED_COMMISSION、LAST_REVIEW_RATING)。鉴于此,拥有单独的表可以使数据模型更加准确。

关于必须复制依赖表,正如 Ollie 指出的那样,这是一种误解。适用于所有员工的表,无论其实际情况如何,都应该引用 EMPLOYEES 表而不是其子表。

最后我不明白为什么使用两张表比一张表更难维护历史数据。大多数日志代码应该完全从数据字典中生成。


"如果我有 Employee 表和 Employee_forecast 表..."

三个表:

  • EMPLOYEES - 保证唯一 EMP_ID 的主表
  • ACTUAL_EMPLOYEES - 为贵公司工作的人员的子表
  • FORECAST_EMPLOYEES - 您希望招募到公司的人员的子表

"...他们的产品或活动都将存储在一个单一的 产品/活动表?”

请记住,我是根据您提供的少量详细信息对您的业务逻辑做出假设。

现在在我看来,尚未为贵公司工作的人不应该有任何相关活动。在这种情况下,您将拥有一个表 EMPLOYEE_ACTIVITIES,它是 ACTUAL_EMPLOYEES 的子表。

但也许您确实为不存在的人提供活动。所以这里有一个选择:一张还是两张?单表设计将 EMPLOYEE_TASKS 作为主 EMPLOYEES 表的子表。这两个表设计分别将 ACTUAL_EMPLOYEE_TASKS 和 FORECAST_EMPLOYEE_TASKS 作为 ACTUAL_EMPLOYEES 和 FORECAST_EMPLOYEES 表的子表。

哪种设计是正确的取决于您是否需要强制执行有关任务分配的规则。例如,您的公司可能有一条规则,规定只有真人才能雇用新员工。因此,拥有一个只允许将招聘任务分配给 ACTUAL_EMPLOYEES 的模型会很有用。


"这个设计没有考虑按月 预测”

好的,我已经在两个表中添加了日期列。这将允许您运行所需的报告。

【讨论】:

  • 我可能还为每种员工类型提供了一些参考表。说employee_products。所以我需要为实际员工准备两张单独的表格,然后为预测员工准备一张。如果将来我向实际员工添加一个参考表,我还必须将其添加到预测表中。另外,如果实际员工中有一些列更改,我将不得不使它们与预测表保持同步。另外,这些表的更改需要审核,因为我还需要维护历史数据。如果我把它们分开,那就有点头疼了。你有什么建议?
  • @Ashish,如果它们只是参考表,那么将它们链接到EMPLOYEE 表,我认为没有理由专门为每个EMPLOYEE 表提供参考表。如果您需要添加员工列,那就另当别论了。
  • @APC,为此 +1....“欢迎来到数据建模的世界。这是一个令人头疼的问题”:-)
  • @APC 所以你的意思是说如果我有 Employee 表和 Employee_forecast 表,他们的产品或活动都将存储在一个产品/活动表中?
  • @APC 此外,正如我在问题中所说,这种设计没有考虑按月预测。这不仅仅是为实际和预测员工提供唯一的 ID。而且还关于每月获得实际和预测员工的所有信息。即 3 月(4 月、5 月、... 12 月)预测的所有员工(两者)计数,4 月(5 月、6 月、7 月... 12 月)预测的所有员工(两者)计数) 等等。例如根据 3 月的 4 月计数 = 400,5 月 = 410,6 月 = 430,但按 4 月计算,5 月 = 405,6 月 = 440。
【解决方案2】:

我认为您的数据模型将取决于您需要报告的信息。 例如,我倾向于使用标准的 EMPLOYEEDEPARTMENT 表(如 Oracle 默认的 SCOTT 架构)。

我还会有一个状态列,您可以在其中表示员工是当前员工或潜在员工,从而允许您报告当前雇用和预测雇用。您可以根据员工的状态等围绕需要哪些列添加功能约束/业务规则。因此当前员工将有全名、出生日期等,而潜在员工可能没有。

然后,我还将创建一个审计表来跟踪 EMPLOYEE 记录所经历的更改。这将允许您追溯查找他们的部门更改以及记录员工何时从潜在员工更改为当前员工等,以及对 EMPLOYEE 记录中其他数据的任何更改。
它还具有将所有数据保存在一个位置的优势。如果需要,您还可以考虑使用状态列对 EMPLOYEE 表进行分区。

这将为您带来好处,即在您申请的各个就业阶段的整个过程中,每位员工只需向他们颁发一个 ID。

状态栏的另一个好处是,您可以随后根据需要介绍员工可能经历的任何其他阶段。

编辑:

这也将确保如果您将来需要添加列,您只需要支持一个表结构。

【讨论】:

    【解决方案3】:

    我会这样做: Employee 和 Department 表是典型的,但 emp 表中没有 dept_id 有一个 emp_dept 表来表示员工和部门之间的多对多,并具有关系的生效日期或生效日期范围。 对于 perspective_employees,我会推荐一个单独的表格,其中包含日期,然后在您需要该信息时与雇员表格合并。

    在这里很难得到真正的详细信息,但我希望你能理解我所说的基本内容。

    问候, 罗杰

    【讨论】:

    • 感谢您的回复。但我的员工表可能有 20 列可能需要像部门一样进行跟踪。比如说城市、州、国家、地区、部门、产品、名称等。那么我是否需要为每一列分别创建一个表格?
    • 那么,在这种情况下,您可以将生效日期或生效日期范围放在员工表中。
    猜你喜欢
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    相关资源
    最近更新 更多