684 lines
26 KiB
Markdown
684 lines
26 KiB
Markdown
|
|
## 一、如和使用
|
|||
|
|
{: id="20251007101950-1gugbp5"}
|
|||
|
|
|
|||
|
|
- {: id="20251007103613-sqd2oun"}启用宏功能
|
|||
|
|
{: id="20251007103613-75wsxtt"}
|
|||
|
|
{: id="20251007103538-0h6e40i"}
|
|||
|
|
|
|||
|
|
- {: id="20251007103538-z0q3aph"}将库存数据<span data-type="strong">全选覆盖粘贴</span>到<span data-type="code">料件库存报表</span>工作表
|
|||
|
|
{: id="20251007103538-dh9t5wa"}
|
|||
|
|
- {: id="20251007103538-f74vlns"}将BOM数据粘贴到<span data-type="code">BOM</span>工作表
|
|||
|
|
{: id="20251007103538-3ue35ls"}
|
|||
|
|
- {: id="20251007103538-l98kcxb"}将预测数据粘贴到<span data-type="code">Focest</span>工作表
|
|||
|
|
{: id="20251007103538-2crsvgh"}
|
|||
|
|
{: id="20251007103538-bdebbsq"}
|
|||
|
|
|
|||
|
|
- {: id="20251007103623-69q9u7n"}按<span data-type="code">Alt+F8</span>打开宏对话框
|
|||
|
|
{: id="20251007103623-ik5ukjv"}
|
|||
|
|
{: id="20251007103538-wptkjh0"}
|
|||
|
|
|
|||
|
|
- {: id="20251007103627-u1ocd3t"}选择宏<span data-type="code">A</span>
|
|||
|
|
{: id="20251007103627-rryv6m0"}
|
|||
|
|
{: id="20251007103538-l28z8vd"}
|
|||
|
|
|
|||
|
|
- {: id="20251007103631-s4oome2"}点击<span data-type="code">运行</span>按钮
|
|||
|
|
{: id="20251007103631-qhayol7"}
|
|||
|
|
- {: id="20251007103747-229bjft"} 在0000工作表查看所有汇总数据
|
|||
|
|
{: id="20251007103749-o3w3b7f"}
|
|||
|
|
{: id="20251007103538-6q6mpo3"}
|
|||
|
|
|
|||
|
|
> <span data-type="strong">重要注意事项</span>:
|
|||
|
|
> {: id="20251007103538-joq3kr7"}
|
|||
|
|
>
|
|||
|
|
> - {: id="20251007103538-m1bekwm"}<span data-type="strong">保持原始列位置不变,避免修改列顺序</span>
|
|||
|
|
> {: id="20251007103538-yhzozlu"}
|
|||
|
|
> {: id="20251007103538-smjcynk"}
|
|||
|
|
{: id="20251007103538-z5d2rho"}
|
|||
|
|
|
|||
|
|
# 二、文件结构
|
|||
|
|
{: id="20251007103209-33jahkh"}
|
|||
|
|
|
|||
|
|
{: id="20251007103237-06coebk"}
|
|||
|
|
|
|||
|
|

