Я пытаюсь создать новые рабочие книги для каждой группы, найденной на листе 10, на основе списка имен групп из другого листа с именем GroupFileNames.
Чтобы упростить устранение неполадок, текущий код создает новые рабочие листы вместо рабочих книг. У меня уже есть код, необходимый для создания книг.
Моя проблема в том, что мой код не будет перебирать список имен групп. Он создает лист для первой группы (ABC Corp) и копирует соответствующие данные, но никогда не создает лист для следующей группы (XYZ Corp).
Я пробовал разные способы зацикливания, используя «До», «Для каждого» и т. д.
Sub CreateWkBookByGroupName()
Dim Transaction() As Variant
Dim GroupNameTransactions() As Variant
Dim TransactionCounter As Long
Dim GpnTransactionCounter As Long
Dim Counter As Long
Dim i As Integer
Dim gfn As Worksheet
Set gfn = ThisWorkbook.Sheets("GroupFileNames")
Dim groupName As String
i = 1
groupName = gfn.Range("A" & i)
'Store entire database in the Transaction array
Transaction = Range("A1").CurrentRegion
'Starting in the i row of the database loop through each transaction
For TransactionCounter = i To UBound(Transaction, 1)
'If the thirteenth column contains a value equal to groupName...
If Transaction(TransactionCounter, 13) = groupName Then
'...increase the GpnTransactionCounter by 1
GpnTransactionCounter = GpnTransactionCounter + 1
'Redimension the GroupNameTransaction array with each instance _
of a GroupName transaction.
ReDim Preserve _
GroupNameTransactions(1 To 13, 1 To GpnTransactionCounter)
'Start a counter to populate the GroupNameTransactions array
For Counter = 1 To 13
'The GroupNameTransactions array equals the current transaction
GroupNameTransactions(Counter, GpnTransactionCounter) _
= Transaction(TransactionCounter, Counter)
Next Counter
End If
Next TransactionCounter
'Add a new sheet
Worksheets.Add
'Add the headings in the first row of the Transactions array
Range("A1:M1") = Transaction
'Transpose the GroupNameTransaction array onto the new sheet
Range("A2", Range("A2").Offset(GpnTransactionCounter - 1, 12)) _
= Application.Transpose(GroupNameTransactions)
'Autofit columns
Columns.AutoFit
End Sub
Эти данные должны создать два новых листа, один для ABC Corp, а другой для XYZ Corp. На каждом новом листе должны быть все столбцы, принадлежащие их группе.
Это список имен групп, которые мой код использует для сравнения с именами групп на Листе 10.
Вы называете свою таблицу Excel базой данных. Я думаю, что инструмент, который вам действительно нужен, — это база данных. Вы пытаетесь сделать представления из данных. Не изменяйте данные, чтобы создать представление. Пробовали войти в MS Access?
Если вам нужно создать новые листы, которые являются подмножеством сгруппированных данных, то вложенный словарь сценариев является полезной структурой данных.
Option Explicit
Sub CreateWkBookByGroupName()
Dim myTransactionsGroupedByName As Scripting.Dictionary
Set myTransactionsGroupedByName = PopulateTransactionsByGroupName
Dim myGroup As Variant
Dim myWS As Excel.Worksheet
For Each myGroup In myTransactionsGroupedByName
With myTransactionsGroupedByName
Set myWS = CreateSheetForGroupName(.Item(myGroup))
myWS.Name = myGroup
End With
Next
End Sub
Public Function CreateSheetForGroupName(ByVal NamedGroup As Scripting.Dictionary) As Excel.Worksheet
Static myHeadingRow As Excel.Range
If myHeadingRow Is Nothing Then
Set myHeadingRow = NamedGroup.Item(0)
Set CreateSheetForGroupName = Nothing
Exit Function
End If
Dim myWS As Excel.Worksheet
Set myWS = ThisWorkbook.Worksheets.Add
myWS.Range("A1").Value = myHeadingRow
myHeadingRow.Copy Destination:=myWS.Range("A1")
Dim myTransaction As Variant
For myTransaction = 0 To NamedGroup.Count - 1
NamedGroup(myTransaction).Copy Destination:=myWS.Range("A" & CStr(myTransaction + 2))
Next
Set CreateSheetForGroupName = myWS
End Function
Public Function PopulateTransactionsByGroupName() As Scripting.Dictionary
Const GroupNameColumn As Long = 13 'Column number for Group Names
Dim myTransaction As Variant
Dim myGroupedByName As Scripting.Dictionary
Set myGroupedByName = New Scripting.Dictionary
For Each myTransaction In Range("A1").CurrentRegion.Rows
Dim GroupName As String
GroupName = myTransaction.Columns(GroupNameColumn).Cells(1, 1).Value
With myGroupedByName
If Not .exists(GroupName) Then
' First entry will be the heading rows with a key of "GroupName"
.Add GroupName, New Scripting.Dictionary
End If
With .Item(GroupName)
.Add .Count, myTransaction
End With
End With
Next
Set PopulateTransactionsByGroupName = myGroupedByName
End Function
Спасибо за ваш ответ. Когда я пытаюсь запустить ваш код, я получаю сообщение об ошибке компиляции: определяемый пользователем тип не определен. Строка с Public Function CreateSheetForGroupName(ByVal NamedGroup As Scripting.Dictionary) As Excel.Worksheet выделена после ошибки. Что может быть причиной этой ошибки?
Вам нужно добавить ссылку на среду выполнения сценариев Microsoft (Tools.References) или изменить New Scripting.Dictionary на CreateObject("Scripting.Dictionary"). Первый позволяет IntelliSense из-за раннего связывания, второй не предлагает IntelliSense, так как связывается поздно. Если вы новичок в VBA или Scripting.DIctionaries, я бы рекомендовал первый подход.
Я добавил ссылку на среду выполнения сценариев, как вы советовали, но теперь есть новая ошибка. Ошибка выполнения '91': переменная объекта или переменная блока не установлена. Выделенная строка — это строка 15, которая читается как myWS.Name = myGroup.
Используйте окно locals, чтобы посмотреть значения переменных в затронутом методе. Это должно помочь вам понять, что происходит. Код отлично работал на моем ПК с использованием предоставленного вами примера набора данных.
Я просмотрел ваш код и заметил, что myWs = Nothing. Выданное пришло из публичной функции CreateSheetForGroupName. Переменная myHeadingRow не инициализируется значением. Поэтому оператор If запускается, а затем выходит из функции, устанавливающей myWs = Nothing. Я добавил Set myHeadingRow = ActiveSheet.Range("A1:L1") после объявления, и все работает отлично! БОЛЬШОЕ СПАСИБО за потраченное время и усилия! С НОВЫМ ГОДОМ!
Это можно сделать проще с помощью фильтра.