基於先進先出方式的庫齡分析算法

庫齡分析表,通常的進銷存都要提供。大多數的庫齡分析要求分析1個月內,1-2個月,2-3個月,3-6個月,6-12個月,1-2年,2-3年,3年以上。如下例子按照這個來設計。(月的概念其實不精確,通常按照30天或者31來計算月)算法

先進先出的庫齡分析算法數據庫

先統計當前機構、倉庫下,產品對應的庫存數量。而後按照產品的入庫歷史去追溯,直到當前數量減去入庫數量總數小於號這等於0,記錄下來這個入庫時間。而後把這些入庫按照庫齡分析要求的時間段進行歸類便可。
舉例說明一下:
假設產品A的庫存數量是50個。假設當前時間是6月1號。
假設產品A的入庫歷史以下:
序號    產品  入庫時間   入庫數量
1       A       6月1日      20
2       A       5月3日      10
3       A       5月1日      15
4       A       3月20日     30
5       A       2月3日      25
    ......
按照咱們設定的數據50,
減去序號1的20個,剩餘30個,大於0,繼續;
減去序號2的10個,剩餘20個,大於0,繼續;
減去序號3的15個,剩餘5個,大於0,繼續;
減去序號4的30個,結果爲負數,OK,計算到這裏截至。根據這個時間,咱們知道,最先的入庫時間是4月20日。
而後按照序號一、二、三、4去歸類,序號一、2歸類到1個月內,序號3歸類到1-2個月,序號4歸類到2-3個月;
庫齡分析的結果是:
1個月內     20
1-2個月     25
2-3個月     5
其他爲0性能

 

SQL例子spa

更進一步,咱們能夠考慮先把出入庫歷史按照時間段分好,而後統計好數量,直接用當前庫存數據減去各個區間的數據,這樣直接就得出結果。下面的實際例子就是按照這種方式來作的。設計

用存儲過程直接統計,可能會存在性能上的問題。若是要考慮性能,能夠根據這個存儲過程算法設計中間表,把存儲過程轉換爲數據庫的job,晚上定時來運行。
首先假設有一個表或者試圖保存了出入庫歷史記錄V_ST_BILL_FT_GOOD_IN;code

這裏只簡單列一下關鍵SQL語句的寫法:
SELECT
    CASE WHEN SD_CREATE_DATE+31>:indate1 THEN 1
        WHEN SD_CREATE_DATE+31<=:indate1 AND SD_CREATE_DATE+61>:indate1 THEN 2
        WHEN SD_CREATE_DATE+61<=:indate1 AND SD_CREATE_DATE+91>:indate1 THEN 3
        WHEN SD_CREATE_DATE+91<=:indate1 AND SD_CREATE_DATE+181>:indate1 THEN 4
        WHEN SD_CREATE_DATE+181<=:indate1 AND SD_CREATE_DATE+361>:indate1 THEN 5
        WHEN SD_CREATE_DATE+361<=:indate1 AND SD_CREATE_DATE+721>:indate1 THEN 6
        WHEN SD_CREATE_DATE+721<=:indate1 AND SD_CREATE_DATE+1081>:indate1 THEN 7
        ELSE 8 end as lable,
        IN_STOCK.*
FROM V_ST_BILL_FT_GOOD_IN IN_STOCK
WHERE ...... and SD_CREATE_DATE<:in_date2

說明:SD_CREATE_DATE是入庫時間,這樣就按照庫齡分析的時間,首先爲各個出入庫歷史數據加上庫齡區間標籤
假設咱們爲臨時統計出來的這個表取別名叫IN_STOCK
而後針對臨時表IN_STOCK按照各個區間進行數據的彙總。
select SD_SHOP_ID,SD_INVOICE_NO,
    sum(decode(lable,1,SD_NUM))NUM1,sum(decode(lable,1,SD_COST_PRICE*SD_NUM))MON1,
    sum(decode(lable,2,SD_NUM))NUM2,sum(decode(lable,2,SD_COST_PRICE*SD_NUM))MON2,
    sum(decode(lable,3,SD_NUM))NUM3,sum(decode(lable,3,SD_COST_PRICE*SD_NUM))MON3,
    sum(decode(lable,4,SD_NUM))NUM4,sum(decode(lable,4,SD_COST_PRICE*SD_NUM))MON4,
    sum(decode(lable,5,SD_NUM))NUM5,sum(decode(lable,5,SD_COST_PRICE*SD_NUM))MON5,
    sum(decode(lable,6,SD_NUM))NUM6,sum(decode(lable,6,SD_COST_PRICE*SD_NUM))MON6,
    sum(decode(lable,7,SD_NUM))NUM7,sum(decode(lable,7,SD_COST_PRICE*SD_NUM))MON7,
    sum(decode(lable,8,SD_NUM))NUM8,sum(decode(lable,8,SD_COST_PRICE*SD_NUM))MON8
FROM IN_STOCK
GROUP BY SD_SHOP_ID,SD_INVOICE_NO

這樣就統計出來了各個區間的數據了。咱們爲這個臨時表取名叫作IN_STOCK_NUM;
而後統計當前庫存,這個很簡單就不詳細說了,假設得出的臨時表名稱叫作CURRENT_NUM;把這兩部分數據LEFT JOIN到一塊兒。
最後,也就是要直接經過算法來查看到底這個數據落在庫齡分析的哪個區間上。
SELECT STOCK_NAME,PRODUCT_CODE,PRODUCT_NAME,PRODUCT_MODEL,PRODUCT_UNIT,STOCK_NUM,STOCK_MONEY,
    DECODE(STOCK_NUM,0,0,ROUND(STOCK_MONEY/STOCK_NUM,2))AVG_PRICE,
    case when nvl(num1,0)>STOCK_NUM then STOCK_NUM else  nvl(num1,0) end as  TOTAL_NUM1,
    case when nvl(num1,0)>STOCK_NUM then STOCK_MONEY else nvl(mon1,0) end as TOTAL_MONEY1,
    case when nvl(num1,0)         case when nvl(num2,0)>STOCK_NUM-nvl(num1,0) then STOCK_NUM-nvl(num1,0) else nvl(num2,0) end
    else 0 end as   TOTAL_NUM2,
    case when nvl(num1,0)         case when nvl(num2,0)>STOCK_NUM-nvl(num1,0) then STOCK_MONEY-nvl(mon1,0) else nvl(mon2,0) end
    else 0       end as   TOTAL_MONEY2,
    ......依次類推
    case when nvl(num1,0)+nvl(num2,0)+nvl(num3,0)+nvl(num4,0)+nvl(num5,0)+nvl(num6,0)+nvl(num7,0)         case when nvl(num8,0)>STOCK_NUM-(nvl(num1,0)+nvl(num2,0)+nvl(num3,0)+nvl(num4,0)+nvl(num5,0)+nvl(num6,0)+ nvl(num7,0))
        then STOCK_NUM-(nvl(mon1,0)+nvl(mon2,0)+nvl(mon3,0)+nvl(mon4,0)+nvl(mon5,0)+nvl(mon6,0)+nvl(mon7,0))
        else nvl(mon8,0) end
    else 0   end as   TOTAL_MONEY8
FROM
    CURRENT_NUM
    LEFT JOIN IN_STOCK_NUM ON .......
產品

剩下的就是對這些數據作數據格式的處理,好比保留小數點後兩位數,計算比例等等.date

相關文章
相關標籤/搜索