PL/SQL實例講解(一)

題目要求:某加工廠發貨規則是:每車發貨480件,週六週日不發貨,供貨期間除了最後一批貨外其餘只能整車發貨。

舉個例子:某廠商需求三天貨,週四需要供貨300,週五需要供貨200,週六需要供貨400,下週一需要供貨200。

原發貨表如下:

SHIP_DATE SHIP_QTY PLAN_TYPE
2016-12-01 300 OLD
2016-12-02 200 OLD
2016-12-03 400 OLD
2016-12-05 200 OLD

按照要求不滿480件也要發貨480,那麼週四發貨480件,相當於多發了180,多發的量計入週五該發的數量,相當於週五只需要20件就夠了。但是週六不發貨,所以週六的貨需要提前發,併入週五。考慮到下週一還需要貨,那麼還得按照整車發貨要求來,週五也發480件,相當於發了下週一的60件,而整個供貨期到週一截止,那麼週一發貨120即可。

所以實際發貨清單如下:

SHIP_DATE SHIP_QTY PLAN_TYPE
2016-12-01 300 OLD
2016-12-01 480 NEW
2016-12-02 200 OLD
2016-12-02 480 NEW
2016-12-03 400 OLD
2016-12-05 200 OLD
2016-12-05 120 NEW

相信題意應該明確了。

可以簡單思考一下,如何在程序中考慮這些因素。有兩個思路:

第一個:把週六週日的數據移到週五(不是說週六日不讓發貨嗎,那就當成是週五要發的貨),再進行發貨整車計算。

第二個:先不管週六日不讓發貨這個規則,先按照整車必須480來計算每天需要的發貨量。再將週六日要發的貨移到週五即可。

CREATE OR REPLACE PROCEDURE ship_plan IS
  l_qty      NUMBER := 0;
  l_last_day DATE;
BEGIN
--process_data遊標中放置了按照日期排序的hand_ship_plan表
  FOR process_data IN (SELECT hsp.ship_date,
                              hsp.ship_qty,
                              to_char(hsp.ship_date, 'D') week
                         FROM hand_ship_plan hsp
                        ORDER BY hsp.ship_date) LOOP

    IF process_data.week NOT IN ('1', '7') THEN
    --如果遊標取到日期不是週六和週日,進行插入操作,相當於對週一到週五的數據進行了複寫,將type值變爲new
      INSERT INTO hand_ship_plan
        (ship_date, ship_qty, plan_type)
      VALUES
        (process_data.ship_date, process_data.ship_qty, 'NEW');
    ELSE
    --否則(如果遊標取到的日期是週六和週日)進行更新操作,更新的是哪一天?由decode判斷  如果是週日,讓週日那天減2,如果是週六,讓週六那天減1,確保日期爲週五,將運貨量加在週五裏
      UPDATE hand_ship_plan hsp
         SET hsp.ship_qty = nvl(hsp.ship_qty, 0) + process_data.ship_qty
       WHERE hsp.ship_date =
             process_data.ship_date - decode(process_data.week, 1, 2, 1);
    --如果沒有語句受到影響(意味着週五沒有發貨任務)  所以上邊的更新操作沒有成功,那麼直接將週六日插入新建的週五中
      IF SQL%NOTFOUND THEN
        INSERT INTO hand_ship_plan
          (ship_date, ship_qty, plan_type)
        VALUES
          (process_data.ship_date - decode(process_data.week, 1, 2, 1),
           process_data.ship_qty,
           'NEW');
      END IF;

    END IF;
  --至此,將週六週日的數據移到週五 完成
  END LOOP;
--進行第二步操作,process_new遊標先取到所有 類型 爲 ‘new’的 並且按照日期排序的 條目 及 ROWID 類型爲‘new’的只有週一到週五
  FOR process_new IN (SELECT ROWID row_id, hsp.*
                        FROM hand_ship_plan hsp
                       WHERE hsp.plan_type = 'NEW'
                       ORDER BY hsp.ship_date) LOOP
    --l_qty變量是爲了記錄當多發的量   當l_qty大於當日該發的量,此時刪除那天的‘new’記錄
    IF l_qty >= process_new.ship_qty THEN
      DELETE FROM hand_ship_plan hsp WHERE ROWID = process_new.row_id;
      l_qty := l_qty - process_new.ship_qty;
    ELSE
    --計算每天要發貨的數量  ceil向上取整  先算個數  再算數量
      UPDATE hand_ship_plan hsp
         SET hsp.ship_qty =
             ceil((process_new.ship_qty - l_qty) / 480) * 480
       WHERE ROWID = process_new.row_id;
    --更新多發的貨
      l_qty      := ceil((process_new.ship_qty - l_qty) / 480) * 480 -
                    (process_new.ship_qty - l_qty);
      l_last_day := process_new.ship_date;
    END IF;

  END LOOP;
--當到最後一天時  發貨剩餘的數量
  IF l_qty > 0 THEN
    UPDATE hand_ship_plan hsp
       SET hsp.ship_qty = hsp.ship_qty - l_qty
     WHERE hsp.plan_type = 'NEW'
       AND hsp.ship_date = l_last_day;
  END IF;

END;

具體過程程序的註釋都有解釋。大家可以自己見表嘗試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章