Excel VBA记录订购

时间:2011-10-10 15:45:36

标签: excel vba

我有以下数据

 Empid       Empname   salary   Company   location   status

    x1         Phil       50      IBM        us
    x2         Karl       30      IBM        us
    x3         Steve      20      IBM        us
    x4         jacob      70      Oracle     uk
    x5         jason      30      Oracle     uk
    x6         stuart     50      Oracle     uk
    zz         jay        150      Oracle    uk
   x10         Steve1     20      IBM        ind
    x9         Steve2     20      IBM        nj
    xx         Jhon      100      IBM        us   

我必须编写一个VB宏来根据公司和位置分隔记录。所以我将得到两组记录

首先设置

Empid     Empname   salary   company    Location  status
    xx        Jhon             100      IBM           us   
    x1        Phil             50       IBM          us
    x2        Karl             30       IBM         us
    x3        Steve            20       IBM         us

第二组

   Empid     Empname   salary   company  Location  status
    x4        jacob      70       Oracle    uk
    x5        jason      30       Oracle    uk
    x6        stuart     50       Oracle    uk
    zz        jay       150       Oracle    uk

以下代码的工作原理: 首先在公司和位置上获得不同的数据集。之后它将基于主记录XX或zz过滤掉。如果该集合中的任何主记录那么它将考虑整个集合。最后在每个集合中在主记录数量上比较所有其他子记录数量。如果它匹配,那么我将复制到新工作表。

下面的代码工作正常,如果主记录xx,zz按顺序排列到子记录之后。如果我把最后一条记录放在表格“xx Jhon 100 IBM us”中。它工作得非常好。否则它不起作用。

VBA大师。对此表示赞赏。

代码iam尝试

Sub tester()

    Const COL_EID As Integer = 1
    Const COL_comp As Integer = 4
    Const COL_loc As Integer = 5
    Const COL_sal As Integer = 3
    Const COL_S As Integer = 6
    Const VAL_DIFF As String = "XXdifferentXX"

    Dim d As Object, sKey As String, sKey1 As String, id As String
    Dim rw As Range, opt As String, rngData As Range
    Dim rngCopy As Range, goodId As Boolean, goodId1 As Boolean
    Dim FirstPass As Boolean, arr, arr1

    Dim sal As Integer
    Dim colsal As Integer
    Dim mastersal As Integer
    Dim status As Boolean
    Dim status1 As Boolean

        With Sheet1.Range("A1")
            Set rngData = .CurrentRegion.Offset(1).Resize( _
                             .CurrentRegion.Rows.Count - 1)
        End With
        Set rngCopy = Sheet2.Range("A1")
         FirstPass = True
        SecondPass = False
      status = False
       Set a = CreateObject("scripting.dictionary")

        Set d = CreateObject("scripting.dictionary")


    redo:

        For Each rw In rngData.Rows

            sKey = rw.Cells(COL_comp).Value & "<>" & _
                   rw.Cells(COL_loc).Value
            sKey1 = rw.Cells(COL_comp).Value & "<>" & _
                   rw.Cells(COL_loc).Value
            colsal = rw.Cells(COL_sal).Value
            If FirstPass Then
              id = rw.Cells(COL_EID).Value
              goodId = (id = "xx" Or id = "zz")

              If d.exists(sKey) Then
                  arr = d(sKey) 'can't modify the array in situ...

                  If goodId Then arr(0) = True
                  d(sKey) = arr 'return [modified] array

              Else
                  d.Add sKey, Array(goodId)
            End If
            End If

            If SecondPass Then
              id = rw.Cells(COL_EID).Value
              goodId1 = (id = "xx" Or id = "zz")

             If d(sKey)(0) = True Then
             If goodId1 Then mastersal = rw.Cells(COL_sal).Value
             If a.exists(sKey1) Then
                  arr1 = a(sKey1) 'can't modify the array in situ...

                  If goodId1 = False Then sal = sal + colsal
                   If mastersal = sal Then arr1(0) = True



                  'If goodId1 Then arr1(0) = True
                  a(sKey1) = arr1 'return [modified] array

              Else
                  a.Add sKey1, Array(status)
                  sal = 0
                   If goodId1 = False Then sal = sal + colsal
            End If

            End If
            End If

             If FirstPass = False And SecondPass = False Then
            If d(sKey)(0) = True Then
              If a(sKey1)(0) = True Then
                  rw.Copy rngCopy
                  Set rngCopy = rngCopy.Offset(1, 0)
             End If
            End If
            End If


        Next rw
        If SecondPass Then
            SecondPass = False
            GoTo redo
        End If
        If FirstPass Then
            FirstPass = False
            SecondPass = True
            colsal = 0
            GoTo redo
        End If

    End Sub

有人可以帮我这个吗?

1 个答案:

答案 0 :(得分:2)

我会使用类模块。这是一个前期工作,但更容易阅读和维护。首先,将类模块插入到项目中,并将其命名为CEmployee。此代码在CEmployee

Option Explicit

Private mlEmployeeID As Long
Private msEmpid As String
Private msEmpName As String
Private mdSalary As Double
Private msCompany As String
Private msLocation As String

Private Const msDELIM As String = "|"

