Я же про "отбор занял три строки". Три строки чего? Кода с двоеточиями?
И про "построчное копирование ячеек" никто и не спорит - да, при одинаковом количестве итераций это будет тормозом. А вот если "отбор" будет выполняться суммарно за существенно меньшее количество "телодвижений" (итераций) - то это ускорит алгоритм.
Кстати, насчет "построчного копирования ячеек" ты тоже не совсем прав. Тут ведь смотря что подразумевать под "копированием", ведь использовать <Range>.Copy Destibation:= - никто не предлагает А насколько быстрее "скопировать массив 10000x10 в указанный диапазон" по сравнению со "скопировать 10000 раз массив 1x10 в указанные 10000 диапазонов" - это ещё надо посмотреть. Ведь и в том, и в другом случае запись идет в .Values. И хотя кажется, что во втором случае время скушают итерации цикла - но не забываем, что в первом случае ещё и исполнялось "10000 раз переписать массив 1x10 в массив 1x10" - а ведь мы смотрим на суммарное время выполнения.
А про "30 секунд" ТС пишет как про общее время выполнения макроса. А не про время записи файлов - откуда он там время записи файлов-то возьмет? Так что я не удивлюсь, если как раз практически все время затрачивается на выборки, а не на запись файлов. Хотя не забываем ещё и о рефрешах сводов - для чистоты картины надо бы знать время "отборов+записей" без сводов вообще.
Я же про "отбор занял три строки". Три строки чего? Кода с двоеточиями?
И про "построчное копирование ячеек" никто и не спорит - да, при одинаковом количестве итераций это будет тормозом. А вот если "отбор" будет выполняться суммарно за существенно меньшее количество "телодвижений" (итераций) - то это ускорит алгоритм.
Кстати, насчет "построчного копирования ячеек" ты тоже не совсем прав. Тут ведь смотря что подразумевать под "копированием", ведь использовать <Range>.Copy Destibation:= - никто не предлагает А насколько быстрее "скопировать массив 10000x10 в указанный диапазон" по сравнению со "скопировать 10000 раз массив 1x10 в указанные 10000 диапазонов" - это ещё надо посмотреть. Ведь и в том, и в другом случае запись идет в .Values. И хотя кажется, что во втором случае время скушают итерации цикла - но не забываем, что в первом случае ещё и исполнялось "10000 раз переписать массив 1x10 в массив 1x10" - а ведь мы смотрим на суммарное время выполнения.
А про "30 секунд" ТС пишет как про общее время выполнения макроса. А не про время записи файлов - откуда он там время записи файлов-то возьмет? Так что я не удивлюсь, если как раз практически все время затрачивается на выборки, а не на запись файлов. Хотя не забываем ещё и о рефрешах сводов - для чистоты картины надо бы знать время "отборов+записей" без сводов вообще.AndreTM
Iurii, да оставьте вы старый код для обновления сводной Просто возьмите в исходниках диапазон с запасом так, чтобы он тоже чтобы был с пустыми строками, и наложите сразу фильтр, чтобы не показывались "пусто". Тогда и в скопированных сводных этот фильтр сработает и все будет показывать нормально.
Iurii, да оставьте вы старый код для обновления сводной Просто возьмите в исходниках диапазон с запасом так, чтобы он тоже чтобы был с пустыми строками, и наложите сразу фильтр, чтобы не показывались "пусто". Тогда и в скопированных сводных этот фильтр сработает и все будет показывать нормально.AndreTM
AndreTM, Спасибо за совет. То есть мне можно не применять макрос для обновление границ сводной который Ви написали? Просто прописать использование фильтра который не равно пусто.
А в Ваш код можно добавить обновление? [vba]
Код
Dim wsSh As Worksheet, PVTable As PivotTable For Each wsSh In .Worksheets For Each PVTable In wsSh.PivotTables PVTable.ChangePivotCache wsSh.Parent. _ PivotCaches.Create(SourceType:=xlDatabase, SourceData:=wsSh.Parent.Sheets("Исх").[a1].CurrentRegion, _ Version:=xlPivotTableVersion15) Next PVTable Next wsSh
[/vba]
AndreTM, Спасибо за совет. То есть мне можно не применять макрос для обновление границ сводной который Ви написали? Просто прописать использование фильтра который не равно пусто.
А в Ваш код можно добавить обновление? [vba]
Код
Dim wsSh As Worksheet, PVTable As PivotTable For Each wsSh In .Worksheets For Each PVTable In wsSh.PivotTables PVTable.ChangePivotCache wsSh.Parent. _ PivotCaches.Create(SourceType:=xlDatabase, SourceData:=wsSh.Parent.Sheets("Исх").[a1].CurrentRegion, _ Version:=xlPivotTableVersion15) Next PVTable Next wsSh
Так что я не удивлюсь, если как раз практически все время затрачивается на выборки, а не на запись файлов.
О, вижу ты недооцениваешь скорость работы с дисками и листом. Суди сам, см. скрин. Считал так на 23538 строк: [vba]
Код
a = r.Value: n = 1 t = Timer For m = 2 To UBound(a) If a(m, 10) = PodrNow Then n = n + 1: For k = 1 To 10: a(n, k) = a(m, k): Next Next t = Timer - t t1 = t1 + t r.ClearContents .Sheets("Исх").[a1].Resize(n, 10) = a Dim wsSh As Worksheet, PVTable As PivotTable 'обновление всех сводных ' For Each wsSh In .Worksheets ' For Each PVTable In wsSh.PivotTables: PVTable.RefreshTable: Next PVTable ' Next wsSh .Close -1 End With Next i fsh = Timer Application.ScreenUpdating = True MsgBox "Все ОК! Время работы макроса: " & (fsh - st) & vbCrLf & _ "время отбора " & t1
Так что я не удивлюсь, если как раз практически все время затрачивается на выборки, а не на запись файлов.
О, вижу ты недооцениваешь скорость работы с дисками и листом. Суди сам, см. скрин. Считал так на 23538 строк: [vba]
Код
a = r.Value: n = 1 t = Timer For m = 2 To UBound(a) If a(m, 10) = PodrNow Then n = n + 1: For k = 1 To 10: a(n, k) = a(m, k): Next Next t = Timer - t t1 = t1 + t r.ClearContents .Sheets("Исх").[a1].Resize(n, 10) = a Dim wsSh As Worksheet, PVTable As PivotTable 'обновление всех сводных ' For Each wsSh In .Worksheets ' For Each PVTable In wsSh.PivotTables: PVTable.RefreshTable: Next PVTable ' Next wsSh .Close -1 End With Next i fsh = Timer Application.ScreenUpdating = True MsgBox "Все ОК! Время работы макроса: " & (fsh - st) & vbCrLf & _ "время отбора " & t1
Да не, я всё адекватно оцениваю... А сколько было ключей? 3? 25? 200 не пробовал? Фиг ли мерять время той части, где работа с памятью? Причем только той части, где "скопируем 10000 раз массив 1x10". А где время на чтение исходного массива (N раз, между прочим), а где время записи результата - в ячейки? Время очистки от лишних данных места для результата? Замеряй для t1 хотя бы время в диапазоне команд от Set r = , до записи массива a на лист включительно.
Не скинешь мне как-нибудь набор данных, на котором тестировал? Вот не поленюсь, напишу в самом тупом первом варианте свой алгоритм - и сравню.
Да не, я всё адекватно оцениваю... А сколько было ключей? 3? 25? 200 не пробовал? Фиг ли мерять время той части, где работа с памятью? Причем только той части, где "скопируем 10000 раз массив 1x10". А где время на чтение исходного массива (N раз, между прочим), а где время записи результата - в ячейки? Время очистки от лишних данных места для результата? Замеряй для t1 хотя бы время в диапазоне команд от Set r = , до записи массива a на лист включительно.
Не скинешь мне как-нибудь набор данных, на котором тестировал? Вот не поленюсь, напишу в самом тупом первом варианте свой алгоритм - и сравню.
Таких файлов нужно будет делать 25, исходник будет состоять из 80 тис строк.
Как думаешь 25 выборок(да, именно в памяти! Я именно это предложил в качестве оптимизации) существенно замедлят программу по сравнению с остальным? Короче, это уже спор ради спора. Неинтересно.
Андрей, мне кажется ты слегка потерялся в пылу азарта дебатов.
Таких файлов нужно будет делать 25, исходник будет состоять из 80 тис строк.
Как думаешь 25 выборок(да, именно в памяти! Я именно это предложил в качестве оптимизации) существенно замедлят программу по сравнению с остальным? Короче, это уже спор ради спора. Неинтересно.KuklP
Ну с НДС и мы чего-то стoим! kuklp60@gmail.com WM Z206653985942, R334086032478, U238399322728
Да кто спорит Понятное дело, что в исходном варианте ТС - действия "удалим строки листа" и занимали ту самую бОльшую часть времени работы макроса. Замена на "просто отберем нужную информацию в массиве памяти, и разом запишем на лист", естественно, и решает проблему первого узкого места.
Я просто предлагал алгоритм, который, по времени исполнения, - не хуже "варианта из #3". И кто-то высказался о его сомнительности...
Да кто спорит Понятное дело, что в исходном варианте ТС - действия "удалим строки листа" и занимали ту самую бОльшую часть времени работы макроса. Замена на "просто отберем нужную информацию в массиве памяти, и разом запишем на лист", естественно, и решает проблему первого узкого места.
Я просто предлагал алгоритм, который, по времени исполнения, - не хуже "варианта из #3". И кто-то высказался о его сомнительности... AndreTM
Не всё время, не всё... И показал время своей выборки, а я говорил про "время у ТС, о котором он заявил". И про количество ключей ты не сказал, на котором свою выборку считал, а это влияющий показатель.
Давай тогда попросим у ТС его данные, чтобы замерить... Или сгенерируем какой-то набор на сотню тысяч записей, и протестим на нём.
Может, кто-нибудь из модераторов не поленится, оформит наш спор в виде отдельной темы? И из этой темы можно наши посты, относящиеся к выяснению именно этих подробностей - туда и закинуть сразу?
Не всё время, не всё... И показал время своей выборки, а я говорил про "время у ТС, о котором он заявил". И про количество ключей ты не сказал, на котором свою выборку считал, а это влияющий показатель.
Давай тогда попросим у ТС его данные, чтобы замерить... Или сгенерируем какой-то набор на сотню тысяч записей, и протестим на нём.
Может, кто-нибудь из модераторов не поленится, оформит наш спор в виде отдельной темы? И из этой темы можно наши посты, относящиеся к выяснению именно этих подробностей - туда и закинуть сразу?AndreTM
Ребята огромное спасибо за рвение помочь мне в моей проблеме Как только у меня будет конечный файл на более 80 тыс. строк отпишусь по скорости работы, добавлю таймер на отбор.
AndreTM, пока из-за недостатка знаний и времени пользуюсь методом который написал KuklP/, но как только доведу до ума этот макрос (файл на 80 тыс. строк еще не готов и он может отличаться от "пробника" на 13 тыс.) попробую реализовать Ваш метод заодно и приобрету дополнительный опыт VBA.
Kuzmich, пока Ваш макрос не пробовал, так как файла на 80 тыс. у меня еще нет и я только в общих чертах догадываюсь каким он будет, возможно он будет иметь большее количество строк. И пока проверить количество строк в самом большом регионе увы нет возможности. Возможно у одного критерия будет меньше 8000 строк, а может и 15 000. Рисковать не хочу. Но спасибо за идею. возьму на вооружение.
Ребята огромное спасибо за рвение помочь мне в моей проблеме Как только у меня будет конечный файл на более 80 тыс. строк отпишусь по скорости работы, добавлю таймер на отбор.
AndreTM, пока из-за недостатка знаний и времени пользуюсь методом который написал KuklP/, но как только доведу до ума этот макрос (файл на 80 тыс. строк еще не готов и он может отличаться от "пробника" на 13 тыс.) попробую реализовать Ваш метод заодно и приобрету дополнительный опыт VBA.
Kuzmich, пока Ваш макрос не пробовал, так как файла на 80 тыс. у меня еще нет и я только в общих чертах догадываюсь каким он будет, возможно он будет иметь большее количество строк. И пока проверить количество строк в самом большом регионе увы нет возможности. Возможно у одного критерия будет меньше 8000 строк, а может и 15 000. Рисковать не хочу. Но спасибо за идею. возьму на вооружение.Iurii
Решил проблему с ошибкой Отчет сводной таблицы был сохранен без данных. Для обновления отчета используйте команду "обновить данные"
Добавил в код 2 строчки:
[vba]
Код
PVTable.PivotCache.Refresh ' Обновление данных сводной таблицы PVTable.SaveData = True ' изменение параметра [b]сохранять исходные данные вместе с файлом[/b] в сводной таблице
[/vba]
Kuzmich, спасибо за идею возьму на вооружение. У меня уже почти готовый макрос с методом KuklP. Но думаю у меня еще будут задания где я смогу применить Вашу идею.
Решил проблему с ошибкой Отчет сводной таблицы был сохранен без данных. Для обновления отчета используйте команду "обновить данные"
Добавил в код 2 строчки:
[vba]
Код
PVTable.PivotCache.Refresh ' Обновление данных сводной таблицы PVTable.SaveData = True ' изменение параметра [b]сохранять исходные данные вместе с файлом[/b] в сводной таблице
[/vba]
Kuzmich, спасибо за идею возьму на вооружение. У меня уже почти готовый макрос с методом KuklP. Но думаю у меня еще будут задания где я смогу применить Вашу идею. Iurii
Посмотрите вариант со сводной таблицей на листе "Исх". Отдельные файлы в той же директории, что и исходный файл. Макрос запускать при активном листе "Исх"
[vba]
Код
Sub Main() Dim PRange As Range Dim PTCache As PivotCache Dim PT As PivotTable Dim FinalRow As Long Dim FinalCol As Integer Dim WBN As Workbook Dim WSh As Worksheet Application.ScreenUpdating = False FinalRow = Cells(Application.Rows.Count, 1).End(xlUp).Row FinalCol = Cells(1, Application.Columns.Count).End(xlToLeft).Column Set PRange = Cells(1, 1).Resize(FinalRow, FinalCol) Set PTCache = ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:=PRange.Address) Set PT = PTCache.CreatePivotTable(TableDestination:=Cells(2, FinalCol + 2), TableName:="PivotTable1") PT.ManualUpdate = True PT.AddFields RowFields:=Array("Менеджер", "Номенклатура"), ColumnFields:="Данные", _ PageFields:="Подразделение" With PT.PivotFields("Данные1") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "# ##0" .Name = "Сумма_1" End With With PT.PivotFields("Данные2") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "# ##0" .Name = "Сумма_2" End With With PT.PivotFields("Данные3") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "# ##0" .Name = "Сумма_3" End With With PT.PivotFields("Данные4") .Orientation = xlDataField .Function = xlSum .Position = 4 .NumberFormat = "# ##0" .Name = "Сумма_4" End With With PT.PivotFields("Данные5") .Orientation = xlDataField .Function = xlSum .Position = 5 .NumberFormat = "# ##0" .Name = "Сумма_5" End With With PT.PivotFields("Данные6") .Orientation = xlDataField .Function = xlSum .Position = 6 .NumberFormat = "# ##0" .Name = "Сумма_6" End With With PT.PivotFields("Данные7") .Orientation = xlDataField .Function = xlSum .Position = 7 .NumberFormat = "# ##0" .Name = "Сумма_7" End With PT.NullString = "0" PT.ManualUpdate = False PT.ManualUpdate = True Dim PivItem As Object 'цикл по значениям поля Подразделение For Each PivItem In PT.PivotFields("Подразделение").PivotItems PT.PivotFields("Подразделение").CurrentPage = PivItem.Name 'пересчитать сводную таблицу PT.ManualUpdate = False PT.ManualUpdate = True Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSh = WBN.Worksheets(1) WSh.Name = PivItem.Name 'копируем диапазон соответствующего Подразделения PT.TableRange2.Offset(3, 0).Copy WSh.Range("A2").PasteSpecial xlPasteValuesAndNumberFormats WSh.Columns("A:I").AutoFit WBN.SaveAs Filename:=ThisWorkbook.Path & "\" & WSh.Name & ".xls" WBN.Close SaveChanges:=True Next Application.ScreenUpdating = True End Sub
[/vba]
Посмотрите вариант со сводной таблицей на листе "Исх". Отдельные файлы в той же директории, что и исходный файл. Макрос запускать при активном листе "Исх"
[vba]
Код
Sub Main() Dim PRange As Range Dim PTCache As PivotCache Dim PT As PivotTable Dim FinalRow As Long Dim FinalCol As Integer Dim WBN As Workbook Dim WSh As Worksheet Application.ScreenUpdating = False FinalRow = Cells(Application.Rows.Count, 1).End(xlUp).Row FinalCol = Cells(1, Application.Columns.Count).End(xlToLeft).Column Set PRange = Cells(1, 1).Resize(FinalRow, FinalCol) Set PTCache = ActiveWorkbook.PivotCaches.Add(SourceType:=xlDatabase, SourceData:=PRange.Address) Set PT = PTCache.CreatePivotTable(TableDestination:=Cells(2, FinalCol + 2), TableName:="PivotTable1") PT.ManualUpdate = True PT.AddFields RowFields:=Array("Менеджер", "Номенклатура"), ColumnFields:="Данные", _ PageFields:="Подразделение" With PT.PivotFields("Данные1") .Orientation = xlDataField .Function = xlSum .Position = 1 .NumberFormat = "# ##0" .Name = "Сумма_1" End With With PT.PivotFields("Данные2") .Orientation = xlDataField .Function = xlSum .Position = 2 .NumberFormat = "# ##0" .Name = "Сумма_2" End With With PT.PivotFields("Данные3") .Orientation = xlDataField .Function = xlSum .Position = 3 .NumberFormat = "# ##0" .Name = "Сумма_3" End With With PT.PivotFields("Данные4") .Orientation = xlDataField .Function = xlSum .Position = 4 .NumberFormat = "# ##0" .Name = "Сумма_4" End With With PT.PivotFields("Данные5") .Orientation = xlDataField .Function = xlSum .Position = 5 .NumberFormat = "# ##0" .Name = "Сумма_5" End With With PT.PivotFields("Данные6") .Orientation = xlDataField .Function = xlSum .Position = 6 .NumberFormat = "# ##0" .Name = "Сумма_6" End With With PT.PivotFields("Данные7") .Orientation = xlDataField .Function = xlSum .Position = 7 .NumberFormat = "# ##0" .Name = "Сумма_7" End With PT.NullString = "0" PT.ManualUpdate = False PT.ManualUpdate = True Dim PivItem As Object 'цикл по значениям поля Подразделение For Each PivItem In PT.PivotFields("Подразделение").PivotItems PT.PivotFields("Подразделение").CurrentPage = PivItem.Name 'пересчитать сводную таблицу PT.ManualUpdate = False PT.ManualUpdate = True Set WBN = Workbooks.Add(xlWBATWorksheet) Set WSh = WBN.Worksheets(1) WSh.Name = PivItem.Name 'копируем диапазон соответствующего Подразделения PT.TableRange2.Offset(3, 0).Copy WSh.Range("A2").PasteSpecial xlPasteValuesAndNumberFormats WSh.Columns("A:I").AutoFit WBN.SaveAs Filename:=ThisWorkbook.Path & "\" & WSh.Name & ".xls" WBN.Close SaveChanges:=True Next Application.ScreenUpdating = True End Sub
Kuzmich, запустил Ваш макрос и теперь при открытии любого файла Excel параллельно открываются еще 3 файла с названиями Винница Киев и Днепр Как исправить?
Kuzmich, запустил Ваш макрос и теперь при открытии любого файла Excel параллельно открываются еще 3 файла с названиями Винница Киев и Днепр Как исправить?Iurii
Уточню(пошарил по загашникам) - до 2003 Экса включительно вып список автофильтра содержал не более 1000 значений, начиная с 2007 - 10000. Но метод specialcells нужный для копирования, возвращает диапазон не более 8192 прямоугольных областей. Так было до 2007 включительно. В версиях моложе - не знаю.
Уточню(пошарил по загашникам) - до 2003 Экса включительно вып список автофильтра содержал не более 1000 значений, начиная с 2007 - 10000. Но метод specialcells нужный для копирования, возвращает диапазон не более 8192 прямоугольных областей. Так было до 2007 включительно. В версиях моложе - не знаю.KuklP
Ну с НДС и мы чего-то стoим! kuklp60@gmail.com WM Z206653985942, R334086032478, U238399322728
Как только у меня будет конечный файл на более 80 тыс. строк
Не будем ждать! [vba]
Код
Sub ГенераторДобра_InExSu() 'Option Base 1 нужен 'генерирует данные по столбцам из имеющихся ячеек 'случайным образом 'ячейка диапазона должна быть активна. 'шапка таблицы пока не игнорируется. 'Call УскоряемExcel z = Application.InputBox(Title:="ГенераторДобра", Prompt:="Сколько строк добавить?", Type:=1) Dim r As Range: Set r = ActiveCell.CurrentRegion Dim arrZ(): ReDim arrZ(z, 2): Dim arr01() For Each cl In r.Columns arr01 = cl.Value For i = 1 To UBound(arrZ) arrZ(i, 1) = arr01(Int((UBound(arr01)) * Rnd + 1), 1) Next Cells(Cells(Rows.count, cl.Column).End(xlUp).Row + 1, cl.Column).Resize(UBound(arrZ), UBound(arrZ, 2)) = arrZ Next 'Call УскорениеExcelУбрать End Sub
Как только у меня будет конечный файл на более 80 тыс. строк
Не будем ждать! [vba]
Код
Sub ГенераторДобра_InExSu() 'Option Base 1 нужен 'генерирует данные по столбцам из имеющихся ячеек 'случайным образом 'ячейка диапазона должна быть активна. 'шапка таблицы пока не игнорируется. 'Call УскоряемExcel z = Application.InputBox(Title:="ГенераторДобра", Prompt:="Сколько строк добавить?", Type:=1) Dim r As Range: Set r = ActiveCell.CurrentRegion Dim arrZ(): ReDim arrZ(z, 2): Dim arr01() For Each cl In r.Columns arr01 = cl.Value For i = 1 To UBound(arrZ) arrZ(i, 1) = arr01(Int((UBound(arr01)) * Rnd + 1), 1) Next Cells(Cells(Rows.count, cl.Column).End(xlUp).Row + 1, cl.Column).Resize(UBound(arrZ), UBound(arrZ, 2)) = arrZ Next 'Call УскорениеExcelУбрать End Sub