使用VBA小程序提高资产清查效率

  资产清查是一件相当烦人的工作,去年使用LayUI+PHP+MS SQL Server 2014写了一个资产清查的程序,可惜写完了,LayUI已经停止更新了,就没有再完善下去,数据也没有更新,等于就废了。

  今年又要进行资产清查,启用LayUI的程序,快一年没有弄了已经有些陌生了,也来不及整改了,就使用Excel的VBA来进行匹配。

  资产清查,就是资产台账与实物记录进行匹配的,这个是很烦人的工作,因为资产台账和实物台账的数据都不一定准确,要核对好不是一件轻松的事情。

  要手工去核对几乎不可能,比如1500条台账数据,实物也有1500条,核对上做上标记,看似简单,如果一个人做那么特别累,时间长也来不及,多人去做,数据怎样统一和共享是问题,所以,只能由程序来完成。

  实际上工作中,这样的任务需要很短的时间去完成,没有必要开发一个系统来完成,因为界面部分就会耗去大量的时间,而直接使用Excel VBA就是一个不错的选择。

  根据实际需要可以随时修改、优化程序,很大程度上提高了工作效率。

  核对过程:

  1、整理完整的资产台账和实物台账,要求数据必须准确、格式统一;

  2、使用VBA小程序去匹配,可以按指定的条件去匹配,匹配上了就给实物发放一个资产编码;

  3、最严格的匹配条件过后,可能有一些是匹配不上的,需要放松条件去匹配,匹配完成后针对匹配记录发放调配单。比如:因为某某原因,某一台设备由什么变为什么,由某一地点调配至另一地点等。

  4、根据调配单更新资产台账和实物台账,匹配完成。

  下面是代码部分:

  主要涉及VBA的结构体传参、函数和过程调用、快速查找等功能。

  ⑴参数传递的结构体

'获取返回的信息结构体
Type StructGetInfo
    SDW As String   '单位名称
    SGGXH As String '规格型号
    SWZ As String   '位置
    SSYR As String  '使用人
    SRow As String  '匹配的行号
End Type

'参数传递的结构体
Type StructPara
    SDW As String   '单位名称
    SPP As String   '品牌
    SGGXH() As String '规格型号
    SSheetName As String    'sheet名称
    SSrcRow As String       '源数据行
    SZCBM As String         '资产编码
End Type

  ⑵定义共用的方法

Public Sub SetCellValue(SCellName As String, SValue As String)
    '设置单元格的值
    Range(SCellName).Select
    Selection.FormulaR1C1 = SValue
End Sub

Public Function GetCellValue(SCellName As String)
    '获取单元格的值
    Range(SCellName).Select
    GetCellValue = Selection.FormulaR1C1
End Function
Function ContainNumber(Str) As Boolean
    '判断字符串是否包含数字
    ContainNumber = False
    Dim Reg As Object
    Set Reg = CreateObject("vbscript.regexp")
    With Reg
        .Global = True
        .Pattern = "\d{1,}"
        ContainNumber = .Test(Str)
    End With
End Function

Function GetNumberFromChar(Str As String) As String
    '提取字符串中的数字,只提取第一个匹配的结果
    GetNumberFromChar = ""
    Dim Reg As Object
    Dim MatchResult As Object
    Dim ReturnStr As String
    Dim MatchItem As Object
    
    Set Reg = CreateObject("vbscript.regexp")
    With Reg
        .Global = True
        .Pattern = "\d{1,}"
        Set MatchResult = .Execute(Str)
        GetNumberFromChar = MatchResult(0)
'        If MatchResult.Count > 0 Then
'            For Each MatchItem In MatchResult
'                ReturnStr = ReturnStr + MatchItem
'            Next
'            GetNumberFromChar = ReturnStr
'        End If
    End With
End Function

Function ConvertArrToChar(Arr() As String)
    '将字符串数组转换为字符
    Dim IFor As Integer
    Dim IArrLength As Integer   '数组的长度
    Dim Str As String
    
    IArrLength = UBound(Arr) - LBound(Arr) + 1
    For IFor = 0 To IArrLength - 1
        Str = Str + " " + UCase(Arr(IFor))
    Next
    ConvertArrToChar = Str
End Function

  ⑶根据匹配条件进行匹配的函数

