1

编辑:[详细信息]我正在做一个简单的数据库设计任务作为培训练习,我必须为以下情况提出一个基本的模式设计:

我有一个产品的父子层次结构(原材料>正在进行的工作>最终产品)。

订单在每个级别下。

在接下来的 6 个月中,应在每周存储桶中查看订单数量。

可以对每个产品级别进行需求预测。

对未来 6 个月的每周桶进行需求预测。

它通常在层次结构的更高级别(原材料或正在进行的工作)中完成

它必须分解到较低的级别(最终产品)

有两种方法可以将需求预测从较高层次分解到较低层次:

  1. 用户指定最终产品的百分比分布。说,有 1000 的预测工作正在进行中.. 用户说我想要 40% 的最终产品 1 和 60% 的最终产品 2 在桶 10.. 然后从现在开始的第 10 周(周日到周六),预测值最终产品 1 为 400,最终产品 2 为 600。

  2. 用户说,只是根据对桶 5 中终端产品的订单进行分解,桶 5 中终端产品 1 和 2 的订单分别为 200 和 800,那么 EP1 的预测值为 ((200/1000) * 100)%对于 EP2,将是“正在进行的工作”预测的 ((800/1000) * 100)%。

未来 6 个月的预测应在每周存储桶中查看,理想的格式应为:

product name | bucket number | week start date | week end date | forecast value

这种要求的基本理想模式是什么?


Product_Hierarchy表可能如下所示:

id  |   name                |   parent_id
__________________________________________
1   |   raw material        |   (null)
2   |   work in progress    |   1
3   |   end product 1       |   2
4   |   end product 2       |   2

这是存储订单的好方法吗?

订单

id | prod_id | order_date | delivery_date | delivered_date

在哪里,

prod_id是引用idproduct_hierarchy 表的外键,

每周26桶的订单可以选择为

SELECT
    COUNT(*) TOTAL_ORDERS,
    WIDTH_BUCKET(
        delivery_date,
        SYSDATE,
        ADD_MONTHS(sysdate, 6), 
        TO_NUMBER( TO_CHAR(SYSDATE,'DD-MON-YYYY') - TO_CHAR(ADD_MONTHS(sysdate, 6),'DD-MON-YYYY') ) / 7
    ) BUCKET_NO
FROM
    orders_table
WHERE
    delivery_date BETWEEN SYSDATE AND ADD_MONTHS(sysdate, 6);

但这将给出从今天开始的每周存储桶,无论哪一天。我希望他们在星期天到星期六星期。

请帮助设计这个数据库结构。

(将使用 Oracle 11g)

4

3 回答 3

1

你最后的评论正是我的意思。很高兴看到你得到它!

自从我开始做以来,我完成了一个示例代码。与您所说的不同之处在于,仅使用一周的日期(即monday)和各种检查约束来区分会改变的和不会改变的(raw_materialVS )。raw_material_hist

CREATE TABLE raw_material 
  ( 
     material_id     NUMBER PRIMARY KEY, 
     material_blabla VARCHAR2(20) 
  ); 

CREATE TABLE wip 
  ( 
     wip_id     NUMBER PRIMARY KEY, 
     parent_raw NUMBER REFERENCES raw_material(material_id), 
     wip_desc   VARCHAR2(20) 
  ); 

CREATE TABLE end_product 
  ( 
     end_product_id NUMBER PRIMARY KEY, 
     parent_wip     NUMBER REFERENCES wip(wip_id), 
     description    VARCHAR2(20) 
  ); 

CREATE TABLE rm_histo 
  ( 
     material_id NUMBER REFERENCES raw_material(material_id), 
     week_start  DATE CHECK (To_char(week_start, 'D')=1), 
     forecast    NUMBER(8) CHECK (forecast >0), 
     CONSTRAINT pk_rm_histo PRIMARY KEY (material_id, week_start) 
  ); 

CREATE TABLE wip_histo 
  ( 
     wip_id            NUMBER REFERENCES wip(wip_id), 
     week_start        DATE CHECK(To_char(week_start, 'D')=1), 
     wip_user_forecast NUMBER(8) CHECK (wip_user_forecast>0), 
     CONSTRAINT pk_wip_histo PRIMARY KEY (wip_id, week_start) 
  ); 

