Здравствуйте уважаемые форумчане! Задачка не новая, но есть ньюансы:
В папке находятся примерно 200 файлов с отчётами. Необходимо: -в каждом файле снять фильтр по столбцу Е -скопировать строки с данными начиная ниже 8 строки (включительно) (пустые строки не нужны) Далее в итоговом отчёте: -вставить скопированные строки в итоговый отчёт последовательно из каждого отчёта -установить фильтр по столбцу Е по значению "+" -скрыть столбец Е -перейти в ячейку А1 -сохранить итоговый отчёт
Подскажите, пожалуйста, решение, как автоматизировать эти однотипные операции.
Необходимо: 1) Поместить все файлы Отчёт1, Отчёт2 в папку "Отчеты". 2) Файл во вложении должен находится на 1 уровень выше. 3) Откройте файл, сохраните его и нажмите "Обновить все".
Я бы предложил один из 2-х вариантов: 1. Обратиться в раздел форума "Работа". Где Вам обязательно помогут за денюжку. (добрые люди уже помогли) 2. Попробовать самостоятельно разобраться с надстройкой Power Query, судя по описанию, в ней вполне реально всё сделать. https://www.planetaexcel.ru/techniques/24/2152/
Public first_file As Boolean
Sub Main()
Application.ScreenUpdating = False
Dim shSum As Worksheet:
Set shSum = ThisWorkbook.Sheets(1)
Job_sum_sheet1 shSum
Job_folder shSum
Job_sum_sheet2 shSum
Application.ScreenUpdating = True
End Sub
Код
Sub Job_folder(shSum As Worksheet)
Dim fso As Object: Set fso = CreateObject("Scripting.Filesystemobject")
Dim f As Variant
first_file = True
For Each f In fso.GetFolder(ThisWorkbook.Path).Files
With f
If fso.GetExtensionName(.Name) Like ("xls*") Then
If Left(.Name, 2) <> "~$" Then
If .Name <> ThisWorkbook.Name Then
Application.StatusBar = .Name
Job_file f, shSum
Application.StatusBar = False
End If
End If
End If
End With
DoEvents
Next
Application.CutCopyMode = False
End Sub
Код
Sub Job_file(ByVal sFull As String, shSum As Worksheet)
Dim wb As Workbook
Set wb = Workbooks.Open(sFull)
Job_sheet wb.Sheets(1), shSum
wb.Close False
End Sub
Код
Sub Job_sheet(sh As Worksheet, shSum As Worksheet)
Dim rTo As Range
With ThisWorkbook.Sheets(1)
' If .Cells(1, 1).Value = "" Then
' Set rTo = .Cells(1, 1)
' Else
Set rTo = .Cells(.Rows.Count, 1).End(xlUp).Cells(2, 1)
' End If
End With
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range(.Cells(7, 1), .Cells(y, 5)).AutoFilter Field:=5
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Rows("8:" & y).Copy rTo
If first_file Then
.Rows("8:" & y).Copy
rTo.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
first_file = False
End If
End With
Application.CutCopyMode = False
End Sub
Код
Sub Job_sum_sheet1(shSum As Worksheet)
With shSum
.Columns("A:E").Delete Shift:=xlToLeft
End With
End Sub
Код
Sub Job_sum_sheet2(shSum As Worksheet)
With shSum
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim a As Variant
a = .Range(.Cells(1, 1), .Cells(y, 1))
For y = UBound(a, 1) To 2 Step -1
If a(y, 1) = "" Then
.Rows(y).Delete
End If
Next
.Parent.Activate
.Select
.Cells(1, 1).Select
.Range(.Cells(1, 1), .Cells(y, 5)).AutoFilter Field:=5, Criteria1:="+"
.Columns("E:E").EntireColumn.Hidden = True
Application.DisplayAlerts = False
.Parent.Save
Application.DisplayAlerts = True
End With
End Sub
Murderface_, Wiss, ,вариант на PQ попробовал, в принципе- получилось, но, непонятно, как сохранить исходное форматирование (шрифт, заливка и.т.п.). Заливка, к примеру, удобна для того, чтобы навскидку определить тип дефекта. Приложу 2 файла: первый-это то, что выдаёт PQ, второй то, что хотелось бы получить на выходе.
Murderface_ написал: Не уверен, что с помощью PQ можно
Тоже не уверен. Точнее, скорее почти уверен, что нельзя. PQ с данными работает, а не форматированиями. Это фактически БД. Вариант МатросНаЗебре, вроде бы с форматированием копирует.
А вам не нужно исходное, вам нужно в принципе форматирование. Ваша задаче легко решается с помощью маленького справочника и УФ. Можно и без справочника, но тогда надо будет правил побольше сделать - не принципиально.
Sub DeleteEmptyRow(sh As Worksheet)
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim a As Variant
If y = 1 Then
ReDim a(1 To 1, 1 To 1)
a(1, 1) = .Cells(y, 1).Value
Else
a = .Range(.Cells(1, 1), .Cells(y, 1))
End If
For y = UBound(a, 1) To 2 Step -1
If a(y, 1) = "" Then
.Rows(y).Delete
End If
Next
End With
End Sub
Sub Копировать_ячейки()
' Сочетание клавиш: Ctrl+ч
Range("A8:E100").Select
Application.CutCopyMode = False
Selection.Copy
Windows("Трубопроводы межцеховые.xlsx").Activate ' текст в кавычках=имя файла сводного отчёта
Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial
End Sub
Однако приходится последовательно открывать каждый фал и применять макрос. Подскажите, пожалуйста, как допилить макрос, чтобы сделать следующие шаги:
-1. Зайти в определённую папку
-2. Открыть файл
-3. Применить макрос
-4. Закрыть файл без сохранения
-5. Повторить пункты 1-4 для всех файлов в папке
Для облегчения задачи можно предварительно переименовать файлы (например Отчёт1, Отчёт2, Отчёт3 и.т.д.)
PooHkrd написал: А вам не нужно исходное, вам нужно в принципе форматирование. Ваша задаче легко решается с помощью маленького справочника и УФ.Можно и без справочника, но тогда надо будет правил побольше сделать - не принципиально.
Решение на PQ, конечно, самое элегантное. Сейчас пришлось использовать VBA тупо потому, что внешний вид ранее оформленных отчётов и последующих должен быть одинаковым (от слова совсем ). А так, да, PQ - это отличный инструмент.
МатросНаЗебре написал: Вставьте, например, в конец модуля. И удалите существующую процедуру DeleteEmptyRow. От Sub DeleteEmptyRow(sh As Worksheet) до End Sub.
Что-то я туплю. Не могу понять, куда именно вставить код. Вот код из сообщения №4 целиком. Если не сложно поправьте, пожалуйста
Код
Public first_file As Boolean
Sub Main()
Application.ScreenUpdating = False
Dim shSum As Worksheet:
Set shSum = ThisWorkbook.Sheets(1)
Job_sum_sheet1 shSum
Job_folder shSum
Job_sum_sheet2 shSum
Application.ScreenUpdating = True
End Sub
Sub Job_folder(shSum As Worksheet)
Dim fso As Object: Set fso = CreateObject("Scripting.Filesystemobject")
Dim f As Variant
first_file = True
For Each f In fso.GetFolder(ThisWorkbook.Path).Files
With f
If fso.GetExtensionName(.Name) Like ("xls*") Then
If Left(.Name, 2) <> "~$" Then
If .Name <> ThisWorkbook.Name Then
Application.StatusBar = .Name
Job_file f, shSum
Application.StatusBar = False
End If
End If
End If
End With
DoEvents
Next
Application.CutCopyMode = False
End Sub
Sub Job_file(ByVal sFull As String, shSum As Worksheet)
Dim wb As Workbook
Set wb = Workbooks.Open(sFull)
Job_sheet wb.Sheets(1), shSum
wb.Close False
End Sub
Sub Job_sheet(sh As Worksheet, shSum As Worksheet)
Dim rTo As Range
With ThisWorkbook.Sheets(1)
' If .Cells(1, 1).Value = "" Then
' Set rTo = .Cells(1, 1)
' Else
Set rTo = .Cells(.Rows.Count, 1).End(xlUp).Cells(2, 1)
' End If
End With
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range(.Cells(7, 1), .Cells(y, 5)).AutoFilter Field:=5
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Rows("8:" & y).Copy rTo
If first_file Then
.Rows("8:" & y).Copy
rTo.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
first_file = False
End If
End With
Application.CutCopyMode = False
End Sub
Sub Job_sum_sheet1(shSum As Worksheet)
With shSum
.Columns("A:E").Delete Shift:=xlToLeft
End With
End Sub
Sub Job_sum_sheet2(shSum As Worksheet)
With shSum
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim a As Variant
a = .Range(.Cells(1, 1), .Cells(y, 1))
For y = UBound(a, 1) To 2 Step -1
If a(y, 1) = "" Then
.Rows(y).Delete
End If
Next
.Parent.Activate
.Select
.Cells(1, 1).Select
.Range(.Cells(1, 1), .Cells(y, 5)).AutoFilter Field:=5, Criteria1:="+"
.Columns("E:E").EntireColumn.Hidden = True
Application.DisplayAlerts = False
.Parent.Save
Application.DisplayAlerts = True
End With
End Sub
Public first_file As Boolean
Sub Main()
Application.ScreenUpdating = False
Dim shSum As Worksheet:
Set shSum = ThisWorkbook.Sheets(1)
Job_sum_sheet1 shSum
Job_folder shSum
Job_sum_sheet2 shSum
Application.ScreenUpdating = True
End Sub
Sub Job_folder(shSum As Worksheet)
Dim fso As Object: Set fso = CreateObject("Scripting.Filesystemobject")
Dim f As Variant
first_file = True
For Each f In fso.GetFolder(ThisWorkbook.Path).Files
With f
If fso.GetExtensionName(.Name) Like ("xls*") Then
If Left(.Name, 2) <> "~$" Then
If .Name <> ThisWorkbook.Name Then
Application.StatusBar = .Name
Job_file f, shSum
Application.StatusBar = False
End If
End If
End If
End With
DoEvents
Next
Application.CutCopyMode = False
End Sub
Sub Job_file(ByVal sFull As String, shSum As Worksheet)
Dim wb As Workbook
Set wb = Workbooks.Open(sFull)
Job_sheet wb.Sheets(1), shSum
wb.Close False
End Sub
Sub Job_sheet(sh As Worksheet, shSum As Worksheet)
Dim rTo As Range
With ThisWorkbook.Sheets(1)
' If .Cells(1, 1).Value = "" Then
' Set rTo = .Cells(1, 1)
' Else
Set rTo = .Cells(.Rows.Count, 1).End(xlUp).Cells(2, 1)
' End If
End With
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range(.Cells(7, 1), .Cells(y, 5)).AutoFilter Field:=5
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Rows("8:" & y).Copy rTo
If first_file Then
.Rows("8:" & y).Copy
rTo.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
first_file = False
End If
End With
Application.CutCopyMode = False
End Sub
Код
Sub Job_sum_sheet1(shSum As Worksheet)
With shSum
.Columns("A:E").Delete Shift:=xlToLeft
End With
End Sub
Sub Job_sum_sheet2(shSum As Worksheet)
DeleteEmptyRow shSum
With shSum
.Parent.Activate
.Select
.Cells(1, 1).Select
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Range(.Cells(1, 1), .Cells(y, 5)).AutoFilter Field:=5, Criteria1:="+"
.Columns("E:E").EntireColumn.Hidden = True
Application.DisplayAlerts = False
.Parent.Save
Application.DisplayAlerts = True
End With
End Sub
Sub DeleteEmptyRow(sh As Worksheet)
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
Dim a As Variant
If y = 1 Then
ReDim a(1 To 1, 1 To 1)
a(1, 1) = .Cells(y, 1).Value
Else
a = .Range(.Cells(1, 1), .Cells(y, 1))
End If
For y = UBound(a, 1) To 2 Step -1
If a(y, 1) = "" Then
.Rows(y).Delete
End If
Next
End With
End Sub
Sub Job_sum_sheet2(shSum As Worksheet)
DeleteEmptyRow shSum
With shSum
.Parent.Activate
.Select
.Cells(1, 1).Select
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
If y > 1 Then
.Range(.Cells(1, 1), .Cells(y, 5)).AutoFilter Field:=5, Criteria1:="+"
.Columns("E:E").EntireColumn.Hidden = True
End If
Application.DisplayAlerts = False
.Parent.Save
Application.DisplayAlerts = True
End With
End Sub
Код
Sub Job_sheet(sh As Worksheet, shSum As Worksheet)
Dim rTo As Range
With ThisWorkbook.Sheets(1)
' If .Cells(1, 1).Value = "" Then
' Set rTo = .Cells(1, 1)
' Else
Set rTo = .Cells(.Rows.Count, 1).End(xlUp).Cells(2, 1)
' End If
End With
With sh
Dim y As Long
y = .Cells(.Rows.Count, 1).End(xlUp).Row
If y > 7 Then
.Range(.Cells(7, 1), .Cells(y, 5)).AutoFilter Field:=5
y = .Cells(.Rows.Count, 1).End(xlUp).Row
.Rows("8:" & y).Copy rTo
If first_file Then
.Rows("8:" & y).Copy
rTo.PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
first_file = False
End If
End If
End With
Application.CutCopyMode = False
End Sub
Для работы с пустыми файлами нужно заменить эти процедуры.
И минутка недоумения. Зачем Вы тестируете на пустых файлах, если у Вас 200 файлов в папке?
МатросНаЗебре написал: А я понял, ошибка возникла, когда рядом не было файлов отчётов.
Файл отчёта и файлы-исходники находятся в 1 папке, при запуске макроса-ошибка в блоке sum_sheet2. Это ошибка в макросе или я неверно выполняю какие-то шаги? Уже ум за разум заходит.
МатросНаЗебре написал: Сложно сказать, не видя файла. А какая область заполнена на момент появления ошибки?
Вот мои действия пошагово: - в 1 папку складываю отчёты-исходники и НЕ заполненный файл сводного отчёта с шапкой - открываю НЕ заполненный файл сводного отчёта (приложил) - запускаю макрос - ошибка Макрос хранится в персональной книге. Грешил на надстройку Office tab, но при отключенной надстройке та же ошибка.
МатросНаЗебре написал: Нашёл.Перенесите макрос из персональной книги.
Вы правы! Макрос заработал, если хранить в текущей книге, но есть пару багов: -затирается строка 1 с шапкой -не копируются 8 (восьмые) строки -прощу прощения, не указал в задаче, что в итоговом отчёте нужны только строки со значением "+" по столбцу Е, т.е либо не снимать фильтр по столбцу Е в исходнике, либо удалить строки БЕЗ пометки "+" по столбцу Е в итоговом отчёте (в приоритете - скорость работы макроса на большом количестве файлов ~до 250 файлов)