Public Function MatchAtMultiCol(MyStructPara As StructPara) As StructMatchInfo
    '根据传递的参数对表格记录进行匹配
    Dim MatchCell_DeviceType As Range, MatchCell_Brand As Range, MatchCell_UnitName As Range, MatchCell_AssetCode As Range, MatchCell_GGXH As Range
    Dim MatchCell_MatchRowSign As Range     '匹配行号
    Dim MatchCell_MatchType As Range        '匹配类型
    Dim MatchCell_MatchMemo As Range        '匹配说明
    Dim MatchCell_RealUnitname As Range     '实际的单位名称
    Dim MatchCell_RealGGXH As Range         '实际的规格型号
    Dim MatchCell_Position As Range         '位置
    Dim MatchCell_UserName As Range         '使用人
    Dim MatchCell_ActionMemo As Range       '操作说明
        
    Dim SMatchRowSign As String             '匹配的行号记录
    Dim SGGXH() As String
    Dim ws As Worksheet
    Dim LastRow As Long
    Dim IFor As Integer
    Dim DawnMatchInfo As StructMatchInfo  '返回信息的结构体
        
    SGGXH = MyStructPara.SGGXH
    Set ws = Worksheets(MyStructPara.SSheetName)
    LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    '设置范围
    Set MatchCell_AssetCode = ws.Range("A2:A" & Trim(Str(LastRow)))     '资产编码
    Set MatchCell_DeviceType = ws.Range("B2:B" & Trim(Str(LastRow)))    '设备类型
    Set MatchCell_Brand = ws.Range("C2:C" & Trim(Str(LastRow)))         '品牌
    Set MatchCell_UnitName = ws.Range("D2:D" & Trim(Str(LastRow)))      '单位名称
    Set MatchCell_GGXH = ws.Range("E2:E" & Trim(Str(LastRow)))          '规格型号
    Set MatchCell_MatchRowSign = ws.Range("F2:F" & Trim(Str(LastRow)))  '记录匹配的行号
    Set MatchCell_MatchType = ws.Range("G2:G" & Trim(Str(LastRow)))     '匹配类型
    Set MatchCell_MatchMemo = ws.Range("H2:H" & Trim(Str(LastRow)))     '匹配说明
    Set MatchCell_RealUnitname = ws.Range("I2:I" & Trim(Str(LastRow)))  '实际单位
    Set MatchCell_RealGGXH = ws.Range("J2:J" & Trim(Str(LastRow)))      '实际规格型号
    Set MatchCell_Position = ws.Range("K2:K" & Trim(Str(LastRow)))      '具体位置
    Set MatchCell_UserName = ws.Range("L2:L" & Trim(Str(LastRow)))      '使用人
    Set MatchCell_ActionMemo = ws.Range("M2:M" & Trim(Str(LastRow)))    '操作说明
        
    DawnMatchInfo.SMatchRow = ""
    DawnMatchInfo.SAssetCode = ""
    MatchAtMultiCol = DawnMatchInfo
    
    For IFor = 1 To LastRow - 1
        SDeviceType = UCase(Trim(MatchCell_DeviceType(IFor).Value))
        SBrand = UCase(Trim(MatchCell_Brand(IFor).Value))
        SUnitName = UCase(Trim(MatchCell_UnitName(IFor).Value))
        StrGGXH = UCase(Trim(MatchCell_GGXH(IFor).Value))
        SMatchRowSign = UCase(Trim(MatchCell_MatchRowSign(IFor).Value))
        
        Select Case MyStructPara.SMatchMethod
                Case 1      '严格匹配
                    If SUnitName = MyStructPara.SUnitName And SDeviceType = MyStructPara.SDeviceType And SBrand = MyStructPara.SBrand And InStr(StrGGXH, SGGXH(0)) > 0 And InStr(StrGGXH, SGGXH(1)) > 0 And SMatchRowSign = "" Then
                        '记录
                        MatchCell_MatchRowSign(IFor).Value = MyStructPara.SSrcRow
                        MatchCell_MatchType(IFor).Value = MyStructPara.SMatchMethod
                        MatchCell_MatchMemo(IFor).Value = "√"
                        MatchCell_RealUnitname(IFor).Value = MyStructPara.SUnitName
                        MatchCell_RealGGXH(IFor).Value = ConvertArrToChar(MyStructPara.SGGXH)
                        MatchCell_Position(IFor).Value = MyStructPara.SPosition
                        MatchCell_UserName(IFor).Value = MyStructPara.SUser
                        MatchCell_ActionMemo(IFor).Value = ""
                                                
                        DawnMatchInfo.SMatchRow = Str(MatchCell_AssetCode(IFor).Row)
                        DawnMatchInfo.SAssetCode = Str(MatchCell_AssetCode(IFor).Value)
                        MatchAtMultiCol = DawnMatchInfo
                        Exit For
                    End If
                    
                Case 2
                        '
                    If SDeviceType = MyStructPara.SDeviceType And SBrand = MyStructPara.SBrand And InStr(StrGGXH, SGGXH(0)) > 0 And InStr(StrGGXH, SGGXH(1)) > 0 And SMatchRowSign = "" Then
                        '记录
                        MatchCell_MatchRowSign(IFor).Value = MyStructPara.SSrcRow
                        MatchCell_MatchType(IFor).Value = MyStructPara.SMatchMethod
                        MatchCell_MatchMemo(IFor).Value = "★"
                        MatchCell_RealUnitname(IFor).Value = MyStructPara.SUnitName
                        MatchCell_RealGGXH(IFor).Value = ConvertArrToChar(MyStructPara.SGGXH)
                        MatchCell_Position(IFor).Value = MyStructPara.SPosition
                        MatchCell_UserName(IFor).Value = MyStructPara.SUser
                        MatchCell_ActionMemo(IFor).Value = "资产调拨单"
                                                
                        DawnMatchInfo.SMatchRow = Str(IFor)
                        DawnMatchInfo.SAssetCode = Str(MatchCell_AssetCode(IFor).Value)
                        MatchAtMultiCol = DawnMatchInfo
                        Exit For
                    End If
                        
                Case 3
                        '
        End Select
        
    Next
