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