私が持っているケースに取り組んでいます
- 製品の親子階層: [最上位] 原材料RM >仕掛品 WIP > 最終製品EP [最下位]
- 特定の週の最終製品の注文
- 特定の週の原材料または仕掛品の予測値
私の目標は、特定の週の特定の RM または WIP の予測値を、子の注文数に基づいて、その特定の週のその RM または WIP の一部またはすべての子 EP に分解することです。
これは単に、3 つの子 EP (EP1、EP2、EP3 など) を持つ RM (たとえば RM1) があり、RM1 の第 2 週の予測値が 1000 である場合、私の目標はこの予測を次のように分割することです。各 EP の計算された、または指定されたパーセンテージ分布に基づく EP の 3 つの部分。
ユーザーは、パーセンテージ分布を取得するために使用する方法を選択できます。
計算: ユーザーは、10 番目から 15 番目のバケット (現在の開始日から 10 週目から現在の開始日から 16 週目) に出された注文に従って、RM1 予測値を EP1 と EP2 に分解すると言います。したがって、EP1 と EP2 の合計注文数を 10 番目から 15 番目の週バケットまで個別に計算し、次のように分配率を計算します: EP1 注文 / (EP1 + EP2 注文) * 100 % および (EP2 注文) / (EP1 + EP2 注文) * 100 % 、 それぞれ。
指定: ユーザーは、EP1 に 20%、EP2 に 50%、EP3 に 10% と言う
次に、各 EP の第 2 週の RM1 予測値 1000 を、計算または上で得たパーセンテージに従って単純に分割し、第 2 週の EP の予測値として同じテーブルに保存します。
分解のために選択された方法は、parent_id、child_id、子のパーセンテージ、開始バケットの開始日、(終了バケット + 1) の開始日とともに別のテーブルに格納されます。
次のテーブルがあります。
- Products、製品情報を保存し、親子階層を維持します (原材料 > 進行中の作業 > 最終製品)
- 階層の最下位レベル (最終製品) の注文を格納するためのOrders 。
- 予測値、特定の週の製品の予測値 (数値) を保存するため
- 分解の方法、予測テーブルには、最初に階層の上位レベル (原材料) にある特定の週の製品の予測値が格納されます。その値は、その子レベル (一部の最終製品) に分解され、予測テーブル自体に格納されます。分解方法には、どの親からどの子への予測値を分解するために使用された方法と、この子のパーセンテージ分布が格納されます。
- 日付情報日付ディメンションには、特定の日付が含まれる週に対応する開始日 (土曜日である必要があります) と終了日に関する情報があります。
私はここにデータモデルを投稿しました: 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 を使用するにはどうすればよいですか? (ID だけですべての目的に役立つため、おそらく child_name も削除する必要があります)
質問 3 : 分解方法を取得する方法と、ユーザー入力としてパーセンテージを指定する場合の方法は?