1

編集:[詳細]次の場合の基本的なスキーマ設計を考え出す必要があるトレーニング演習として、単純なデータベース設計タスクを行っています。

製品の親子階層があります (原材料 > 進行中の作業 > 最終製品)。

注文は各レベルで行われます。

注文数は、次の 6 か月間、毎週のバケットで表示できます。

商品レベルごとの需要予測が可能です。

需要予測は、次の 6 か月間、毎週のバケットに対して行われます。

通常、階層の上位レベル (原材料または進行中の作業) で行われます。

下位レベル (最終製品) に分解する必要があります。

需要予測を上位レベルから下位レベルに分解するには、次の 2 つの方法があります。

  1. ユーザーは、最終製品の割合分布を指定します。たとえば、Work In Progress の予測が 1000 で、バケット 10 の最終製品 1 に 40%、最終製品 2 に 60% が必要だとユーザーが言うと、今から 10 週目 (日曜日から土曜日) の予測値最終製品 1 の場合は 400、最終製品 2 の場合は 600 になります。

  2. ユーザーは、バケット 5 の最終製品に対して出された注文に従って分解し、最終製品 1 と 2 のバケット 5 の注文がそれぞれ 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_ididproduct_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 プロシージャまたはインターフェイスに使用しているものに含めることができます。

編集:また、最後のコメントから、手動で予測されたものと計算されたものを設定することに言及していました。だから私はそのようなコラムを追加しましたが、クレジットはあなたに行きます

編集 bis: バケット番号については、日付に適切なマスクを使用するだけIWですWW。年の最初の週であるこれらの 2 つの変更。

于 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 の構文です。Google で同等の Oracle 関数を検索できます。

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

これにより、現在の週の最初の日の真夜中 (0:00:00) が得られます。これが何日かは、システム設定によって異なります。DATEADD に相当する Oracle を使用して、必要な日に移動できます。

私はあなたのスキーマを再考します.あなたの説明から、階層は私の頭に浮かんだ概念ではありません. ビジネス オブジェクトから始めてデータベースに戻る方が、その逆よりも良いと思います。

于 2013-02-10T08:51:26.163 に答える