Sql 设计简单的需求预测分解方案

Sql 设计简单的需求预测分解方案,sql,oracle,database-design,oracle11g,Sql,Oracle,Database Design,Oracle11g,编辑:[Details]我正在做一个简单的数据库设计任务,作为一个培训练习,我必须为以下情况提出一个基本的模式设计: 我有一个产品的父子层次结构(原材料>在制品>最终产品) 每一级都有订单 在接下来的6个月内,订单数量应每周可见 可以对每个产品级别进行需求预测 对未来6个月的每周桶进行需求预测 通常在更高层次上完成(原材料或在制品) 必须将其分解到较低级别(最终产品) 有两种方法可以将需求预测从较高级别分解到较低级别: 用户指定最终产品的百分比分布。比如说,预计有1000个在建工程。。用户说我想

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

我有一个产品的父子层次结构(原材料>在制品>最终产品)

每一级都有订单

在接下来的6个月内,订单数量应每周可见

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

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

通常在更高层次上完成(原材料或在制品)

必须将其分解到较低级别(最终产品)

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

  • 用户指定最终产品的百分比分布。比如说,预计有1000个在建工程。。用户说我想要40%的成品1和60%的成品2在桶10中。。然后,从现在开始的第10周(周日至周六),最终产品1的预测值为400,最终产品2的预测值为600

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

  • 未来6个月的预测应以周为单位进行查看,理想的格式应为:

    产品名称|桶号|周开始日期|周结束日期|预测值

    对于这种需求,最基本的理想模式是什么


    产品层次结构表可以如下所示:

    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\u id
    是引用产品层次结构表的
    id
    的外键

    每周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);
    
    但这将使每周桶从今天开始,无论哪一天。我希望他们在星期天到星期六

    请帮助设计此数据库结构


    (将使用Oracle11g)

    这是SQL Server语法,您可以在谷歌上搜索与Oracle等效的函数

    DATEADD(week, DATEDIFF(week, GETDATE(), 0), 0)
    
    这将为您提供当前周第一天的午夜(0:00:00)。今天是哪一天取决于您的系统设置-您可以使用Oracle eqivalent of DATEADD将其移动到您需要的日期


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

    您最后的评论正是我的意思。很高兴看到你拿到了

    因为我已经开始做了,所以我完成了一个示例代码。与您刚才所说的不同之处在于,仅使用一周的日期(即周一)和各种检查约束来区分将要改变的内容和不会改变的内容(
    raw\u material
    VS
    raw\u material\u 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过程中,或者您在接口中使用的任何东西中

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


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

    好的,这是我提出的数据模型

    产品--存储产品信息并维护父子层次结构

    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)                  
    
    订单——存储产品订单

    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--存储产品的预测值(存储较高级别的值,从父级分解后存储较低级别的值)

    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;
    

    你能解释一下你对模式的建议吗?我做这个任务是作为一个训练练习(关于我需要什么的细节),所以我愿意重新思考我的模式。我需要一些指导。你需要更多的细节吗?好的,基本上计算机程序是用来解决现实问题的。IMO编程的基本前提不是从软件可以做什么开始,而是从如何解决问题开始,并建立一个概念模型。一般来说,会有事物(代码中的对象)和过程(代码中的方法)允许对象诞生、演化和消亡。数据库只是存储这些状态的一种方式。如果你想发布一个关于你问题的具体细节的问题,我会在那里更具体。为了更清晰,我更新了我的问题。请查看它是否有助于可视化案例。如果forecast是一个计算值,请不要为其设置字段。使用动态计算的虚拟列,或者如果愿意,使用视图。这是关系数据库设计的基础,具有范式等。
    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;