Excel сгруппировать несколько столбцов и транспонировать

1036
BeachBum

У меня есть лист Excel, полный компаний, филиалов, данных о компании и контактов.

Исходные данные Excel

Я пытаюсь сгруппировать данные для той же компании и города филиала, а затем транспонировать, чтобы в каждом отдельном столбце у меня была информация о заголовке компании / филиала, затем contact1, contact2, contact3 и т. Д. Затем, следующий столбец, следующая компания / Информация заголовка ветки, затем ее контакты. У каждого контакта должны быть свои имена и фамилии, а также имена, объединенные, и должны быть отсортированы по имени, фамилии.

Желаемый формат

Я хотел бы делать это регулярно для данных (первый снимок), так как они будут часто меняться. Это лучше всего сделать с формулами, VBA, сводной таблицы? Любая помощь будет оценена.

РЕДАКТИРОВАТЬ
Просто добавьте все шаги для элегантного решения Рона, приведенного ниже:
1. Сохраните лист на лист с поддержкой макросов (.xlsm)
2. Убедитесь, что основной лист называется sheet1
3. Создайте пустой целевой лист sheet2
4. Откройте редактор VBA (Alt-F11)
5. Нажмите Вставить, модуль класса, затем вставьте код модуля класса
6. Нажмите F4, чтобы открыть окно свойств модуля класса, затем в поле Имя измените его на cCompanyInfo
7. Нажмите Вставить, Модуль, затем вставьте код обычного модуля
8. Нажмите Инструменты, Ссылки, затем найдите Microsoft Scripting Runtime, установите флажок и нажмите ОК.
9. Вернувшись на рабочий лист, нажмите Alt-F8, чтобы просмотреть макрос, и нажмите «Выполнить».

sheet2 будет заполнен отформатированными данными.

Вы также можете назначить сочетание клавиш для запуска макроса с помощью кнопки «Параметры» в диалоговом окне просмотра макроса.

0
Я бы предложил VBA. Ron Rosenfeld 7 лет назад 0
I'm not a VBA expert. Any ideas on how to do this? BeachBum 7 лет назад 0
Я бы использовал классы и коллекции или словари для объединения данных и создания нужного вам вида продукции. Есть примеры выполнения этого в SO, но ничего такого, что можно было бы поднять напрямую и использовать для ваших целей, из-за необходимости объединения полей контактной информации в одно поле. Ron Rosenfeld 7 лет назад 0

2 ответа на вопрос

0
Tony EE rocketscientist
  • Запишите макрос, назначьте горячую клавишу макроса, затем выполните задачи
  • Скопировать> вставить специальный> транспонировать> поместить курсор [введите]
  • объединить (&) текст, как этот Джо удар, главный хончо с формулами
  • = M5 & "" & M6 & "," & M7
    • где эти ячейки содержат 4 записи. и двойные кавычки содержат пробел и
Ваш метод приведет к вертикальному столбцу для каждой строки, и ОП показывает, что он хочет объединить строки, где компания / филиал одинаковы. Ron Rosenfeld 7 лет назад 0
хорошая точка зрения. В макросе это мешает делать сортировку и Vlookup. и увеличение указателя ячейки интеллектуального фильтра. Ваш результат выглядит хорошо. Это было бы проще в отчете о доступе Tony EE rocketscientist 7 лет назад 0
0
Ron Rosenfeld

Я сделал несколько изменений в ваших исходных данных.

В частности, я добавил последнюю строку, которая имеет ABC Corp.неправильный порядок, а также отличается Noteот других записей.

Вы можете увидеть, как это обрабатывается в кодировке, и, если необходимо, вы можете использовать похожую технику, если у вас также были разные телефонные номера.

Для телефонных номеров я удалил нечисловые элементы, чтобы они могли отображаться в едином формате, если они введены непоследовательно. Возможно, вам придется изменить этот алгоритм в зависимости от изменчивости ваших реальных данных.

Я сделал некоторое форматирование, чтобы результаты выглядели хорошо. Вы можете предпочесть ни одного или другое форматирование. Вам также может понадобиться настроить имена рабочих листов в обычном модуле.

Обязательно прочитайте и поймите код и примечания, чтобы иметь возможность поддерживать это в будущем.

Исходные данные :

Модуль класса

Обязательно переименуйте этот cCompanyInfo