End Function

  ⑷实际调用

Sub AssetVerify()
    'Dawn 2023年4月19日
    Dim DawnPara As StructPara              '参数传递的结构体
    Dim DawnMatchInfo As StructMatchInfo    '返回信息的结构体
    
    Dim IFor As Integer
    Dim iFindCount As Integer               '匹配的总数
    Dim DestRow As String                   '在目标表中匹配到的行号
    Dim allEquipment As Integer             '计算机资产表的记录数
    Dim SrcTable As String                  '计算机资产表的名称
    Dim Src_DWMC As String                  '源表的单位名称
    Dim Src_PP As String                    '源表的品牌
    Dim Src_GGXH() As String                '源表的规格型号
    Dim Src_ZCBM As String                  '源表的资产编码
        
    allEquipment = 355
    SrcTable = "实物表"
    DawnPara.SMatchMethod = 1   '单位、品牌、规格型号完全匹配,说明:★
    'DawnPara.SMatchMethod = 2   '品牌、规格型号完全匹配,说明:◎
    'DawnPara.SMatchMother = 3   '品牌、规格型号模糊匹配,说明:模糊匹配
    DawnPara.SSheetName = "资产表"
    
    For IFor = 2 To allEquipment
        '提取源表的单位名称、品牌、规格型号
        Sheets(SrcTable).Activate
        DawnPara.SUnitName = Trim(UCase(GetCellValue("B" + Trim(Str(IFor)))))            '单位名称
        DawnPara.SUser = Trim(UCase(GetCellValue("C" + Trim(Str(IFor)))))                '使用人
        DawnPara.SPosition = Trim(UCase(GetCellValue("D" + Trim(Str(IFor)))))            '位置
        DawnPara.SBrand = Trim(UCase(GetCellValue("E" + Trim(Str(IFor)))))               '品牌
        DawnPara.SDeviceType = Trim(UCase(GetCellValue("F" + Trim(Str(IFor)))))          '设备类型
        DawnPara.SGGXH = Split(Trim(UCase(GetCellValue("G" + Trim(Str(IFor))))), " ")    '规格型号
        DawnPara.SSrcRow = Str(IFor)
        
        If UBound(DawnPara.SGGXH) > 0 And DawnPara.SGGXH(0) <> "" Then
            DawnMatchInfo = MatchAtMultiCol(DawnPara)
            If DawnMatchInfo.SMatchRow <> "" Then
                Call SetCellValue("K" & Trim(Str(IFor)), DawnMatchInfo.SMatchRow)
                Call SetCellValue("L" & Trim(Str(IFor)), DawnMatchInfo.SAssetCode)
                iFindCount = iFindCount + 1
            End If
        End If
    Next
    
    MsgBox "核对完毕!匹配数:" + Str(iFindCount)
End Sub

Sub Init()
    Sheets("实物表").Activate
    For IFor = 2 To 356
        Call SetCellValue("K" & Trim(Str(IFor)), "")
        Call SetCellValue("L" & Trim(Str(IFor)), "")
    Next
    Sheets("资产表").Activate
    For IFor = 2 To 1020
        Call SetCellValue("F" & Trim(Str(IFor)), "")
        Call SetCellValue("G" & Trim(Str(IFor)), "")
        Call SetCellValue("H" & Trim(Str(IFor)), "")
        Call SetCellValue("I" & Trim(Str(IFor)), "")
        Call SetCellValue("J" & Trim(Str(IFor)), "")
        Call SetCellValue("K" & Trim(Str(IFor)), "")
        Call SetCellValue("L" & Trim(Str(IFor)), "")
        Call SetCellValue("M" & Trim(Str(IFor)), "")
    Next
End Sub

  使用VBA程序核对起来很快,1500条数据不到1分钟就核对完成,在数据准确的情况下匹配率令人满意,关键是速度快,省去了不少的时间。
  表面上这个问题似乎简单,但是实际运行过程中并不容易,比如:

  ⑴ 资产表中的规格型号为“ThinkcenterM8500TNO76(单屏”,实际的型号应该为"ThinkCentre M8500t-NO76",核心应该是"M8500tNO76",那么就需要灵活处理,关键是提取其中的数字进行匹配。

  ⑵ 资产表中的规格型号为“联想ThinkCentreM8330TI5-2400”,实际的型号应该为"ThinkCentre M8330t",核心应该是"8330t"。

  ⑶ 资产表中的规格型号为“惠普 288 Pro G6 Microtower PC”,实际的型号应该为"288 Pro G6 MicrotowerPC",核心应该是"288"和"G6"。

  ⑷ 资产表中的规格型号为“LaserJet Pro MFP M227fdw”,核心应该是"M227fdw",因为这个型号的打印机还有“M227cdw“、"M227cdn"。

  等等,太多了,也因为复杂一些,所以很喜欢VBA语言,根据不需要为界面而操作,调试也方便,真是再好不过如此了。

  最方便的脚本语言可能就是JavaScript和VBA了(还有VBScript)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值