我正在处理一个我有的案例
- 产品的父子层次结构:[最高级别] 原材料RM > 在制品 WIP > 最终产品EP [最低级别]
- 特定周的最终产品订单
- 特定周内原材料或在制品的预测值
我的目标是根据这些孩子的订单数量,将特定周的特定 RM 或 WIP 的预测值分解为该周 RM 或 WIP 的部分或全部子 EP。
这只是意味着如果我有一个 RM,比如 RM1,它有 3 个子 EP,比如 EP1、EP2 和 EP3.. 我对第 2 周的 RM1 的预测值为 1000,那么我的目标是将这个预测拆分为EP 的 3 个部分基于每个 EP 的计算或指定百分比分布。
用户可以选择使用哪种方法来获取百分比分布:
计算:用户说,根据从第 10 到第 15 桶(从现在开始日期的第 10 周到从现在开始日期的第 16 周)对他们下达的订单,将 RM1 预测值分解为 EP1 和 EP2。因此,我们分别计算第 10 至第 15 周期间 EP1 和 EP2 的总订单,并计算百分比分布如下:EP1 订单 / (EP1 + EP2 订单) * 100 % 和 (EP2 订单) / (EP1 + EP2 订单) * 100 % , 分别。
指定:用户说,20% 给 EP1,50% 给 EP2,10% 给 EP3
然后我们简单地将每个 EP 第 2 周的 RM1 预测值根据我们计算或得到的百分比除以 1000,并将其作为第 2 周的 EP 预测值存储在同一张表中。
选择用于分解的方法与 parent_id、child_id、子百分比、开始存储桶的开始日期、(结束存储桶+1)的开始日期一起存储在另一个表中
我有以下表格:
- Products,用于存储产品信息并维护父子层次结构(原材料 > 正在进行的工作 > 最终产品)
- Orders,用于存储最低层次结构(最终产品)的订单。
- Forecast Value,用于存储特定周的产品的预测值(数字)
- 分解方法,预测表最初在层次结构的更高级别(原材料)存储特定周的产品的预测值。该值对其子级别(某些最终产品)进行分解并存储在预测表本身中。分解方法存储使用哪种方法分解预测值从哪个父级到哪个子级以及该子级的百分比分布是多少。
- 日期信息日期维度,包含有关开始日期(必须是星期六)和结束日期的信息,对应于特定日期所在的周
我在这里发布了我的数据模型:https ://stackoverflow.com/a/14881277/891424 ,这是我迄今为止编写的一个函数和几个程序:
查找与给定存储桶对应的周开始日期的函数
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;
返回给定父级的所有子 EP 的过程
CREATE OR REPLACE PROCEDURE get_eps(
v_parent IN NUMBER,
v_children_of_parent OUT SYS_REFCURSOR
)
AS
v_children SYS_REFCURSOR;
BEGIN
OPEN v_children_of_parent FOR
SELECT id, name FROM (
SELECT
CONNECT_BY_ISLEAF isleaf, p.id, p.name
FROM
inf_product p
WHERE p.level_code = 'EP'
START WITH id = 1
CONNECT BY PRIOR id = parent_id
)
WHERE isleaf = 1;
END;
分解预测值的程序(不完整)
CREATE OR REPLACE PROCEDURE inf_disaggregate(v_parent_id IN NUMBER, v_bucket_start IN NUMBER, v_bucket_end IN NUMBER)
IS
/* Parent Product ID from input */
v_parent_prod_id NUMBER;
/* All the children of parent specified in the input */
child_cursor SYS_REFCURSOR;
child_id NUMBER;
child_name VARCHAR2(40);
/* Forecast Bucket Info */
vbucket_start NUMBER;
vbucket_end NUMBER;
vbucket_diff NUMBER; -- loop over vbucket_diff + 1
/* Date corresponding to input buckets */
vbucket_start_date DATE;
vbucket_end_date DATE;
/* Exceptions */
invalid_bucket EXCEPTION;
PRAGMA EXCEPTION_INIT( invalid_bucket, -20001 );
BEGIN
v_parent_prod_id := v_parent_id;
vbucket_start := v_bucket_start;
vbucket_end := v_bucket_end;
vbucket_diff := vbucket_end - vbucket_start;
IF vbucket_diff < 0 THEN
RAISE_APPLICATION_ERROR( -20001, 'Bucket numbers not in the correct order' );
END IF;
IF vbucket_start < 1 OR vbucket_start > 26 OR vbucket_end < 1 OR vbucket_end > 26 THEN
RAISE_APPLICATION_ERROR( -20001, 'Bucket value must be within 1 to 26' );
END IF;
/* Get first day of the week corresponding to the buckets */
vbucket_start_date := get_week_start_date(vbucket_start);
vbucket_end_date := get_week_start_date(vbucket_end);
DBMS_OUTPUT.PUT_LINE(vbucket_start);
DBMS_OUTPUT.PUT_LINE(vbucket_end);
DBMS_OUTPUT.PUT_LINE(vbucket_diff);
DBMS_OUTPUT.PUT_LINE(vbucket_start_date);
DBMS_OUTPUT.PUT_LINE(vbucket_end_date);
/* Get all child EPs for the specified parent */
get_eps(v_parent => v_parent_prod_id, v_children_of_parent => child_cursor);
LOOP
FETCH child_cursor
INTO child_id, child_name;
EXIT WHEN child_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(child_id || ' | ' || child_name);
END LOOP;
CLOSE child_cursor;
EXCEPTION
WHEN invalid_bucket
THEN
DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM, 1 , 80));
END;
/
运行程序
SET SERVEROUTPUT ON;
CALL inf_disaggregate(5, 10, 12);
问题 1:如何创建包或程序来完成此任务?
问题 2:如何摆脱 SYS_REFCURSOR 并改用动态 sql?(我可能也应该摆脱 child_name ,因为仅 ID 就可以很好地为我服务)
问题 3:如何获得分解方法以及在指定的情况下,百分比作为用户输入?