Вопрос или проблема
Я нашёл некоторый код, который прекрасно работает для разделения файла на основе столбца (строка 31) на отдельные вкладки в пределах рабочего листа.
Мне просто нужно, чтобы он разделял файлы на основе столбца на отдельные книги, а также запрашивал добавление суффикса для идентификации каждого файла.
Sub Copy_To_Worksheets()
'Примечание: Этот макрос использует функцию LastRow
Dim My_Range As Range
Dim FieldNum As Long
Dim CalcMode As Long
Dim ViewMode As Long
Dim ws2 As Worksheet
Dim Lrow As Long
Dim cell As Range
Dim CCount As Long
Dim WSNew As Worksheet
Dim ErrNum As Long
'Установить диапазон фильтра на ActiveSheet: A1 - это верхняя левая ячейка вашего диапазона фильтра
'и заголовок первого столбца, D - это последний столбец в диапазоне фильтра.
'Вы также можете добавить имя листа в код, например:
'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
'Нет необходимости, чтобы лист был активным, когда вы запускаете макрос, когда вы используете это.
Set My_Range = Range("A1:O2000") ' & LastRow(ActiveSheet))
My_Range.Parent.Select
If ActiveWorkbook.ProtectStructure = True Or _
My_Range.Parent.ProtectContents = True Then
MsgBox "Извините, не работает, когда книга или лист защищены", _
vbOKOnly, "Копировать в новый рабочий лист"
Exit Sub
End If
'Этот пример фильтрует по первому столбцу в диапазоне (измените поле, если необходимо)
'В этом случае диапазон начинается с A, так что Field:=1 это столбец A, 2 = столбец B, ......
FieldNum = 6 ' Я изменил это на 3 для столбца C
'Выключить AutoFilter
My_Range.Parent.AutoFilterMode = False
'Изменить ScreenUpdating, Calculation, EnableEvents, ....
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
End With
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
ActiveSheet.DisplayPageBreaks = False
'Добавить рабочий лист, чтобы скопировать уникальный список и добавить CriteriaRange
Set ws2 = Worksheets.Add
With ws2
'Сначала мы копируем уникальные данные из поля фильтра в ws2
My_Range.Columns(FieldNum).AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=.Range("A1"), Unique:=True
'Цикл по уникальному списку в ws2 и фильтрация/копирование в новый лист
Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In .Range("A2:A" & Lrow)
'Фильтрация диапазона
My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
'Проверить, если более 8192 зоны (ограничение по зонам)
CCount = 0
On Error Resume Next
CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
.Areas(1).Cells.Count
On Error GoTo 0
If CCount = 0 Then
MsgBox "Есть более 8192 зон для значения : " & cell.Value _
& vbNewLine & "Невозможно скопировать видимые данные." _
& vbNewLine & "Совет: Отсортируйте свои данные перед использованием этого макроса.", _
vbOKOnly, "Разделение на рабочие листы"
Else
'Добавить новый рабочий лист
Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
On Error Resume Next
WSNew.Name = cell.Value
If Err.Number > 0 Then
ErrNum = ErrNum + 1
WSNew.Name = "Ошибка_" & Format(ErrNum, "0000")
Err.Clear
End If
On Error GoTo 0
'Скопировать видимые данные на новый рабочий лист
My_Range.SpecialCells(xlCellTypeVisible).Copy
With WSNew.Range("A1")
' Paste:=8 будет копировать ширину столбца в Excel 2000 и выше
' Удалите эту строку, если вы используете Excel 97
.PasteSpecial Paste:=8
.PasteSpecial xlPasteValues
.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
.Select
End With
End If
'Показать все данные в диапазоне
My_Range.AutoFilter Field:=FieldNum
Next cell
'Удалить лист ws2
On Error Resume Next
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
On Error GoTo 0
End With
'Выключить AutoFilter
My_Range.Parent.AutoFilterMode = False
If ErrNum > 0 Then
MsgBox "Переименуйте каждое имя рабочего листа, начинающееся с ""Ошибка_"" вручную" _
& vbNewLine & "Содержатся символы в имени, которые не разрешены" _
& vbNewLine & "в имени листа или рабочий лист уже существует."
End If
'Восстановить ScreenUpdating, Calculation, EnableEvents, ....
My_Range.Parent.Select
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = CalcMode
End With
MsgBox ("Копирование завершено - - Не забудьте сохранить свою работу.")
End Sub
Какие-нибудь идеи, как это изменить?
Вот макрос, который я сделал несколько месяцев назад на работе. Возможно, он может помочь. Если нет, вы всегда можете посмотреть, как я создаю книги в Sub CopySheet() и адаптировать свой текущий макрос.
Действие пользователя: Макрос запрашивает номер столбца (C=3) для разделения и какой строки начинать (обычно первой строки под заголовками). Этот макрос не запрашивает суффикс – вместо этого он автоматически называет рабочие книги по значению столбца и сохраняет их в подкаталоге \Split\.
Требование: Это требует, чтобы ваша таблица была отсортирована по вашему основному столбцу.
Контекст: Я сделал это в основном для разделения больших сводных таблиц (сначала преобразованных в значения с помощью другого макроса) по первому ярлыку строки в режиме компоновки. Поскольку в этих таблицах много пустых ячеек, которые просто скрытые дубликаты, она не полагается на фильтры и вместо этого идет сверху вниз – поэтому требуется сортировка.
Метод: Каждый раз, когда встречается новое значение в указанном столбце, он копирует весь оригинальный рабочий лист в новую книгу каждый раз, а затем удаляет все строки до и после этого текущего раздела (переменные iFirstRow, iStartRow, iStopRow, iTotalRows используются для отслеживания этих частей). Это сохраняет любое форматирование, настройки страниц, формулы и т.д., которые вы можете иметь в своей оригинальной книге.
Public Sub SplitToFiles()
' МАКРО SplitToFiles
' Последнее обновление: 2012-03-05
'
' Описание
' Обходит указанный столбец и разделяет каждоеDistinct значеие в отдельный файл, создавая копию и удаляя строки ниже и выше.
'
' Примечание: Значения в столбце должны быть уникальными или отсортированными.
'
' Следующие ячейки игнорируются при делении секций:
' - пустые ячейки или содержащие только пробелы
' - одинаковое значение повторяется
' - ячейки, содержащие "итог"
'
' Файлы сохраняются в подкаталоге "Split" из местоположения исходной книги и называются по имени секции.
Dim osh As Worksheet ' Оригинальный лист
Dim iRow As Long ' Курсоры
Dim iCol As Long
Dim iFirstRow As Long ' Константа
Dim iTotalRows As Long ' Константа
Dim iStartRow As Long ' Разделители секций
Dim iStopRow As Long
Dim sSectionName As String ' Имя секции (и имя файла)
Dim rCell As Range ' текущая ячейка
Dim owb As Workbook ' Исходная книга
Dim sFilePath As String ' Константа
Dim iCount As Integer ' # созданных документов
iCol = Application.InputBox("Введите номер столбца, используемого для разделения", "Выбрать столбец", 2, , , , , 1)
iRow = Application.InputBox("Введите номер строки начала (чтобы пропустить заголовок)", "Выбрать строку", 5, , , , , 1)
iFirstRow = iRow
Set osh = Application.ActiveSheet
Set owb = Application.ActiveWorkbook
iTotalRows = osh.UsedRange.Rows.Count
sFilePath = Application.ActiveWorkbook.Path
If Dir(sFilePath + "\Split", vbDirectory) = "" Then
MkDir sFilePath + "\Split"
End If
'Отключить обновление экранов и события
Application.EnableEvents = False
Application.ScreenUpdating = False
Do
' Получить ячейку по курсору
Set rCell = osh.Cells(iRow, iCol)
sCell = Replace(rCell.Text, " ", "")
If sCell = "" Or (rCell.Text = sSectionName And iStartRow <> 0) Or InStr(1, rCell.Text, "total", vbTextCompare) <> 0 Then
' Условия пропуска выполнены
Else
' Найдено новое разделение
If iStartRow = 0 Then
' Разделитель StartRow не установлен, что означает начало нового раздела
sSectionName = rCell.Text
iStartRow = iRow
Else
' Разделитель StartRow установлен, что означает, что мы достигли конца раздела
iStopRow = iRow - 1
' Передача переменных в отдельную подпрограмму для создания и сохранения нового рабочего листа
CopySheet osh, iFirstRow, iStartRow, iStopRow, iTotalRows, sFilePath, sSectionName, owb.fileFormat
iCount = iCount + 1
' Сброс разделителей секций
iStartRow = 0
iStopRow = 0
' Готово к продолжению цикла
iRow = iRow - 1
End If
End If
' Продолжать до достижения последней строки
If iRow < iTotalRows Then
iRow = iRow + 1
Else
' Завершено. Сохранить последний раздел
iStopRow = iRow
CopySheet osh, iFirstRow, iStartRow, iStopRow, iTotalRows, sFilePath, sSectionName, owb.fileFormat
iCount = iCount + 1
' Выход
Exit Do
End If
Loop
'Включить обновление экранов и события
Application.ScreenUpdating = True
Application.EnableEvents = True
MsgBox Str(iCount) + " документов сохранено в " + sFilePath
End Sub
Public Sub DeleteRows(targetSheet As Worksheet, RowFrom As Long, RowTo As Long)
Dim rngRange As Range
Set rngRange = Range(targetSheet.Cells(RowFrom, 1), targetSheet.Cells(RowTo, 1)).EntireRow
rngRange.Select
rngRange.Delete
End Sub
Public Sub CopySheet(osh As Worksheet, iFirstRow As Long, iStartRow As Long, iStopRow As Long, iTotalRows As Long, sFilePath As String, sSectionName As String, fileFormat As XlFileFormat)
Dim ash As Worksheet ' Скопированный лист
Dim awb As Workbook ' Новая книга
' Копировать книгу
osh.Copy
Set ash = Application.ActiveSheet
' Удалить строки после секции
If iTotalRows > iStopRow Then
DeleteRows ash, iStopRow + 1, iTotalRows
End If
' Удалить строки перед секцией
If iStartRow > iFirstRow Then
DeleteRows ash, iFirstRow, iStartRow - 1
End If
' Выбрать ячейку в левом верхнем углу
ash.Cells(1, 1).Select
' Очистить несколько символов, чтобы предотвратить недопустимое имя файла
sSectionName = Replace(sSectionName, "https://superuser.com/", " ")
sSectionName = Replace(sSectionName, "\", " ")
sSectionName = Replace(sSectionName, ":", " ")
sSectionName = Replace(sSectionName, "=", " ")
sSectionName = Replace(sSectionName, "*", " ")
sSectionName = Replace(sSectionName, ".", " ")
sSectionName = Replace(sSectionName, "?", " ")
' Сохранить в том же формате, что и оригинальная книга
ash.SaveAs sFilePath + "\Split\" + sSectionName, fileFormat
' Закрыть
Set awb = ash.Parent
awb.Close SaveChanges:=False
End Sub
Ответ или решение
Чтобы разделить большой файл данных в Excel 2010 на отдельные рабочие книги, основываясь на определённом столбце и предлагая пользователю возможность добавить суффикс к имени файла, можно использовать следующий макрос. Этот код адаптирован из приведённых примеров, чтобы соответствовать вашим требованиям:
Sub SplitDataToWorkbooks()
Dim sourceSheet As Worksheet
Dim uniqueValues As Collection
Dim value As Variant
Dim newWorkbook As Workbook
Dim fileSuffix As String
Dim lastRow As Long
Dim columnToSplit As Long
Dim path As String
' Устанавливаем исходный лист
Set sourceSheet = ActiveSheet
' Запрашиваем номер столбца и суффикс для имени файла
columnToSplit = Application.InputBox("Введите номер столбца для разделения (например, A = 1, B = 2 и т.д.):", "Выберите столбец", 1, , , , , 1)
fileSuffix = Application.InputBox("Введите суффикс для имени файлов:", "Введите суффикс", "", , , , , 255)
' Получаем последний заполненный ряд в исходном листе
lastRow = sourceSheet.Cells(Rows.Count, columnToSplit).End(xlUp).Row
' Создаем коллекцию для хранения уникальных значений
Set uniqueValues = New Collection
' Заполняем коллекцию уникальными значениями
On Error Resume Next ' Игнорируем ошибки при добавлении дубликатов
For i = 2 To lastRow ' Предполагается, что первая строка - это заголовки
uniqueValues.Add sourceSheet.Cells(i, columnToSplit).Value
Next i
On Error GoTo 0 ' Включаем обработку ошибок
' Получаем путь для сохранения файлов
path = ThisWorkbook.Path & "\Split"
If Dir(path, vbDirectory) = "" Then MkDir path ' Создаем папку, если она не существует
' Перебираем уникальные значения и создаем новые рабочие книги
For Each value In uniqueValues
' Создаем новую рабочую книгу
Set newWorkbook = Workbooks.Add
' Фильтруем исходный лист по уникальному значению
With sourceSheet
.Range("A1").AutoFilter Field:=columnToSplit, Criteria1:=value
' Копируем видимые ячейки в новую книгу
.UsedRange.SpecialCells(xlCellTypeVisible).Copy Destination:=newWorkbook.Sheets(1).Range("A1")
' Сохраняем книгу с уникальным именем
newWorkbook.SaveAs Filename:=path & "\" & value & "_" & fileSuffix & ".xlsx", FileFormat:=xlOpenXMLWorkbook
newWorkbook.Close SaveChanges:=False
End With
Next value
' Отключаем фильтр
sourceSheet.AutoFilterMode = False
' Сообщаем о завершении
MsgBox "Разделение завершено. Все файлы были сохранены в папке Split"
End Sub
Пояснение к коду
-
Ввод данных пользователем: В начале макрос запрашивает у пользователя номер столбца, по которому будет происходить разделение данных, и суффикс, который будет добавлен к именам создаваемых файлов.
-
Сбор уникальных значений: Макрос проходит по указанному столбцу и собирает все уникальные значения, игнорируя дубликаты.
-
Создание директории: Для сохранения файлов создаётся новая папка "Split", если её еще не существует.
-
Фильтрация и создание новых файлов: Для каждого уникального значения создается новая рабочая книга, в которую копируются все строки, соответствующие фильтру по этому значению. Файлы сохраняются в формате .xlsx с добавленным к имени файла суффиксом.
-
Завершение работы: После завершения процесса пользователю показывается сообщение о завершении.
Важные моменты
- Убедитесь, что ваши данные отсортированы по выбранному столбцу перед запуском макроса.
- Запускайте код на резервной копии файла данных, чтобы избежать потери информации.
- Путь для сохранения нового файла формируется на основе текущего местоположения файла с макросом.
Этот макрос оптимизирует управление большими наборами данных и упрощает процесс их разделения для дальнейшего анализа.