CREATE TABLE end_prod_histo 
  ( 
     end_product_id         NUMBER REFERENCES end_product(end_product_id), 
     week_start             DATE CHECK(To_char(week_start, 'D')=1), 
     end_prod_user_forecast NUMBER(8) CHECK (end_prod_user_forecast >0) 
  ); 

最后,您确实使用视图来查看预测的事物,或者如果您拥有大量数据,则使用物化视图。通过使用视图,您不会复制数据,因此更改/更新更安全、更容易。

对于您的用例 1 或 2,这不涉及数据库模式。归根结底,它只是为预测更新一些值,用例 1 或 2 的逻辑可以进入 PL/SQL 过程或您用于接口的任何内容。

编辑:同样从您的最后一条评论中,您提到手动设置预测值与计算值。所以我添加了这样一个专栏,但学分归你

编辑之二:至于桶号,只需对日期使用适当的掩码,例如IWor WW。这两个变化是一年中的第一周。

于 2013-02-10T19:30:33.163 回答
0

好的,这就是我想出的数据模型。

PRODUCT——存储产品信息,维护父子层次结构

id  NUMBER  "Primary Key Not Null"                  
level_code  VARCHAR2    Not Null                    
name    VARCHAR2    Not Null                    
description VARCHAR2                        
parent_id   NUMBER  Foreign Key references PRODUCT(id)                  

ORDERS -- 存储产品订单

id  NUMBER  "Primary Key Not Null"                  
prod_id     NUMBER  "Foreign Key references PRODUCT(id) Not Null"                   
order_type  VARCHAR2    "Not Null Default 'Default'"
order_qty   NUMBER  Not Null
order_date  NUMBER  Foreign Key references DATE_INFO(date_key)
delivery_date   NUMBER  "Foreign Key references DATE_INFO(date_key)
Check delivery_date >= order_date"

FORECAST - 存储产品的预测值(存储更高级别的值,从父级分解后存储更低级别的值)

id  NUMBER  "Primary Key Not Null"
product_id  NUMBER  "Foreign Key references PRODUCT(id) Not Null"
forecast_value  NUMBER  Not Null
week    NUMBER  "Foreign Key references DATE_INFO(date_key) Not Null"                   

DISAGGREGATION_RULES -- 存储用于将值从较高级别分解到较低级别的方法以及分配到较低级别的百分比

id  NUMBER  "Primary Key Not Null"
parent_product_id   NUMBER  "Foreign Key id references PRODUCT(id) Not Null"
child_product_id    NUMBER  "Foreign Key id references PRODUCT(id) Not Null"
method  VARCHAR2    Not Null                    
from_week   NUMBER  "Foreign Key references DATE_INFO(date_key) Not Null"
to_week NUMBER  "Foreign Key references DATE_INFO(date_key) Not Null Check end_week >= start_week"
percent_distribution    NUMBER  Not Null                    

DATE_INFO -- 日期维度,包含有关开始日期(必须是星期六)和结束日期的信息,对应于特定日期所在的周

date_key    NUMBER  "Primary Key
Not Null"                   
full_date   DATE    Not Null                    
week_begin_date DATE    Not Null                    
week_end_date   DATE    Not Null

至于桶数/周的事情..我正在使用以下函数计算周开始日期(在我的情况下是星期六的日期)

CREATE OR REPLACE FUNCTION get_week_start_date(v_bucket_num IN NUMBER)
  RETURN DATE
IS
  week_start_date DATE;
BEGIN
  SELECT (TRUNC(SYSDATE+2, 'IW')-2) + ((v_bucket_num-1) * 7)
  INTO week_start_date FROM dual;
  RETURN week_start_date;
END;
于 2013-02-14T18:08:34.417 回答
-1

这是 SQL Server 语法,你可以谷歌搜索等效的 oracle 函数

DATEADD(week, DATEDIFF(week, GETDATE(), 0), 0)

这将在当前一周的第一天为您提供午夜 (0:00:00)。这是哪一天取决于您的系统设置 - 您可以使用 Oracle 等效的 DATEADD 将其移动到您需要的那一天。

我会重新考虑你的模式,从你的描述来看,heirachy 并不是我脑海中闪现的概念——它听起来更像是一个序列。我认为您最好从业务对象开始并返回数据库,而不是相反。

于 2013-02-10T08:51:26.163 回答