題目要求:某加工廠發貨規則是:每車發貨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;
具體過程程序的註釋都有解釋。大家可以自己見表嘗試。