L’individuazione del tipo di domanda è di grande importanza per la successiva fase di previsione e poi di gestione delle scorte, i principali metodi si applicano per i codici che hanno una domande regolare, pertanto è necessario individuare per ogni codice il tipo di domanda, come visto in un precedente post possiamo individuare quattro tipi di domanda: Regolare, intermittente , erratica e lumpy. Per individuare a quale categoria il codice appartenga dobbiamo calcolare due indicatori:
- ADI (avarage demand interval): L’intervallo medio fra due consumi successivi del codice
- CV2 (Coefficiente di variazione al quadrato): Il quadrato del rapporto tra domanda non nulla e la domanda media.
Incrociando i due indicatori (Livello alto e basso) otteniamo una matrice con la quale ricavare la tipologia della domanda.
Per calcolare il primo indicatore consideriamo una tabella in cui sono presenti i seguenti campi: CODICE,DATA,QT. Partendo da questa tabella ed applicando la seguente funzione possiamo derivare una tabella con l’indicatore ADI calcolato.
Public Function ADI(Chiave, CampoData, NomeTabella) Dim db As DAO.Database Dim tabella As DAO.Recordset Dim c1 As DAO.Field Dim c2 As DAO.Field Dim codes(2000000, 3) Dim DATI(100000, 3) Set db = CurrentDb Set tabella = db.OpenRecordset(NomeTabella, dbOpenDynaset) Do Until tabella.EOF t = t + 1 codes(t, 1) = tabella.Fields(Chiave) codes(t, 2) = tabella.Fields(CampoData) tabella.MoveNext Loop tabella.Close db.Close For x = 1 To t If codes(x, 1) = codes(x + 1, 1) Then codes(x, 3) = codes(x + 1, 2) - codes(x, 2) Else codes(x, 3) = 0 End If Next x For x = 1 To t If codes(x, 1) <> codes(x - 1, 1) Then s = codes(x, 3) j = 0 Else s = s + codes(x, 3) j = j + 1 If codes(x, 1) <> codes(x + 1, 1) Then k = k + 1 DATI(k, 1) = codes(x, 1) DATI(k, 2) = s DATI(k, 3) = j End If End If Next x SvuotaTab "ADI" Set db = CurrentDb Set tabella = db.OpenRecordset("ADI", dbOpenDynaset) Set c1 = tabella.Fields("CODICE") Set c2 = tabella.Fields("ADI") For x = 1 To k tabella.AddNew c1 = DATI(x, 1) c2 = DATI(x, 2) / DATI(x, 3) tabella.Update Next x tabella.Close db.Close End Function |
Public Function ADI(Chiave, CampoData, NomeTabella) Dim db As DAO.Database Dim tabella As DAO.Recordset Dim c1 As DAO.Field Dim c2 As DAO.Field Dim codes(2000000, 3) Dim DATI(100000, 3) Set db = CurrentDb Set tabella = db.OpenRecordset(NomeTabella, dbOpenDynaset) Do Until tabella.EOF t = t + 1 codes(t, 1) = tabella.Fields(Chiave) codes(t, 2) = tabella.Fields(CampoData) tabella.MoveNext Loop tabella.Close db.Close For x = 1 To t If codes(x, 1) = codes(x + 1, 1) Then codes(x, 3) = codes(x + 1, 2) - codes(x, 2) Else codes(x, 3) = 0 End If Next x For x = 1 To t If codes(x, 1) <> codes(x - 1, 1) Then s = codes(x, 3) j = 0 Else s = s + codes(x, 3) j = j + 1 If codes(x, 1) <> codes(x + 1, 1) Then k = k + 1 DATI(k, 1) = codes(x, 1) DATI(k, 2) = s DATI(k, 3) = j End If End If Next x SvuotaTab "ADI" Set db = CurrentDb Set tabella = db.OpenRecordset("ADI", dbOpenDynaset) Set c1 = tabella.Fields("CODICE") Set c2 = tabella.Fields("ADI") For x = 1 To k tabella.AddNew c1 = DATI(x, 1) c2 = DATI(x, 2) / DATI(x, 3) tabella.Update Next x tabella.Close db.Close End Function
Il valori che bisogna passare alla funzione sono il nome del campo dove è contenuto il codice articolo, il nome del campo dove è indicata la data ed il nome della tabella dove sono contenuti i codici con lo storico della domanda. La funzione ha bisogno che sia presente una tabella chiamata ADI che abbia i campi CODICE e ADI, la funzione infatti ogni volta che viene lanciata svuota questa tabella ed accoda i nuovi valori calcolati. La funzione per svuotare la tabella richiama una funzione SvotaTab così definita:
Public Function SvuotaTab(nomeTab) DoCmd.SetWarnings False DoCmd.RunSQL "DELETE * FROM [" & nomeTab & "];" DoCmd.SetWarnings True End Function |
Public Function SvuotaTab(nomeTab) DoCmd.SetWarnings False DoCmd.RunSQL "DELETE * FROM [" & nomeTab & "];" DoCmd.SetWarnings True End Function
Per il calcolo del secondo indicatore possiamo procedere attraverso una serie di query che partono dalla tabella movimenti formata dai seguenti campi: CODICE, DATA, SEGNO, QT.
Query MMD
SELECT MOVIMENTI.CODICE, MOVIMENTI.DATA, MOVIMENTI.QT FROM MOVIMENTI WHERE (((MOVIMENTI.SEGNO)="-")) ORDER BY MOVIMENTI.CODICE, MOVIMENTI.DATA, MOVIMENTI.SEGNO DESC; |
SELECT MOVIMENTI.CODICE, MOVIMENTI.DATA, MOVIMENTI.QT FROM MOVIMENTI WHERE (((MOVIMENTI.SEGNO)="-")) ORDER BY MOVIMENTI.CODICE, MOVIMENTI.DATA, MOVIMENTI.SEGNO DESC;
Query calcola CV
SELECT MMD.CODICE, StDevP([QT]) AS DEV, Avg(MMD.QT) AS MEDIA FROM MMD GROUP BY MMD.CODICE HAVING (((Avg(MMD.QT))>0)); |
SELECT MMD.CODICE, StDevP([QT]) AS DEV, Avg(MMD.QT) AS MEDIA FROM MMD GROUP BY MMD.CODICE HAVING (((Avg(MMD.QT))>0));
Query AGG CV2
SELECT [Calcola CV].CODICE, ([DEV]/[MEDIA])^2 AS CV2 INTO CV2 FROM [Calcola CV]; |
SELECT [Calcola CV].CODICE, ([DEV]/[MEDIA])^2 AS CV2 INTO CV2 FROM [Calcola CV];