将Excel表中的项列表转换为逗号分隔的字符串

时间:2013-04-01 17:22:25

标签: excel excel-vba vba

我在Excel(表1)中有一个表,其中包含以下列标题:员工姓名,州许可和许可状态。该表的一个样本是:

John Adams  NY  Active
John Adams  PA  Active
John Adams  NJ  Inactive
Ralph Ames  MS  Active
Ed Turner   MS  Pending

我想设置一个摘要选项卡,每个员工有一行,其中包含活动许可证,待处理许可证和非活动许可证的列,这些单元格将显示相应状态代码的逗号分隔列表。例如:

Name        Active   Pending   Inactive
John Adams  NY, PA             NJ
Ralph Ames  MS
Ed Turner            MS

我只是对进入此自定义列表的最佳方式感到好奇。我编写了下面的函数似乎工作正常,它运行速度比我预期的要快,但它似乎效率低,因为它每次都循环遍历整个表,并且我已经将引用此函数的公式粘贴到几百个单元格中:< / p>

Function comma_state_list(the_name As String, the_status As String) As String
    Dim ws As Worksheet
    Dim oLo As ListObject
    Dim oCol As ListColumns

    Set ws = Worksheets("State Licenses")
    Set oLo = ws.ListObjects("Table1")
    Set oCol = oLo.ListColumns

    For i = 1 To oLo.ListRows.Count
        If oLo.Range(i, 1).Value = the_name And oLo.Range(i, 3) = the_status Then
            comma_state_list = comma_state_list & oLo.Range(i, 4) & ", "
        End If
    Next i

    If Len(comma_state_list) = 0 Then
        comma_state_list = ""
    Else
        comma_state_list = Left(comma_state_list, Len(comma_state_list) - 2)
    End If
End Function

有没有办法可以使用VBA对表运行类似SQL的查询,所以我只是每次都循环遍历SQL结果而不是整个表?我认为这也有助于按字母顺序排列摘要列表。或许还有其他一些我没想到的更好的方式。

1 个答案:

答案 0 :(得分:1)

好的,这是使用Scripting Dictionaries的示例。

我在一个工作表上有这个表:

Initial table list of license status by state

输出应生成一个包含以下摘要数据的新工作表:

Output summary data one row per employee name

我试图将其记录得非常彻底,但如果您对此有任何疑问,请与我联系。

Option Explicit
Sub Test()

Dim wsCurr As Worksheet: Set wsCurr = ActiveSheet
Dim wsNew As Worksheet 'output container'
Dim rowNum As Long 'row number for output'

'Scripting dictionaries:'
Dim inactiveDict As Object
Dim activeDict As Object
Dim key As Variant

'Table variables'
Dim rng As Range 'table of data'
Dim r As Long 'row iterator for the table range.'

'information about each employee/row'
Dim empName As String
Dim state As String
Dim status As String

'Create our dictionaries:'
Set activeDict = Nothing
Set inactiveDict = Nothing
Set activeDict = CreateObject("Scripting.Dictionary")
Set inactiveDict = CreateObject("Scripting.Dictionary")

Set rng = Range("A1:C6") 'better to set this dynamically, this is just an example'

For r = 2 To rng.Rows.Count
    empName = rng(r, 1).Value
    state = rng(r, 2).Value
    status = rng(r, 3).Value

    Select Case UCase(status)
        Case "ACTIVE"
            AddItemToDict activeDict, empName, state

        Case "INACTIVE"

            AddItemToDict inactiveDict, empName, state

    End Select
Next

'Add a new worksheet with summary data'

Set wsNew = Sheets.Add(After:=wsCurr)
With wsNew
    .Cells(1, 1).Value = "Name"
    .Cells(1, 2).Value = "Active"
    .Cells(1, 3).Value = "Inactive"

    rowNum = 2

    'Create the initial table with Active licenses'
    For Each key In activeDict
        .Cells(rowNum, 1).Value = key
        .Cells(rowNum, 2).Value = activeDict(key)
        rowNum = rowNum + 1
    Next

    'Now, go over this list with inactive licenses'
    For Each key In inactiveDict
        If activeDict.Exists(key) Then
            rowNum = Application.Match(key, .Range("A:A"), False)
        Else:
            rowNum = Application.WorksheetFunction.CountA(wsNew.Range("A:A")) + 1
            .Cells(rowNum, 1).Value = key
        End If

        .Cells(rowNum, 3).Value = inactiveDict(key)
    Next
End With

'Cleanup:
Set activeDict = Nothing
Set inactiveDict = Nothing


End Sub


Sub AddItemToDict(dict As Object, empName As String, state As String)
'since we will use the same methods on both dictionary objects, '
' it would be best to subroutine this action:'
Dim key As Variant

'check to see if this employee already exists'
If UBound(dict.Keys) = -1 Then
    dict.Add empName, state
Else:
    If Not dict.Exists(empName) Then
    'If IsError(Application.Match(empName, dictKeys, False)) Then
        'employee doesn't exist, so add to the dict'
        dict.Add empName, state
    Else:
        'employee does exist, so update the list:'
        'concatenate the state list'
        state = dict(empName) & ", " & state
        'remove the dictionary entry'
        dict.Remove empName
        'add the updated dictionary entry'
        dict.Add empName, state
    End If
End If

End Sub