#excel #vba
#превосходить #vba
Вопрос:
Я хочу объединить данные из нескольких листов и книг с разными заголовками столбцов в одно имя листа (база данных) с помощью vba. В настоящее время у меня есть приведенный ниже код, который открывает две книги и копирует листы в целевую книгу. Затем в настоящее время (лист базы данных) в целевой книге есть фиксированные заголовки, которые затем сопоставляются с заголовками на всех скопированных листах, а затем копируются все данные строк и вставляются в лист базы данных для соответствующего заголовка столбца.
Sub CopySheetFromClosedWB() Application.ScreenUpdating = False Dim closedBook1 As Workbook Dim closedBook2 As Workbook Set closedBook1 = Workbooks.Open("C:New folderExec_072021.xlsb", Password:="**********") Set closedBook2 = Workbooks.Open("C:New folderNon Exec_072021.xlsb", Password:="**********") Dim ws1 As Worksheet For Each ws1 In closedBook1.Sheets ws1.Copy After:=ThisWorkbook.Sheets(3) ActiveSheet.Name = ActiveSheet.Name amp; "_Exec" If ActiveSheet.AutoFilterMode Then ActiveSheet.AutoFilterMode = False End If Next ws1 closedBook1.Close SaveChanges:=False Dim ws2 As Worksheet For Each ws2 In closedBook2.Sheets ws2.Copy After:=ThisWorkbook.Sheets(3) ActiveSheet.Name = ActiveSheet.Name amp; "_NonExec" If ActiveSheet.AutoFilterMode Then ActiveSheet.AutoFilterMode = False End If Next ws2 closedBook2.Close SaveChanges:=False Call UpDateData MsgBox "Database Created!!" Application.ScreenUpdating = True End Sub
Sub UpDateData() Application.ScreenUpdating = False Dim i As Long, j As Long, k As Long, n As Long, wData As Worksheet, _ Process(1 To 10) As String, iProc As Long, Dict As Object Process(1) = "Manila_Exec" Process(2) = "Cebu_Exec" Process(3) = "Davao_Exec" Process(4) = "CDO_Exec" Process(5) = "Bacolod_Exec" Process(6) = "Manila_NonExec" Process(7) = "Cebu_NonExec" Process(8) = "Davao_NonExec" Process(9) = "CDO_NonExec" Process(10) = "Bacolod_NonExec" Set wData = Sheets("Database") Set Dict = CreateObject("Scripting.Dictionary") With wData .UsedRange.Offset(1).Clear For j = 1 To .Cells(1, .Columns.Count).End(xlToLeft).Column If Len(.Cells(1, j)) gt; 0 Then Dict.Add LCase$(.Cells(1, j)), j Next j End With i = 2 For iProc = 1 To 10 With Sheets(Process(iProc)) n = .Cells(.Rows.Count, 1).End(xlUp).Row For j = 1 To .Cells(1, .Columns.Count).End(xlToLeft).Column If Dict.exists(LCase$(.Cells(1, j))) Then k = Dict(LCase$(.Cells(1, j))) .Cells(2, j).Resize(n - 1).Copy wData.Cells(i, k).Resize(n - 1) End If Next j End With i = i n - 1 Next iProc Sheets("Database").Select Selection.CurrentRegion.Select Selection.CurrentRegion.Font.Size = 9 Selection.CurrentRegion.Font.Name = "Calibri" Selection.CurrentRegion.Borders.LineStyle = x1None For x = 1 To ActiveSheet.UsedRange.Columns.Count Columns(x).EntireColumn.AutoFit Next x End Sub
Я пытаюсь создать код, который может устранить зависимость перемещения листов из нескольких книг в целевую книгу и скопировать значения вместе с именами заголовков для всех совпадающих и несопоставимых заголовков столбцов.
Заголовки находятся в строке 1 во всех рабочих листах.
Всего строк — 50000
Всего столбцов — 170
Комментарии:
1. Что должно произойти с несопоставимыми столбцами? Является ли ваш лист базы данных пустым, когда вы начинаете процесс? Содержит ли он уже заголовки? К вашему сведению, если вы опубликуете код fome в другом месте (например. ваш
UpdateData
метод) полезно сообщить нам, что вы не писали его сами, иначе мы получим неверное представление о том, насколько вам комфортно с VBA, и зададимся вопросом, почему вы задаете этот вопрос 😉2. Лист базы данных в начале пуст. Я хочу добавить столбцы со всех разных листов в один. (некоторые заголовки столбцов существуют в других файлах , а некоторые-нет), поэтому я хотел добавить все заголовки столбцов вместе с данными строк. Я плохо разбираюсь в vba и взял функцию updateData у сообщества и внес изменения в соответствии с моими требованиями.
Ответ №1:
Проверено и работает на меня.
ПРАВКА: внесено множество исправлений.
Sub ProcessWorkbooks() Dim f, wsData As Worksheet, wbSrc As Workbook, map As Object Set wsData = ThisWorkbook.Sheets("Data") wsData.UsedRange.ClearContents 'clear any existing data Set wbSrc = Workbooks.Open("C:New folderExec_072021.xlsb", Password:="**********") ImportData wbSrc, wsData wbSrc.Close False Set wbSrc = Workbooks.Open("C:New folderNon Exec_072021.xlsb", Password:="**********") ImportData wbSrc, wsData wbSrc.Close False With wsData.Range("A1").CurrentRegion .Font.Size = 9 .Font.Name = "Calibri" .Borders.LineStyle = xlLineStyleNone .EntireColumn.AutoFit End With End Sub Sub ImportData(wbIn As Workbook, wsData As Worksheet) Dim lrData As Long, lrSrc As Long, ws As Worksheet, c As Range Dim Process, hdr, m Process = Array("Manila", "Cebu", "Davao", "CDO", "Bacolod") Application.ScreenUpdating = False For Each ws In wbIn.Worksheets If Not IsError(Application.Match(ws.Name, Process, 0)) Then 'process this sheet? lrData = SheetLastRow(wsData) 1 If lrData = 1 Then lrData = 2 'in case no headers yet... lrSrc = SheetLastRow(ws) For Each c In ws.Range("A1", ws.Cells(1, Columns.Count).End(xlToLeft)).Cells hdr = c.Value m = Application.Match(hdr, wsData.Rows(1), 0) 'existing column match? If IsError(m) Then m = Application.CountA(wsData.Rows(1)) m = IIf(m = 0, 1, m 1) wsData.Cells(1, m).Value = hdr 'add as new column header End If ws.Range(c.Offset(1), ws.Cells(lrSrc, c.Column)).Copy _ wsData.Cells(lrData, m) Next c End If Next ws End Sub 'return the last used row in a worksheet Function SheetLastRow(ws As Worksheet) As Long Dim f As Range Set f = ws.Cells.Find("*", ws.Range("A1"), xlFormulas, xlPart, xlByRows, xlPrevious) If Not f Is Nothing Then SheetLastRow = f.Row 'otherwise 0 End Function
Комментарии:
1. Спасибо, Тим! Пожалуйста, найдите результат после тестирования. — Данные поступают только в столбец А листа базы данных, все остальные 167 столбцов остаются пустыми. — Данные столбца А являются неполными и содержат пробелы между ними. — Код использует строку 1 листа базы данных в качестве заголовков, в идеале код должен создавать заголовки со всех разных листов, а затем копировать вставленные данные для заголовков этих столбцов в лист базы данных. Кроме того, можем ли мы удалить зависимость от жесткого кодирования имен рабочих листов в коде («Манила», «Себу», «Давао», «CDO», «Баколод»), а также пути к файлу и вместо этого попросить пользователя выбрать файлы.?
2. Смотрите мое обновление выше.
3. Спасибо, Тим, программа уже работает. Несколько вещей….1) получение 4-5 пустых строк с каждого листа в базу данных при копировании данных. (Можем ли мы просто использовать столбец A с каждого листа, чтобы получить диапазон последних строк ?)…… 2) как упоминалось ранее, имена листов и рабочие книги в коде жестко закодированы, можем ли мы разрешить выполнение кода для всех листов и любой книги вместо этого (так как в будущем может появиться новый сайт).
4. Почему бы вам не попытаться внести эти изменения? Они должны быть довольно прямолинейными.
5. Я смог удалить фиксированные пути к файлам из кода и вместо этого использовал средство выбора папок…. Я постараюсь разобраться в проблеме получения нескольких пустых строк после каждого копирования и вставки в лист базы данных….спасибо