|
|||
|
|
{: id="20251007102118-doi1b72"}
|
|||
|
|
|
|||
|
|
|<span data-type="strong">工作表名称</span>|<span data-type="strong">功能描述</span>|<span data-type="strong">数据来源</span>|<span data-type="strong">更新频率</span>|
|
|||
|
|
| --| ------------------------------| --------------| ------------|
|
|||
|
|
|<span data-type="strong">料件库存报表</span>|存放SAP导出的库存数据|SAP系统导出|每日/每周|
|
|||
|
|
|<span data-type="strong">BOM</span>|BOM表数据|SAP系统导出|物料变更时|
|
|||
|
|
|<span data-type="strong">Focest</span>|存放预测需求数据|预测系统导出|每周|
|
|||
|
|
|<span data-type="strong">Output</span>|宏运行后生成的需求计算结果|系统自动生成|每次运行宏|
|
|||
|
|
|<span data-type="strong">Cutput</span>|宏运行后生成的需求透视表|系统自动生成|每次运行宏|
|
|||
|
|
|<span data-type="strong">Unmatched</span>|宏运行后生成的未匹配料号清单|系统自动生成|每次运行宏|
|
|||
|
|
|<span data-type="strong">0000</span>|主分析报表(最终查看页面)|综合所有数据|实时更新|
|
|||
|
|
{: colgroup="|||" id="20251007101950-3xgqm1t"}
|
|||
|
|
|
|||
|
|
#### 步骤1:准备源数据
|
|||
|
|
{: id="20251007101950-4wo5r07"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">库存报表数据要求:</span>
|
|||
|
|
{: id="20251007101950-znq4l0w"}
|
|||
|
|
|
|||
|
|
- {: id="20251007101950-6pqjxdb"}必须包含的字段:料号、库存量、待验量、需求量、采购订单量、采购申请量、提前期天数、最小订单量、结余量
|
|||
|
|
{: id="20251007101950-5e97muw"}
|
|||
|
|
- {: id="20251007101950-n6nqtj0"}数据格式:从SAP系统标准导出格式
|
|||
|
|
{: id="20251007101950-2r71rup"}
|
|||
|
|
- {: id="20251007102208-qmdycmg"}直接整体覆盖粘贴
|
|||
|
|
{: id="20251007102208-d0y7lkq"}
|
|||
|
|
- {: id="20251007102222-55xa6og"}
|
|||
|
|
{: id="20251007102222-mup6fx7"}
|
|||
|
|
{: id="20251007101950-0d46td2"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">BOM表数据要求:</span>
|
|||
|
|
{: id="20251007101950-mx6n0z8"}
|
|||
|
|
|
|||
|
|
- {: id="20251007101950-wvilwt7"}父料号、子料号、用量比例
|
|||
|
|
{: id="20251007101950-6x7egcc"}
|
|||
|
|
- {: id="20251007101950-dh700zj"}完整的物料层级关系
|
|||
|
|
{: id="20251007101950-3s3cuty"}
|
|||
|
|
- {: id="20251007102256-7lf98jt"}
|
|||
|
|
{: id="20251007102256-tgfu4hi"}
|
|||
|
|
{: id="20251007101950-r20cvwd"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">Focest预测数据要求:</span>
|
|||
|
|
{: id="20251007101950-7wfj835"}
|
|||
|
|
|
|||
|
|
- {: id="20251007101950-cjynlq3"}料号、LIC系数
|
|||
|
|
{: id="20251007101950-48gvvew"}
|
|||
|
|
- {: id="20251007101950-tmr8lst"}56周的需求预测数据
|
|||
|
|
{: id="20251007101950-igk84lq"}
|
|||
|
|
- {: id="20251007101950-raxyodd"}基准日期信息
|
|||
|
|
{: id="20251007101950-lg129e0"}
|
|||
|
|
{: id="20251007101950-v31blto"}
|
|||
|
|
|
|||
|
|
### 参数配置详解
|
|||
|
|
{: id="20251007101950-12z0rkw"}
|
|||
|
|
|
|||
|
|
|<span data-type="strong">单元格</span>|<span data-type="strong">对应数据</span>|<span data-type="strong">默认值</span>|<span data-type="strong">数据源列</span>|<span data-type="strong">说明</span>|
|
|||
|
|
| --| --------| ---| -----| ----------------------------|
|
|||
|
|
|<span data-type="strong">B1</span>|库存量|2|D列|库存报表中库存所在列|
|
|||
|
|
|<span data-type="strong">C1</span>|待验量|3|E列|库存报表中待验量所在列|
|
|||
|
|
|<span data-type="strong">D1</span>|需求量|4|F列|库存报表中需求量所在列|
|
|||
|
|
|<span data-type="strong">E1</span>|PO量|5|G列|库存报表中采购订单量所在列|
|
|||
|
|
|<span data-type="strong">F1</span>|PR量|6|H列|库存报表中采购申请量所在列|
|
|||
|
|
|<span data-type="strong">G1</span>|LT天数|7|I列|库存报表中提前期天数所在列|
|
|||
|
|
|<span data-type="strong">H1</span>|MOQ|8|J列|库存报表中最小订单量所在列|
|
|||
|
|
|<span data-type="strong">I1</span>|结余量|9|K列|库存报表中结余量所在列|
|
|||
|
|
{: colgroup="||||" id="20251007101950-i1k872g"}
|
|||
|
|
|
|||
|
|
如需更改数据提取列,直接修改B1:I1中的数字(如B1=3表示提取库存报表E列数据)
|
|||
|
|
{: id="20251007101950-3rapueu"}
|
|||
|
|
|
|||
|
|
### 4. 0000工作表(主分析仪表板)
|
|||
|
|
{: id="20251007101950-3vhh8c9"}
|
|||
|
|
|
|||
|
|

|
|||
|
|
{: id="20251007103256-08bskql"}
|
|||
|
|
|
|||
|
|
#### 核心分析列说明
|
|||
|
|
{: id="20251007101950-89pe4g7"}
|
|||
|
|
|
|||
|
|
|<span data-type="strong">列</span>|<span data-type="strong">标题</span>|<span data-type="strong">公式</span>|<span data-type="strong">业务含义</span>|
|
|||
|
|
| --| -----------| ----------| ------------------------|
|
|||
|
|
|<span data-type="strong">A</span>|P/N|手工输入|需要分析的料号|
|
|||
|
|
|<span data-type="strong">B</span>|庫存|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,B$1,0)</span>|当前库存数量|
|
|||
|
|
|<span data-type="strong">C</span>|待驗|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,C$1,0)</span>|在检验中的数量|
|
|||
|
|
|<span data-type="strong">D</span>|需求|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,D$1,0)</span>|当前需求量|
|
|||
|
|
|<span data-type="strong">E</span>|PO|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,E$1,0)</span>|采购在途订单量|
|
|||
|
|
|<span data-type="strong">F</span>|PR|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,F$1,0)</span>|采购申请量|
|
|||
|
|
|<span data-type="strong">G</span>|天数|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,G$1,0)</span>|物料提前期(天)|
|
|||
|
|
|<span data-type="strong">H</span>|MOQ|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,H$1,0)</span>|最小订购批量|
|
|||
|
|
|<span data-type="strong">I</span>|结余量|<span data-type="code">=VLOOKUP($A3,料件库存报表!$D:$BG,I$1,0)</span>|可用库存结余|
|
|||
|
|
|<span data-type="strong">J</span>|L/T+两周|<span data-type="code">=ROUND(G3/7,0)+2</span>|提前期周数+安全缓冲|
|
|||
|
|
|<span data-type="strong">K</span>|工单欠料|<span data-type="code">=I3-SUM(...)</span>|结余量减去提前期内需求|
|
|||
|
|
|<span data-type="strong">L</span>|L/T内需求|<span data-type="code">=SUM(INDIRECT('P'&ROW()&':'&NT($J3+COLUMN($P$1)-1)&ROW()))</span>|提前期内的总需求|
|
|||
|
|
|<span data-type="strong">M</span>|差异|<span data-type="code">=I3-L3</span>|库存与需求的差异|
|
|||
|
|
|<span data-type="strong">N-BH</span>|周需求|<span data-type="code">=VLOOKUP($A5,Cutput!$A:$BH,Q$1,0)</span>|各周预测需求数量|
|
|||
|
|
{: colgroup="|||" id="20251007101950-5snse30"}
|
|||
|
|
|
|||
|
|
### 动态需求预测调整
|
|||
|
|
{: id="20251007104428-or2eom7"}
|
|||
|
|
|
|||
|
|
通过修改<span data-type="code">0000</span>工作表的<span data-type="code">P2</span>日期,系统实现动态重算:
|
|||
|
|
{: id="20251007104428-t440rq0"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">动态生成时间轴。</span> 它通过计算一个基准周数,并利用列位置自动向右递增,从而快速创建出一系列连续的周序号。当基准日期变化时,整个周序列会自动更新。
|
|||
|
|
{: id="20251007104803-l1ak6we"}
|
|||
|
|
|
|||
|
|
{: id="20251007104435-p1a57hu"}
|
|||
|
|
|
|||
|
|
```mermaid
|
|||
|
|
graph LR
|
|||
|
|
P2[修改开始日期] --> A[重算周偏移量]
|
|||
|
|
A --> B[更新所有日期相关公式]
|
|||
|
|
B --> C[刷新需求时间序列]
|
|||
|
|
C --> D[重新计算L/T内需求]
|
|||
|
|
```
|
|||
|
|
{: id="20251007104428-b0lymn0"}
|
|||
|
|
|
|||
|
|
# VBA代码中文注释
|
|||
|
|
{: id="20251007104110-2uh5k3t"}
|
|||
|
|
|
|||
|
|
## 子程序 A
|
|||
|
|
{: id="20251007104110-jpr1zki"}
|
|||
|
|
|
|||
|
|
```vba
|
|||
|
|
Sub A()
|
|||
|
|
' 调用B子程序处理数据
|
|||
|
|
Call B
|
|||
|
|
' 调用Q子程序生成数据透视表
|
|||
|
|
Call Q
|
|||
|
|
End Sub
|
|||
|
|
```
|
|||
|
|
{: id="20251007104110-mbzdcls"}
|
|||
|
|
|
|||
|
|
## 子程序 B - 主要数据处理程序
|
|||
|
|
{: id="20251007104110-pa95spg"}
|
|||
|
|
|
|||
|
|
```vba
|
|||
|
|
Sub B()
|
|||
|
|
' 关闭屏幕更新、自动计算和事件处理以提高性能
|
|||
|
|
Application.ScreenUpdating = False
|
|||
|
|
Application.Calculation = xlCalculationManual
|
|||
|
|
Application.EnableEvents = False
|
|||
|
|
|
|||
|
|
' 定义工作表变量
|
|||
|
|
Dim wsFocest As Worksheet, wsBOM As Worksheet, wsOutput As Worksheet, wsUnmatched As Worksheet
|
|||
|
|
' 定义行号变量
|
|||
|
|
Dim lastRowF As Long, lastRowB As Long, lastRowO As Long, lastRowU As Long
|
|||
|
|
' 定义循环计数器
|
|||
|
|
Dim i As Long, j As Long, k As Long, col As Long
|
|||
|
|
' 定义数据变量
|
|||
|
|
Dim keyPart As String, material As String, usage As Double
|
|||
|
|
Dim lic As Double, focestCol1 As String, focestCol2 As String
|
|||
|
|
' 定义56周数据数组
|
|||
|
|
Dim weekValues(1 To 56) As Double
|
|||
|
|
' 定义字典对象用于存储BOM数据和未匹配数据
|
|||
|
|
Dim dictBOM As Object, dictUnmatched As Object
|
|||
|
|
Dim materialData As Variant
|
|||
|
|
Dim key As Variant
|
|||
|
|
|
|||
|
|
' 创建字典对象
|
|||
|
|
Set dictBOM = CreateObject("Scripting.Dictionary")
|
|||
|
|
Set dictUnmatched = CreateObject("Scripting.Dictionary")
|
|||
|
|
|
|||
|
|
' 设置工作表引用
|
|||
|
|
Set wsFocest = ThisWorkbook.Sheets("Focest")
|
|||
|
|
Set wsBOM = ThisWorkbook.Sheets("BOM")
|
|||
|
|
|
|||
|
|
' 删除并重新创建输出工作表
|
|||
|
|
On Error Resume Next
|
|||
|
|
Application.DisplayAlerts = False
|
|||
|
|
ThisWorkbook.Sheets("Output").Delete
|
|||
|
|
ThisWorkbook.Sheets("Unmatched").Delete
|
|||
|
|
Application.DisplayAlerts = True
|
|||
|
|
On Error GoTo 0
|
|||
|
|
|
|||
|
|
' 创建新的输出工作表
|
|||
|
|
Set wsOutput = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
|
|||
|
|
wsOutput.Name = "Output"
|
|||
|
|
Set wsUnmatched = ThisWorkbook.Sheets.Add(After:=wsOutput)
|
|||
|
|
wsUnmatched.Name = "Unmatched"
|
|||
|
|
|
|||
|
|
' 阶段1: 读取BOM数据到字典中
|
|||
|
|
lastRowB = wsBOM.Cells(wsBOM.Rows.Count, "A").End(xlUp).Row
|
|||
|
|
Dim bomData As Variant
|
|||
|
|
bomData = wsBOM.Range("A2:C" & lastRowB).Value
|
|||
|
|
|
|||
|
|
' 遍历BOM数据并填充字典
|
|||
|
|
For i = 1 To UBound(bomData, 1)
|
|||
|
|
keyPart = Trim(bomData(i, 1) & "")
|
|||
|
|
material = Trim(bomData(i, 2) & "")
|
|||
|
|
|
|||
|
|
' 安全处理使用量数值
|
|||
|
|
If IsNumeric(bomData(i, 3)) Then
|
|||
|
|
usage = CDbl(bomData(i, 3))
|
|||
|
|
Else
|
|||
|
|
usage = 0
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 如果关键部件和物料号都不为空,添加到字典
|
|||
|
|
If keyPart <> "" And material <> "" Then
|
|||
|
|
If Not dictBOM.Exists(keyPart) Then
|
|||
|
|
dictBOM.Add keyPart, New Collection
|
|||
|
|
End If
|
|||
|
|
dictBOM(keyPart).Add Array(material, usage)
|
|||
|
|
End If
|
|||
|
|
Next i
|
|||
|
|
|
|||
|
|
' 阶段2: 处理Focest数据 - 只处理有BOM匹配的行
|
|||
|
|
lastRowF = wsFocest.Cells(wsFocest.Rows.Count, "A").End(xlUp).Row
|
|||
|
|
Dim focestData As Variant
|
|||
|
|
focestData = wsFocest.Range("A2:BJ" & lastRowF).Value ' 列A到BJ (A, B + 56周)
|
|||
|
|
|
|||
|
|
' 预计算输出数据大小
|
|||
|
|
Dim outputRowCount As Long
|
|||
|
|
outputRowCount = 0
|
|||
|
|
For i = 1 To UBound(focestData, 1)
|
|||
|
|
keyPart = Trim(focestData(i, 1) & "")
|
|||
|
|
If keyPart <> "" And dictBOM.Exists(keyPart) Then
|
|||
|
|
outputRowCount = outputRowCount + dictBOM(keyPart).Count
|
|||
|
|
End If
|
|||
|
|
Next i
|
|||
|
|
|
|||
|
|
' 准备输出数组
|
|||
|
|
Dim outputData() As Variant
|
|||
|
|
ReDim outputData(1 To outputRowCount, 1 To 60) ' 4个固定列 + 56个周列
|
|||
|
|
|
|||
|
|
lastRowO = 0
|
|||
|
|
|
|||
|
|
' 处理Focest数据
|
|||
|
|
For i = 1 To UBound(focestData, 1)
|
|||
|
|
keyPart = Trim(focestData(i, 1) & "")
|
|||
|
|
If keyPart = "" Then GoTo NextFocestRow
|
|||
|
|
|
|||
|
|
' 只处理有BOM匹配的行
|
|||
|
|
If dictBOM.Exists(keyPart) Then
|
|||
|
|
focestCol1 = focestData(i, 1) & ""
|
|||
|
|
focestCol2 = focestData(i, 2) & ""
|
|||
|
|
|
|||
|
|
' 安全处理LIC值
|
|||
|
|
If IsNumeric(focestData(i, 2)) Then
|
|||
|
|
lic = CDbl(focestData(i, 2))
|
|||
|
|
Else
|
|||
|
|
lic = 0
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 提取周数据并进行错误处理
|
|||
|
|
For j = 1 To 56
|
|||
|
|
If IsNumeric(focestData(i, j + 2)) Then
|
|||
|
|
weekValues(j) = CDbl(focestData(i, j + 2))
|
|||
|
|
Else
|
|||
|
|
weekValues(j) = 0
|
|||
|
|
End If
|
|||
|
|
Next j
|
|||
|
|
|
|||
|
|
' 处理匹配的BOM项目
|
|||
|
|
For k = 1 To dictBOM(keyPart).Count
|
|||
|
|
materialData = dictBOM(keyPart)(k)
|
|||
|
|
material = materialData(0)
|
|||
|
|
usage = materialData(1)
|
|||
|
|
lastRowO = lastRowO + 1
|
|||
|
|
|
|||
|
|
' 填充输出数据
|
|||
|
|
outputData(lastRowO, 1) = focestCol1
|
|||
|
|
outputData(lastRowO, 2) = focestCol2
|
|||
|
|
outputData(lastRowO, 3) = material
|
|||
|
|
outputData(lastRowO, 4) = usage
|
|||
|
|
|
|||
|
|
' 计算每周数据:周值 × LIC × 使用量
|
|||
|
|
For col = 1 To 56
|
|||
|
|
outputData(lastRowO, col + 4) = weekValues(col) * lic * usage
|
|||
|
|
Next col
|
|||
|
|
Next k
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
NextFocestRow:
|
|||
|
|
Next i
|
|||
|
|
|
|||
|
|
' 阶段3: 单独处理没有BOM匹配的Focest行
|
|||
|
|
For i = 1 To UBound(focestData, 1)
|
|||
|
|
keyPart = Trim(focestData(i, 1) & "")
|
|||
|
|
If keyPart <> "" And Not dictBOM.Exists(keyPart) Then
|
|||
|
|
If Not dictUnmatched.Exists(keyPart) Then
|
|||
|
|
dictUnmatched.Add keyPart, True
|
|||
|
|
End If
|
|||
|
|
End If
|
|||
|
|
Next i
|
|||
|
|
|
|||
|
|
' 批量写入输出数据
|
|||
|
|
If outputRowCount > 0 Then
|
|||
|
|
wsOutput.Range("A2").Resize(outputRowCount, 60).Value = outputData
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 生成未匹配数据工作表
|
|||
|
|
wsUnmatched.Cells(1, 1).Value = "Unmatched Key Part Numbers"
|
|||
|
|
|
|||
|
|
' 写入未匹配的数据
|
|||
|
|
If dictUnmatched.Count > 0 Then
|
|||
|
|
Dim unmatchedData() As Variant
|
|||
|
|
ReDim unmatchedData(1 To dictUnmatched.Count, 1 To 1)
|
|||
|
|
i = 0
|
|||
|
|
For Each key In dictUnmatched.Keys
|
|||
|
|
i = i + 1
|
|||
|
|
unmatchedData(i, 1) = key
|
|||
|
|
Next key
|
|||
|
|
wsUnmatched.Range("A2").Resize(dictUnmatched.Count, 1).Value = unmatchedData
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 设置输出表的标题行
|
|||
|
|
wsOutput.Cells(1, 1).Value = "Focest Col1"
|
|||
|
|
wsOutput.Cells(1, 2).Value = "Focest Col2"
|
|||
|
|
wsOutput.Cells(1, 3).Value = "Material Number"
|
|||
|
|
wsOutput.Cells(1, 4).Value = "BOM Usage"
|
|||
|
|
For col = 1 To 56
|
|||
|
|
wsOutput.Cells(1, col + 4).Value = "Week" & col
|
|||
|
|
Next col
|
|||
|
|
|
|||
|
|
' 自动调整列宽
|
|||
|
|
wsOutput.Columns.AutoFit
|
|||
|
|
wsUnmatched.Columns.AutoFit
|
|||
|
|
|
|||
|
|
' 恢复Excel设置
|
|||
|
|
Application.ScreenUpdating = True
|
|||
|
|
Application.Calculation = xlCalculationAutomatic
|
|||
|
|
Application.EnableEvents = True
|
|||
|
|
|
|||
|
|
' 显示处理完成消息
|
|||
|
|
MsgBox "Processing completed! " & outputRowCount & " rows generated in Output sheet. " & _
|
|||
|
|
dictUnmatched.Count & " unmatched items found."
|
|||
|
|
End Sub
|
|||
|
|
```
|
|||
|
|
{: id="20251007104110-kny6p89"}
|
|||
|
|
|
|||
|
|
## 子程序 Q - 数据透视表生成程序
|
|||
|
|
{: id="20251007104110-v8p7fvg"}
|
|||
|
|
|
|||
|
|
```vba
|
|||
|
|
Sub Q()
|
|||
|
|
' 定义变量
|
|||
|
|
Dim wsSource As Worksheet, wsDest As Worksheet
|
|||
|
|
Dim pvtCache As PivotCache
|
|||
|
|
Dim pvtTable As PivotTable
|
|||
|
|
Dim lastRow As Long
|
|||
|
|
Dim SourceDataRange As Range
|
|||
|
|
Dim i As Long
|
|||
|
|
Dim fieldName As String
|
|||
|
|
Dim startTime As Double
|
|||
|
|
Dim dataField As PivotField
|
|||
|
|
|
|||
|
|
' 开始计时
|
|||
|
|
startTime = Timer
|
|||
|
|
|
|||
|
|
' 禁用Excel功能以提高性能
|
|||
|
|
OptimizeVBA True
|
|||
|
|
|
|||
|
|
On Error GoTo ErrorHandler
|
|||
|
|
|
|||
|
|
' 检查源工作表是否存在
|
|||
|
|
If Not WorksheetExists("Output") Then
|
|||
|
|
MsgBox "Source worksheet 'Output' not found!", vbCritical
|
|||
|
|
GoTo CleanUp
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 设置源工作表引用
|
|||
|
|
Set wsSource = ThisWorkbook.Worksheets("Output")
|
|||
|
|
|
|||
|
|
' 如果目标工作表已存在则删除
|
|||
|
|
If WorksheetExists("Cutput") Then
|
|||
|
|
Application.DisplayAlerts = False
|
|||
|
|
ThisWorkbook.Worksheets("Cutput").Delete
|
|||
|
|
Application.DisplayAlerts = True
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 移除同名的现有数据透视表
|
|||
|
|
RemovePivotTable "WeeklySummaryPivot"
|
|||
|
|
|
|||
|
|
' 创建新的数据透视表工作表
|
|||
|
|
Set wsDest = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
|
|||
|
|
wsDest.Name = "Cutput"
|
|||
|
|
|
|||
|
|
' 查找源工作表的最后一行数据
|
|||
|
|
lastRow = FindLastRow(wsSource)
|
|||
|
|
|
|||
|
|
' 验证是否有足够的数据
|
|||
|
|
If lastRow < 2 Then
|
|||
|
|
MsgBox "Insufficient data in source worksheet!", vbExclamation
|
|||
|
|
GoTo CleanUp
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 定义源数据范围
|
|||
|
|
Set SourceDataRange = wsSource.Range("A1:BH" & lastRow)
|
|||
|
|
|
|||
|
|
' 从源数据创建数据透视缓存
|
|||
|
|
Set pvtCache = ThisWorkbook.PivotCaches.Create( _
|
|||
|
|
SourceType:=xlDatabase, _
|
|||
|
|
sourceData:=SourceDataRange)
|
|||
|
|
|
|||
|
|
' 创建数据透视表
|
|||
|
|
Set pvtTable = pvtCache.CreatePivotTable( _
|
|||
|
|
TableDestination:=wsDest.Range("A3"), _
|
|||
|
|
tableName:="WeeklySummaryPivot")
|
|||
|
|
|
|||
|
|
' 配置数据透视表
|
|||
|
|
With pvtTable
|
|||
|
|
.ManualUpdate = True
|
|||
|
|
.RowAxisLayout xlTabularRow
|
|||
|
|
|
|||
|
|
' 添加行字段 - 物料号(C列)
|
|||
|
|
.AddFields RowFields:=wsSource.Cells(1, 3).Value
|
|||
|
|
|
|||
|
|
' 添加数据字段(E列到BH列)
|
|||
|
|
For i = 5 To 60
|
|||
|
|
fieldName = wsSource.Cells(1, i).Value
|
|||
|
|
|
|||
|
|
If fieldName <> "" Then
|
|||
|
|
On Error Resume Next
|
|||
|
|
Set dataField = .PivotFields(fieldName)
|
|||
|
|
If Err.Number = 0 Then
|
|||
|
|
With dataField
|
|||
|
|
.Orientation = xlDataField
|
|||
|
|
.Function = xlSum
|
|||
|
|
.NumberFormat = "#,##0"
|
|||
|
|
|
|||
|
|
If InStr(.Caption, "Sum of") = 0 Then
|
|||
|
|
.Caption = "Sum of " & fieldName
|
|||
|
|
End If
|
|||
|
|
End With
|
|||
|
|
Else
|
|||
|
|
Err.Clear
|
|||
|
|
End If
|
|||
|
|
On Error GoTo ErrorHandler
|
|||
|
|
End If
|
|||
|
|
Next i
|
|||
|
|
|
|||
|
|
' 应用格式设置
|
|||
|
|
.ShowTableStyleRowStripes = True
|
|||
|
|
.TableStyle2 = "PivotStyleMedium9"
|
|||
|
|
.ManualUpdate = False
|
|||
|
|
End With
|
|||
|
|
|
|||
|
|
' 添加标题和时间戳
|
|||
|
|
With wsDest
|
|||
|
|
.Range("A1").Value = "Weekly Summary Report"
|
|||
|
|
.Range("A1").Font.Bold = True
|
|||
|
|
.Range("A1").Font.Size = 14
|
|||
|
|
|
|||
|
|
.Range("A2").Value = "Generated: " & Now()
|
|||
|
|
.Range("A2").Font.Italic = True
|
|||
|
|
End With
|
|||
|
|
|
|||
|
|
' 自动调整列宽
|
|||
|
|
If wsDest.UsedRange.Count > 1 Then
|
|||
|
|
wsDest.UsedRange.Columns.AutoFit
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' 成功消息
|
|||
|
|
MsgBox "Pivot table created successfully in " & Format(Timer - startTime, "0.00") & _
|
|||
|
|
" seconds! Location: Worksheet " & wsDest.Name, vbInformation
|
|||
|
|
|
|||
|
|
CleanUp:
|
|||
|
|
' 清理和恢复设置
|
|||
|
|
OptimizeVBA False
|
|||
|
|
Set pvtTable = Nothing
|
|||
|
|
Set pvtCache = Nothing
|
|||
|
|
Set SourceDataRange = Nothing
|
|||
|
|
Set wsSource = Nothing
|
|||
|
|
Set wsDest = Nothing
|
|||
|
|
|
|||
|
|
Exit Sub
|
|||
|
|
|
|||
|
|
ErrorHandler:
|
|||
|
|
' 错误处理
|
|||
|
|
MsgBox "Error " & Err.Number & ": " & Err.Description & vbCrLf & _
|
|||
|
|
"Error occurred at line: " & Erl, vbCritical
|
|||
|
|
Resume CleanUp
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
' 辅助函数:优化VBA性能
|
|||
|
|
Sub OptimizeVBA(Optimize As Boolean)
|
|||
|
|
With Application
|
|||
|
|
If Optimize Then
|
|||
|
|
.ScreenUpdating = False
|
|||
|
|
.Calculation = xlCalculationManual
|
|||
|
|
.DisplayAlerts = False
|
|||
|
|
.EnableEvents = False
|
|||
|
|
.StatusBar = "Processing... Please wait"
|
|||
|
|
Else
|
|||
|
|
.ScreenUpdating = True
|
|||
|
|
.Calculation = xlCalculationAutomatic
|
|||
|
|
.DisplayAlerts = True
|
|||
|
|
.EnableEvents = True
|
|||
|
|
.StatusBar = False
|
|||
|
|
End If
|
|||
|
|
End With
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
' 辅助函数:检查工作表是否存在
|
|||
|
|
Function WorksheetExists(sheetName As String) As Boolean
|
|||
|
|
On Error Resume Next
|
|||
|
|
WorksheetExists = Not ThisWorkbook.Sheets(sheetName) Is Nothing
|
|||
|
|
On Error GoTo 0
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
' 辅助函数:按名称移除数据透视表
|
|||
|
|
Sub RemovePivotTable(tableName As String)
|
|||
|
|
Dim ws As Worksheet
|
|||
|
|
Dim pt As PivotTable
|
|||
|
|
|
|||
|
|
On Error Resume Next
|
|||
|
|
|
|||
|
|
For Each ws In ThisWorkbook.Worksheets
|
|||
|
|
Set pt = ws.PivotTables(tableName)
|
|||
|
|
If Not pt Is Nothing Then
|
|||
|
|
pt.TableRange2.Clear
|
|||
|
|
Exit For
|
|||
|
|
End If
|
|||
|
|
Next ws
|
|||
|
|
|
|||
|
|
On Error GoTo 0
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
' 辅助函数:查找有数据的最后一行
|
|||
|
|
Function FindLastRow(ws As Worksheet) As Long
|
|||
|
|
On Error Resume Next
|
|||
|
|
FindLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
|
|||
|
|
If FindLastRow = 1 And ws.Cells(1, 1).Value = "" Then FindLastRow = 0
|
|||
|
|
If Err.Number <> 0 Then FindLastRow = 0
|
|||
|
|
On Error GoTo 0
|
|||
|
|
End Function
|
|||
|
|
```
|
|||
|
|
{: id="20251007104110-5m3p17h"}
|
|||
|
|
|
|||
|
|
## 代码功能总结
|
|||
|
|
{: id="20251007104110-9k50axy"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">子程序A</span>:主程序入口,依次调用B和Q子程序
|
|||
|
|
{: id="20251007104110-2p9o3tb"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">子程序B</span>:
|
|||
|
|
{: id="20251007104110-x04g2t3"}
|
|||
|
|
|
|||
|
|
1. {: id="20251007104110-78alrwz"}读取BOM(物料清单)数据并建立字典索引
|
|||
|
|
{: id="20251007104110-y2w6cka"}
|
|||
|
|
2. {: id="20251007104110-jewpl19"}处理Focest数据,与BOM数据进行匹配计算
|
|||
|
|
{: id="20251007104110-pl0ocv2"}
|
|||
|
|
3. {: id="20251007104110-n8npioj"}生成包含物料用量和周数据的输出表
|
|||
|
|
{: id="20251007104110-n4kbxkg"}
|
|||
|
|
4. {: id="20251007104110-buwct96"}记录未匹配的关键部件号到单独工作表
|
|||
|
|
{: id="20251007104110-u57rtfv"}
|
|||
|
|
{: id="20251007104110-mdk4nrh"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">子程序Q</span>:
|
|||
|
|
{: id="20251007104110-epkbb6q"}
|
|||
|
|
|
|||
|
|
1. {: id="20251007104110-ssaf42k"}基于B子程序生成的输出表创建数据透视表
|
|||
|
|
{: id="20251007104110-3zpxiwb"}
|
|||
|
|
2. {: id="20251007104110-can3jf8"}按物料号汇总各周数据
|
|||
|
|
{: id="20251007104110-09i643v"}
|
|||
|
|
3. {: id="20251007104110-l3a8e41"}生成格式化的周汇总报告
|
|||
|
|
{: id="20251007104110-zkavtaf"}
|
|||
|
|
{: id="20251007104110-1k3ztzp"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">辅助函数</span>:提供性能优化、工作表检查、数据透视表管理等实用功能
|
|||
|
|
{: id="20251007104110-p70n2ap"}
|
|||
|
|
|
|||
|
|
### 1. Output工作表(详细计算结果)
|
|||
|
|
{: id="20251007104234-4cu6rrj"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">数据结构:</span>
|
|||
|
|
{: id="20251007104234-e7qb5rr"}
|
|||
|
|
|
|||
|
|
- {: id="20251007104234-0bxv2y0"}<span data-type="strong">A列</span>:父料号
|
|||
|
|
{: id="20251007104234-5oy2qrt"}
|
|||
|
|
- {: id="20251007104234-qbbgzn5"}<span data-type="strong">B列</span>:LIC系数(需求放大系数)
|
|||
|
|
{: id="20251007104234-s5l6uui"}
|
|||
|
|
- {: id="20251007104234-953gcfx"}<span data-type="strong">C列</span>:子料号
|
|||
|
|
{: id="20251007104234-ah37p39"}
|
|||
|
|
- {: id="20251007104234-7u0kb66"}<span data-type="strong">D列</span>:BOM用量比例
|
|||
|
|
{: id="20251007104234-3aqvd95"}
|
|||
|
|
- {: id="20251007104234-rvvnzjk"}<span data-type="strong">E-BH列</span>:56周的需求量计算(周1到周56)
|
|||
|
|
{: id="20251007104234-b69x0xh"}
|
|||
|
|
{: id="20251007104234-txu57xv"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">使用场景</span>:需要查看具体料号层级需求计算明细时使用
|
|||
|
|
{: id="20251007104234-hfslodc"}
|
|||
|
|
|
|||
|
|
### 2. Cutput工作表(需求汇总透视表)
|
|||
|
|
{: id="20251007104234-vwfajdj"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">数据结构:</span>
|
|||
|
|
{: id="20251007104234-6wjn3sj"}
|
|||
|
|
|
|||
|
|
- {: id="20251007104234-l8jf64k"}<span data-type="strong">A列</span>:料号
|
|||
|
|
{: id="20251007104234-xeygha8"}
|
|||
|
|
- {: id="20251007104234-37ijdow"}<span data-type="strong">B列开始</span>:各周需求总和
|
|||
|
|
{: id="20251007104234-9oiu7wj"}
|
|||
|
|
- {: id="20251007104234-95gtdk4"}<span data-type="strong">顶部标题</span>:生成日期和时间戳
|
|||
|
|
{: id="20251007104234-jg6348e"}
|
|||
|
|
{: id="20251007104234-a6cpl7g"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">特点</span>:
|
|||
|
|
{: id="20251007104234-3s8pph1"}
|
|||
|
|
|
|||
|
|
- {: id="20251007104234-2sgzz55"}按料号汇总所有层级的需求
|
|||
|
|
{: id="20251007104234-aecu5sx"}
|
|||
|
|
- {: id="20251007104234-ckeyepe"}便于查看每个料件的总需求趋势
|
|||
|
|
{: id="20251007104234-ddgak02"}
|
|||
|
|
- {: id="20251007104234-l1w1dk0"}支持数据透视表分析
|
|||
|
|
{: id="20251007104234-vrhonpy"}
|
|||
|
|
{: id="20251007104234-v7fuqbi"}
|
|||
|
|
|
|||
|
|
### 3. Unmatched工作表(异常检测)
|
|||
|
|
{: id="20251007104234-5obwvx7"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">内容</span>:在Focest预测中出现但未在BOM中找到的料号清单
|
|||
|
|
{: id="20251007104234-4vrosku"}
|
|||
|
|
|
|||
|
|
<span data-type="strong">处理建议</span>:
|
|||
|
|
{: id="20251007104234-7yxg0wn"}
|
|||
|
|
|
|||
|
|
1. {: id="20251007104234-m5cmb4a"}检查BOM完整性
|
|||
|
|
{: id="20251007104234-3gw0d1b"}
|
|||
|
|
2. {: id="20251007104234-d75r9gt"}确认料号编码是否正确
|
|||
|
|
{: id="20251007104234-nnh20ro"}
|
|||
|
|
3. {: id="20251007104234-cfkg1bl"}更新BOM表数据
|
|||
|
|
{: id="20251007104234-4i4zp0z"}
|
|||
|
|
{: id="20251007104234-7tnqloh"}
|
|||
|
|
|
|||
|
|
## 六、常见错误处理
|
|||
|
|
{: id="20251007103854-k7hdkk4"}
|
|||
|
|
|
|||
|
|
|<span data-type="strong">错误类型</span>|<span data-type="strong">症状</span>|<span data-type="strong">根本原因</span>|<span data-type="strong">解决方案</span>|
|
|||
|
|
| --| ----------| -----------------------| -----------------------------|
|
|||
|
|
|<span data-type="strong">#REF!</span>|引用错误|列索引超出数据范围|检查B1:I1值是否在1-55范围内|
|
|||
|
|
|<span data-type="strong">#VALUE!</span>|值错误|数值列中包含文本数据|清理库存报表中的非数值字符|
|
|||
|
|
|<span data-type="strong">#N/A</span>|查找失败|VLOOKUP未找到匹配料号|验证料号在库存报表中存在|
|
|||
|
|
|<span data-type="strong">透视表不更新</span>|数据陈旧|数据源范围未更新|重新运行宏更新数据源|
|
|||
|
|
|<span data-type="strong">NT函数失效</span>|公式错误|宏功能未启用|保存为.xlsm格式并启用宏|
|
|||
|
|
{: id="20251007103854-tvzkohd" colgroup="|||"}
|
|||
|
|
|
|||
|
|
{: id="20251007103858-2h0t16a"}
|
|||
|
|
|
|||
|
|
{: id="20251007101943-jrwn98j" title="Excel物料需求与库存分析系统" type="doc"}
|