Страницы: 1
RSS
Оптимизация макроса копирования из таблицы в отдельные ячейки разных листов
 
Добрый день!
Имеется исходная таблица в которой отражен список смет с определенными данными
Из этой таблицы необходимо заполнить 100 листов книги, 1 лист - отдельная смета с наименованием "см.N" (в примере работает макрос для 5 листов)
Наименования листов - строго: "см.1, см.2 ... см.100"

Количество столбцов исходной таблицы, а следовательно и сметы - может увеличиваться.
Все данные с исходной таблице должны копироваться в виде значения (без форматирования и формул).

Я записал макрос для 5 листов через штатную функцию Excel, убрал лишнее, но объем макроса для 5 листов - получился очень внушительный
Для вас это покажется кодом "вырви глаз", но я не программист, поэтому и прошу вашей помощи в оптимизации макроса...

Может это как-то сделать блоками, допустим:
     1) блок копирования Столбца "Наименование" в каждый лист сметы см.1...см.100
     2) блок копирования Столбца "Стоимость" в каждый лист сметы см.1...см.100
     .
     .
     n) блок копирования любого нового столбца...
Изменено: Maxim - 20.06.2022 15:34:28
 
Не знаю для чего это нужно но я бы сделал слияние в "Ворд"  
Изменено: Shuav - 20.06.2022 15:42:39
 
Цитата
Shuav написал:
Не знаю для чего это нужно но я бы сделал слияние в "Ворд"  
Слияние в Word - не нужно, т.к. в каждой смете потом будет производиться экономический расчет показателей (форма заполнения каждого листа будет соблюдена, подцеплю формулы).
Вообще рабочим файлом пользуюсь лет 9, а вот заполняется каждая смета всегда вручную, поэтому хочу как-нибудь оптимизировать процесс заполнения
 
Я так понимаю у Вас коммерческие сметы? А не по сборникам
 
может лучше воспользоваться формулой типа =ИНДЕКС(Расценки!$E$2:$E$89;ПОИСКПОЗ(Расчет!$C16;Расценки!$B$2:$B$89;0)), а наименование работы выбирать из раскрывающегося списка ?
 
Цитата
Shuav написал:
Я так понимаю у Вас коммерческие сметы? А не по сборникам
Нет, сметы по сборникам ФЭР, БЦ.
Рабочий файл - бюджет проекта, к каждой смете есть вкладка с выгрузкой ресурсов.
Выгрузку ресурсов отрабатывают производтственники и МТС (что и сколько купить по факту, а не по смете, сколько стоит)
В во вкладках см.1 и тд - формируется экономическая составляющая данной работы

В примере - я создал примитивную рыбу самого бюджета, т.к. это госорганизация и показывать такое нельзя.
Изменено: Maxim - 20.06.2022 16:15:31
 
Maxim, добрый вечер!
Код прокомментировал (см. ниже). Нажимаете кнопку и смотрите результат  :)

Код
Sub CopyData()
Dim arr, i As Long, j, shName As String, lr As Long, lC As Long, sh As Worksheet

arr = Worksheets("Сводка").Cells(4, 2).CurrentRegion ' подразумевается, что левый верхний угол таблицы - это В4
For i = 3 To UBound(arr, 1) ' 3 - это строка Подготовка котлована (первые 2 - это шапка)

    shName = "см." & arr(i, 1) ' склеиваем строку см. с №п.п
    If Not SheetExists(shName) Then
        Set sh = Application.Worksheets.Add(after:=Worksheets(Worksheets.Count)): shName = "см." & Int(Right(shName, 1)) - 1
        With sh
            .Name = ("см." & Int(Right(shName, 1)) + 1): Worksheets(shName).Cells(4, 2).CurrentRegion.Copy sh.Cells(3, 2): shName = ("см." & Int(Right(shName, 1)) + 1)
            .Cells(3, 2).CurrentRegion.Columns.AutoFit
        End With
    End If