Public Property Get Location() As String: Location = msLocation: End Property
Public Property Let Location(ByVal sLocation As String): msLocation = sLocation: End Property
Public Property Get Company() As String: Company = msCompany: End Property
Public Property Let Company(ByVal sCompany As String): msCompany = sCompany: End Property
Public Property Get Salary() As Double: Salary = mdSalary: End Property
Public Property Let Salary(ByVal dSalary As Double): mdSalary = dSalary: End Property
Public Property Get EmpName() As String: EmpName = msEmpName: End Property
Public Property Let EmpName(ByVal sEmpName As String): msEmpName = sEmpName: End Property
Public Property Get Empid() As String: Empid = msEmpid: End Property
Public Property Let Empid(ByVal sEmpid As String): msEmpid = sEmpid: End Property
Public Property Get EmployeeID() As Long: EmployeeID = mlEmployeeID: End Property
Public Property Let EmployeeID(ByVal lEmployeeID As Long): mlEmployeeID = lEmployeeID: End Property

Public Property Get CompLoc() As String

    CompLoc = Me.Company & msDELIM & Me.Location

End Property

Public Property Get IsMaster() As Boolean

    IsMaster = Me.Empid = String(2, Left$(Me.Empid, 1))

End Property

接下来,在CEmployees中插入另一个类模块和名称(复数)。您必须修改此模块,如http://www.dailydoseofexcel.com/archives/2010/07/04/custom-collection-class/所示,以便能够使用For Each循环访问对象。 CEmployees的代码是

Option Explicit

Private mcolEmployees As Collection

Private Sub Class_Initialize()
    Set mcolEmployees = New Collection
End Sub

Private Sub Class_Terminate()
    Set mcolEmployees = Nothing
End Sub

Public Property Get NewEnum() As IUnknown
    Set NewEnum = mcolEmployees.[_NewEnum]
End Property

Public Sub Add(clsEmployee As CEmployee)
    If clsEmployee.EmployeeID = 0 Then
        clsEmployee.EmployeeID = Me.Count + 1
    End If

    mcolEmployees.Add clsEmployee, CStr(clsEmployee.EmployeeID)
End Sub

Public Property Get Employee(vItem As Variant) As CEmployee
    Set Employee = mcolEmployees.Item(vItem)
End Property

Public Property Get Count() As Long
    Count = mcolEmployees.Count
End Property

Public Sub FillFromRange(rRng As Range)

    Dim rCell As Range
    Dim clsEmployee As CEmployee

    For Each rCell In rRng.Columns(1).Cells
        Set clsEmployee = New CEmployee
        With clsEmployee
            .Empid = rCell.Value
            .EmpName = rCell.Offset(0, 1).Value
            .Salary = rCell.Offset(0, 2).Value
            .Company = rCell.Offset(0, 3).Value
            .Location = rCell.Offset(0, 4).Value
        End With
        Me.Add clsEmployee
    Next rCell

End Sub

Public Property Get UniqueCompLoc() As Collection

    Dim colReturn As Collection
    Dim clsEmployee As CEmployee

    Set colReturn = New Collection

    For Each clsEmployee In Me
        On Error Resume Next
            colReturn.Add clsEmployee.CompLoc, clsEmployee.CompLoc
        On Error GoTo 0
    Next clsEmployee

    Set UniqueCompLoc = colReturn

End Property

Public Property Get FilterCompLoc(sCompLoc As String) As CEmployees

    Dim clsEmployee As CEmployee
    Dim clsReturn As CEmployees

    Set clsReturn = New CEmployees

    For Each clsEmployee In Me
        With clsEmployee
            If .CompLoc = sCompLoc Then
                clsReturn.Add clsEmployee
            End If
        End With
    Next clsEmployee

    Set FilterCompLoc = clsReturn


End Property

Public Property Get SalaryMatch() As Boolean

    Dim clsEmployee As CEmployee
    Dim dSalary As Double, dMaster As Double

    For Each clsEmployee In Me
        If clsEmployee.IsMaster Then
            dMaster = clsEmployee.Salary
        Else
            dSalary = dSalary + clsEmployee.Salary
        End If
    Next clsEmployee

    SalaryMatch = dMaster = dSalary

End Property

Public Property Get OutputToRange() As Variant

    Dim aReturn() As Variant
    Dim clsEmployee As CEmployee
    Dim i As Long

    ReDim aReturn(1 To Me.Count, 1 To 5)

    For Each clsEmployee In Me
        i = i + 1
        With clsEmployee
            aReturn(i, 1) = .Empid
            aReturn(i, 2) = .EmpName
            aReturn(i, 3) = .Salary
            aReturn(i, 4) = .Company
            aReturn(i, 5) = .Location
        End With
    Next clsEmployee

    OutputToRange = aReturn

End Property

最后,将标准模块添加到项目中并包含此代码。

Option Explicit

Public gclsEmployees As CEmployees

Sub CopyRanges()

    Dim clsEmployee As CEmployee
    Dim clsFiltered As CEmployees
    Dim colCompLoc As Collection
    Dim i As Long
    Dim rNext As Range
    Dim vaOutput As Variant

    Sheet2.UsedRange.ClearContents

    'Create a new CEmployees and fill it with CEmployee objects
    Set gclsEmployees = New CEmployees
    gclsEmployees.FillFromRange Sheet1.Range("A2:E11")

    'Get a list of unique company/location combinations
    Set colCompLoc = gclsEmployees.UniqueCompLoc

    'loop through the unique combinations
    For i = 1 To colCompLoc.Count
        'create a new CEmployees containing only that combination
        Set clsFiltered = gclsEmployees.FilterCompLoc(colCompLoc(i))
        'if the salaries add up to the master
        If clsFiltered.SalaryMatch Then
            'write the employee out to sheet2
            Set rNext = Sheet2.Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(1, 0)
            vaOutput = clsFiltered.OutputToRange
            rNext.Resize(UBound(vaOutput, 1), UBound(vaOutput, 2)).Value = vaOutput
        End If
    Next i

End Sub

您可以看到我在http://dl.dropbox.com/u/1347353/FilterEmployees.xls

创建的示例文件