Option Explicit 'Rename this class module: cCompanyInfo  Const dictKey = 1 Const dictItem = 2  Private pCompany As String Private pBranch As String Private pPhone As Currency Private pNote As String Private pNotes As Dictionary Private pFirstName As String Private pLastName As String Private pTitle As String Private pNameTitles As Dictionary  Public Property Get Company() As String Company = pCompany End Property Public Property Let Company(Value As String) pCompany = Value End Property  Public Property Get Branch() As String Branch = pBranch End Property Public Property Let Branch(Value As String) pBranch = Value End Property  Public Property Get Phone() As Currency Phone = pPhone End Property Public Property Let Phone(Value As Currency) pPhone = Value End Property  Public Property Get Note() As String Note = pNote End Property Public Property Let Note(Value As String) pNote = Value End Property  Public Property Get FirstName() As String FirstName = pFirstName End Property Public Property Let FirstName(Value As String) pFirstName = Value End Property  Public Property Get LastName() As String LastName = pLastName End Property Public Property Let LastName(Value As String) pLastName = Value End Property  Public Property Get Title() As String Title = pTitle End Property Public Property Let Title(Value As String) pTitle = Value End Property  Public Property Get Notes() As Dictionary Set Notes = pNotes End Property Public Function ADDNote(Value As String) If Not pNotes.Exists(Value) Then pNotes.Add Value, Value End Function  Public Property Get NameTitles() As Dictionary Set NameTitles = pNameTitles End Property Public Function ADDNameTitle(S As String) If Not pNameTitles.Exists(S) Then pNameTitles.Add S, S End Function  Private Sub Class_Initialize() Set pNotes = New Dictionary Set pNameTitles = New Dictionary End Sub  'Dictionary Sort routine 'Shamelessly copied From https://support.microsoft.com/en-us/kb/246067  Public Sub SortDictionary(objDict, intSort) ' declare our variables Dim strDict() Dim objKey Dim strKey, strItem Dim X, Y, Z  ' get the dictionary count Z = objDict.Count  ' we need more than one item to warrant sorting If Z > 1 Then ' create an array to store dictionary information ReDim strDict(Z, 2) X = 0 ' populate the string array For Each objKey In objDict strDict(X, dictKey) = CStr(objKey) strDict(X, dictItem) = CStr(objDict(objKey)) X = X + 1 Next  ' perform a a shell sort of the string array For X = 0 To (Z - 2) For Y = X To (Z - 1) If StrComp(strDict(X, intSort), strDict(Y, intSort), vbTextCompare) > 0 Then strKey = strDict(X, dictKey) strItem = strDict(X, dictItem) strDict(X, dictKey) = strDict(Y, dictKey) strDict(X, dictItem) = strDict(Y, dictItem) strDict(Y, dictKey) = strKey strDict(Y, dictItem) = strItem End If Next Next  ' erase the contents of the dictionary object objDict.RemoveAll  ' repopulate the dictionary with the sorted information For X = 0 To (Z - 1) objDict.Add strDict(X, dictKey), strDict(X, dictItem) Next  End If  End Sub 

Обычный модуль

Option Explicit 'Set Reference to Microsoft Scripting Runtime  Sub ConsolidateCompanyInfo() Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range Dim vSrc As Variant, vRes As Variant Dim cCI As cCompanyInfo, dictCI As Dictionary Dim sNT As String Dim I As Long, J As Long, L As Currency, S As String Dim LastRow As Long, LastCol As Long  'Change worksheets names as appropriate Set wsSrc = Worksheets("sheet1") Set wsRes = Worksheets("sheet2") Set rRes = wsRes.Cells(1, 1)  'Read the data into an array With wsSrc LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column vSrc = .Range(.Cells(1, 1), .Cells(LastRow, LastCol)) End With  'Organize and Collect the data Set dictCI = New Dictionary For I = 2 To UBound(vSrc, 1) Set cCI = New cCompanyInfo With cCI .Company = vSrc(I, 1) .Branch = vSrc(I, 2)  'Remove non-numeric characters from phone number for consistency 'might need to add other Replace functions, or use Regex L = Replace(vSrc(I, 3), "-", "")  .Phone = L .Note = vSrc(I, 4) .ADDNote .Note .FirstName = vSrc(I, 5) .LastName = vSrc(I, 6) .Title = vSrc(I, 7) sNT = .FirstName & " " & .LastName & ", " & .Title .ADDNameTitle sNT S = .Company & "|" & .Branch If Not dictCI.Exists(S) Then dictCI.Add S, cCI Else dictCI(S).ADDNote .Note dictCI(S).ADDNameTitle sNT End If End With Next I  'Populate Results array Dim V, W I = 0  'First need to size the sections Const lHeader As Long = 3 'Name, Branch, Phone number Rows Dim lNotes As Long Dim lContacts As Long  For Each V In dictCI With dictCI(V) lNotes = IIf(lNotes > .Notes.Count, lNotes, .Notes.Count) lContacts = IIf(lContacts > .NameTitles.Count, lContacts, .NameTitles.Count) End With Next V  ReDim vRes(1 To lHeader + 1 + lNotes + 1 + lContacts, 1 To dictCI.Count)  J = 0 For Each V In dictCI J = J + 1 With dictCI(V) vRes(1, J) = .Company vRes(2, J) = .Branch vRes(3, J) = .Phone I = lHeader + 1  For Each W In .Notes I = I + 1 vRes(I, J) = .Notes(W) Next W  I = lHeader + 1 + lNotes + 1  .SortDictionary .NameTitles, 1 For Each W In .NameTitles I = I + 1 vRes(I, J) = .NameTitles(W) Next W End With  Next V  'Write the results Set rRes = rRes.Resize(UBound(vRes, 1), UBound(vRes, 2)) With rRes .EntireColumn.Clear .Value = vRes  'Do some formatting to pretty things up 'You could certainly do something different Range(.Rows(1), .Rows(lHeader)).Style = "Input" Range(.Rows(lHeader + 2), .Rows(lHeader + 1 + lNotes)).Style = "Note" Range(.Rows(lHeader + 1 + lNotes + 2), .Rows(lHeader + 1 + lNotes + 1 + lContacts)).Style = "Output" With .Rows(3) 'Format the phone number .NumberFormat = "000-000-0000" .HorizontalAlignment = xlLeft End With .EntireColumn.AutoFit End With  End Sub 

Результаты :

this looks great, and just what I need. Now I just need to figure out how to integrate this all into Excel properly. Any hints/tips on that would be appreciated. BeachBum 7 лет назад 0
why do you do this when Access wizard is so much easier to create a report view/EXPORT to target app.. I guess as always the best method or tool is ONE you know. Tony EE rocketscientist 7 лет назад 0
@BeachBum Start by doing an Internet Search for "Introduction to VBA" and start getting familiar. Ron Rosenfeld 7 лет назад 0
@TonyStewart Please provide an answer using your tool of choice. That would help others get familiar with what is available. Ron Rosenfeld 7 лет назад 0
@BeachBum Glad to see you were able to figure out how to use the solution. If it is providing the desired results, can you please mark my response as the answer? Tks. Ron Rosenfeld 7 лет назад 0

Похожие вопросы