With Worksheets(shName)
    .[B3] = "Смета" & arr(i, 1): .[B4] = "Наименование работы"
    For j = 2 To UBound(arr, 2)
            If j = 2 Then
                .Cells(4, 2) = .Cells(4, 2).Value & ": """ & arr(i, j) & """" ' Cells(4,2) == [B4]
                With .Cells(4, 2) ' B4
                    .HorizontalAlignment = xlCenter ' выравнивание по горизонтали ячейки И4
                    .WrapText = True ' перенос текста == переносить текст
                End With
               lr = 5: lC = 3
            Else
                .Cells(lr, lC) = arr(i, j)
                lC = lC + 1 ' смещаемся на 1 столбец вправо
            End If
        Next j
End With
Next i
End Sub
Private Function SheetExists(shName As String) As Boolean
Dim sh As Worksheet
    For Each sh In Worksheets
        If sh.Name = shName Then SheetExists = True: Exit Function
    Next sh
SheetExists = False
End Function

Изменено: artemkau88 - 20.06.2022 21:09:46
 
Цитата
Shuav написал:
Не знаю для чего это нужно
Цитата
Maxim написал:
это госорганизация и показывать такое нельзя
:D  потому что
Цитата
Maxim написал:
что и сколько купить по факту, а не по смете, сколько стоит
т.е. чтобы не нашли, насколько 100 или 500 смет завышены :)
 
см. вложение
макрос написан (ВНИМАНИЕ! вносить в него исправления не нужно)
вносите в колонки А, В новые  пары правил копирования
заполняйте данными сметы на листе Сводка
Удачи!
Код
Sub EstimateFill()
  Dim a, adr$, b, c&, cc&, m, r&, rc&, re, s$, ws1 As Worksheet
  Set re = CreateObject("VBScript.RegExp"): re.Pattern = "[A-Z]+:*[A-Z]*"
  With Worksheets(1)
    rc = .Cells(Rows.Count, 1).End(xlUp).Row: Set ws1 = .[a1].Parent
    cc = .Cells(Rows.Count, 3).End(xlUp).Row: a = .[a1].CurrentRegion
  End With
  For c = 3 To cc
  If c - 1 > Worksheets.Count Then Worksheets(2).Copy after:=Worksheets(Worksheets.Count)
  With Worksheets(c - 1)
    For r = 2 To rc
      Set m = re.Execute(a(r, 1))(0)
      If InStr(m, ":") Then adr = Replace(m, ":", c & ":") & c Else adr = m & c
      b = ws1.Range(adr)
      If InStr(adr, ":") Then
        .Range(a(r, 2)).Resize(UBound(b), UBound(b, 2)) = b
      Else
        .Range(a(r, 2)) = Replace(a(r, 1), m, b)
      End If
    Next
  End With
  Next
  MsgBox "Заполнено смет: " & cc - 2 & " шт.", , "Готово!"
End Sub
Изменено: Ігор Гончаренко - 20.06.2022 21:36:36
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
artemkau88 написал:
Maxim , добрый вечер!
Код прокомментировал (см. ниже). Нажимаете кнопку и смотрите результат  :)

Код
    [URL=#]?[/URL]       1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39      Sub   CopyData()    Dim   arr, i   As   Long  , j, shName   As   String  , lr   As   Long  , lC   As   Long  , sh   As   Worksheet       arr = Worksheets(  "Сводка"  ).Cells(4, 2).CurrentRegion   ' подразумевается, что левый верхний угол таблицы - это В4    For   i = 3   To   UBound(arr, 1)   ' 3 - это строка Подготовка котлована (первые 2 - это шапка)             shName =   "см."   & arr(i, 1)   ' склеиваем строку см. с №п.п          If   Not   SheetExists(shName)   Then              Set   sh = Application.Worksheets.Add(after:=Worksheets(Worksheets.Count)): shName =   "см."   & Int(Right(shName, 1)) - 1              With   sh                  .Name = (  "см."   & Int(Right(shName, 1)) + 1): Worksheets(shName).Cells(4, 2).CurrentRegion.Copy sh.Cells(3, 2): shName = (  "см."   & Int(Right(shName, 1)) + 1)                  .Cells(3, 2).CurrentRegion.Columns.AutoFit              End   With          End   If    With   Worksheets(shName)          .[B3] =   "Смета"   & arr(i, 1): .[B4] =   "Наименование работы"          For   j = 2   To   UBound(arr, 2)                  If   j = 2   Then                      .Cells(4, 2) = .Cells(4, 2).Value &   ": "  ""   & arr(i, j) &   ""  ""   ' Cells(4,2) == [B4]                      With   .Cells(4, 2)   ' B4                          .HorizontalAlignment = xlCenter   ' выравнивание по горизонтали ячейки И4                          .WrapText =   True   ' перенос текста == переносить текст                      End   With                     lr = 5: lC = 3                  Else                      .Cells(lr, lC) = arr(i, j)                      lC = lC + 1   ' смещаемся на 1 столбец вправо                  End   If              Next   j    End   With    Next   i    End   Sub    Private   Function   SheetExists(shName   As   String  )   As   Boolean    Dim   sh   As   Worksheet          For   Each   sh   In   Worksheets              If   sh.Name = shName   Then   SheetExists =   True  :   Exit   Function          Next   sh    SheetExists =   False    End   Function   
 
Спасибо большое за помощь!
 
Цитата
Ігор Гончаренко написал:
см. вложение
макрос написан (ВНИМАНИЕ! вносить в него исправления не нужно)
вносите в колонки А, В новые  пары правил копирования
заполняйте данными сметы на листе Сводка
Удачи!
Код
    [URL=#]?[/URL]       1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24      Sub   EstimateFill()        Dim   a, adr$, b, c&, cc&, m, r&, rc&, re, s$, ws1   As   Worksheet        Set   re = CreateObject(  "VBScript.RegExp"  ): re.Pattern =   "[A-Z]+:*[A-Z]*"        With   Worksheets(1)          rc = .Cells(Rows.Count, 1).  End  (xlUp).Row:   Set   ws1 = .[a1].Parent          cc = .Cells(Rows.Count, 3).  End  (xlUp).Row: a = .[a1].CurrentRegion        End   With        For   c = 3   To   cc        If   c - 1 > Worksheets.Count   Then   Worksheets(2).Copy after:=Worksheets(Worksheets.Count)        With   Worksheets(c - 1)          For   r = 2   To   rc            Set   m = re.Execute(a(r, 1))(0)            If   InStr(m,   ":"  )   Then   adr = Replace(m,   ":"  , c &   ":"  ) & c   Else   adr = m & c            b = ws1.Range(adr)            If   InStr(adr,   ":"  )   Then              .Range(a(r, 2)).Resize(UBound(b), UBound(b, 2)) = b            Else              .Range(a(r, 2)) = Replace(a(r, 1), m, b)            End   If          Next        End   With        Next        MsgBox   "Заполнено смет: "   & cc - 2 &   " шт."  , ,   "Готово!"    End   Sub   
 
Большое спасибо! Буду разбираться!
 
Цитата
_Igor_61 написал:
Цитата
Shuav написал:
Не знаю для чего это нужно
Цитата
Maxim написал:
это госорганизация и показывать такое нельзя
:D  потому что
Цитата
Maxim написал:
что и сколько купить по факту, а не по смете, сколько стоит
т.е. чтобы не нашли, насколько 100 или 500 смет завышены :)

Хорошая попытка, но не смешно, увы
 
Цитата
Ігор Гончаренко написал:
см. вложение
макрос написан (ВНИМАНИЕ! вносить в него исправления не нужно)
вносите в колонки А, В новые  пары правил копирования
заполняйте данными сметы на листе Сводка
Удачи!
Код
    [URL=#]?[/URL]       1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24      Sub   EstimateFill()        Dim   a, adr$, b, c&, cc&, m, r&, rc&, re, s$, ws1   As   Worksheet        Set   re = CreateObject(  "VBScript.RegExp"  ): re.Pattern =   "[A-Z]+:*[A-Z]*"        With   Worksheets(1)          rc = .Cells(Rows.Count, 1).  End  (xlUp).Row:   Set   ws1 = .[a1].Parent          cc = .Cells(Rows.Count, 3).  End  (xlUp).Row: a = .[a1].CurrentRegion        End   With        For   c = 3   To   cc        If   c - 1 > Worksheets.Count   Then   Worksheets(2).Copy after:=Worksheets(Worksheets.Count)        With   Worksheets(c - 1)          For   r = 2   To   rc            Set   m = re.Execute(a(r, 1))(0)            If   InStr(m,   ":"  )   Then   adr = Replace(m,   ":"  , c &   ":"  ) & c   Else   adr = m & c            b = ws1.Range(adr)            If   InStr(adr,   ":"  )   Then              .Range(a(r, 2)).Resize(UBound(b), UBound(b, 2)) = b            Else              .Range(a(r, 2)) = Replace(a(r, 1), m, b)            End   If          Next        End   With        Next        MsgBox   "Заполнено смет: "   & cc - 2 &   " шт."  , ,   "Готово!"    End   Sub   
 
Посмотрел как работает макрос - это шедевр!
Огромное спасибо еще раз!
Полностью раскрывает тему вопроса и гибко настраивается!
 
Правила копирования настраиваются так:
в колонке А
пишете откуда взять данные, с какой колонки или с диапазона колонок, если данные из строки сметы ложатся в бланк сметы в таком же порядке
имя колонки (диапазона пишется БОЛЬШИМИ ЛАТИНСКИМИ БУКВАМИ)
для копирования одиночной ячейки допускается в А внести дополнительный текст, например: Смета № C (здесь последняя С это латинская С) в результатте в бланк попадет надпись Смета № №№, где №№ - № сметы указанный в колонке С
в колонке В
указываете адрес конкретной ячейки, куда скопировать данные. если копируете диапазон, можно указать адрес первой ячейки (остальное будет размещено правее), например а А написано E:G, то в В можно написать С5:Е5, а можно просто С5, результат будет один и тот же. в колонке В нужно указывать конкретный и корректный адрес ячейки в бланке сметы.
Изменено: Ігор Гончаренко - 21.06.2022 09:37:31
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
Ігор Гончаренко написал:
Правила копирования настраиваются так:
 в колонке А  
пишете откуда взять данные, с какой колонки или с диапазона колонок, если данные из строки сметы ложатся в бланк сметы в таком же порядке
имя колонки (диапазона пишется БОЛЬШИМИ ЛАТИНСКИМИ БУКВАМИ)
для копирования одиночной ячейки допускается в А внести дополнительный текст, например: Смета № C (здесь последняя С это латинская С) в результате в бланк попадет надпись Смета № №№, где №№ - № сметы указанный в колонке С
 в колонке В  
указываете адрес конкретной ячейки, куда скопировать данные. если копируете диапазон, можно указать адрес первой ячейки (остальное будет размещено правее), например а А написано E:G, то в В можно написать С5:Е5, а можно просто С5, результат будет один и тот же. в колонке В нужно указывать конкретный и корректный адрес ячейки в бланке сметы.
Скажите, а как быть если:
   1) Между сметами находятся суперскрытые листы? Например между сметой 1 и 2 есть лист. Тогда значения с исходной таблицы будут заполняться во все листы, которые идут после листа с Исходными данными, в т.ч. и в суперскрытые листы
   2) Лист с исходными данными по счету не первый, а любой другой (перед листом с исходными данными есть еще листы)
 
1. нужно придумать какими будут имена листов и чуть поправить макрос и обращаться к листам не по номеру, а по имени
и фрагмент, который добавляет новые листы нужно исправить делать копию с "правильного листа" а не со второго, и добавленному листу присвоить "правильное имя" согласно принятого алгоритма наименования листов
2. это вообще элементарно в строке 4 макроса заменить With Worksheets(1) на With Worksheets("Сводка")
Изменено: Ігор Гончаренко - 21.06.2022 10:00:34
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
Ігор Гончаренко написал:
роке 4 макроса заменить With Worksheets(1) на With Worksheets("Сводка"
1) имена всех листов известны: "см.1", "см.2", ..., "см.100". Только между ними точно будут встречаться другие листы. я хотел сделать обход этих листов суперскрытием через макрос, но, как писал выше - не удалось
2) изменил в 4 строке With Worksheets(1) на With Worksheets("Сводка"), как результат - все равно копирование начинается со второго листа.
 
Цитата
Ігор Гончаренко написал:
1. нужно придумать какими будут имена листов и чуть поправить макрос и обращаться к листам не по номеру, а по имени
и фрагмент, который добавляет новые листы нужно исправить делать копию с "правильного листа" а не со второго, и добавленному листу присвоить "правильное имя" согласно принятого алгоритма наименования листов
2. это вообще элементарно в строке 4 макроса заменить With Worksheets(1) на With Worksheets("Сводка")
Игорь, добрый день!
Будьте добры помочь по вашему макросу:
   1) Нужно добавить условие, чтобы копирование производилось только в листы с названием "см.1", "см.2", ..., "см.100".
другими словами - между листами куда копируем данные - будут находиться еще листы, в которые не должно происходить копирование
   2) Лист с исходными данными может быть не первый по очереди, обращался к нему через имя - With Worksheets(1) на With Worksheets("Сводка"), но результат не получил, копирование начинается все равно со второго листа по счету

Код
Option Explicit

Sub EstimateFill()
  Dim a, adr$, b, c&, cc&, m, r&, rc&, re, s$, ws1 As Worksheet
  Set re = CreateObject("VBScript.RegExp"): re.Pattern = "[A-Z]+:*[A-Z]*"
  With Worksheets("Сводка")
    rc = .Cells(Rows.Count, 1).End(xlUp).Row: Set ws1 = .[a1].Parent
    cc = .Cells(Rows.Count, 3).End(xlUp).Row: a = .[a1].CurrentRegion
  End With
  For c = 3 To cc
  If c - 1 > Worksheets.Count Then Worksheets(2).Copy after:=Worksheets(Worksheets.Count)
  With Worksheets(c - 1)
    For r = 2 To rc
      Set m = re.Execute(a(r, 1))(0)
      If InStr(m, ":") Then adr = Replace(m, ":", c & ":") & c Else adr = m & c
      b = ws1.Range(adr)
      If InStr(adr, ":") Then
        .Range(a(r, 2)).Resize(UBound(b), UBound(b, 2)) = b
      Else
        .Range(a(r, 2)) = Replace(a(r, 1), m, b)
      End If
    Next
  End With
  Next
  MsgBox "Заполнено смет: " & cc - 2 & " шт.", , "Готово!"
End Sub
Изменено: Maxim - 08.09.2022 16:13:23
 
Maxim, пожалуйста, прекратите нажимать на кнопку Цитировать, если не хотите процитировать какой-то отдельный текст другого пользователя. Нажимайте кнопку "Имя", она находится правее на 1 см от кнопки Цитировать. Читать тему невозможно из-за ваших цитированный целиком всего текста
 
New, ,буду знать, спасибо за подсказку. Я не гуру форумов...
 
см. вложение
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Ігор Гончаренко, правильно ли я понимаю, что в момент заполнения все листы, которые находятся правее листа с исходными данными - удаляются, а потом создаются и заполняются новые?
 
да, правильно
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Ігор Гончаренко, благодарю за помощь!
Страницы: 1
Наверх