Страницы: 1 2 След.
RSS
Как силами VBA реализовать формулу ВПР?
 
Добрый день!

Есть данные из 1С и данные с сайта, которые постоянно меняются по объему. Т.е. колонки стандарт, а количество вариативно.
Что делает макрос, преобразовывает данные из 1С в удобоваримые для сайта, сравнивает штрихкода на сайте и в 1С, и формирует данные для поставки.
Что сделано: Через запись макроса, сформировано тело макроса. С помощью всемогущего Интернет код ужат по возможности, через форумы добавлены отдельные элементы.

Вопрос: В макросе использую формулы ВПР, но есть затык, который меня беспокоит.

1. Формулу сформировал макросом и у нее есть обращение к таблице определенного размера. Как то можно эту переменную в формуле подстраивать под размеры таблицы? Плюс есть нюанс, когда макрос заканчивается то появляются расхождения между ШК. Но по факту оба ШК из разных источников "на вид" идентичны, т.е. цифра в цифру, и это самый большой минус
Код
    'проверяем на совпадение баркодов c WB
    Sheets("Номенклатура WB").Range("I:I").Cut
    Sheets("Номенклатура WB").Range("A:A").Insert Shift:=xlShiftToRight
    Sheets("Номенклатура WB").Range("A:A") = Sheets("Номенклатура WB").Range("A:A").Value
    LastRow = Cells(Rows.Count, "A").End(xlUp).Row
    Sheets("Сводные данные").Range("I2").FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1],'Номенклатура WB'!R[-1]C[-8]:R[414]C[2],1,FALSE),0)"
    Sheets("Сводные данные").Range("I2").AutoFill Destination:=Sheets("Сводные данные").Range("I2:I" & LastRow)
    Sheets("Сводные данные").Range("J2").FormulaR1C1 = "=IF(RC[-2]=RC[-1],""Нет"",""Есть"")"
    Sheets("Сводные данные").Range("J2").AutoFill Destination:=Sheets("Сводные данные").Range("J2:J" & LastRow)
    Sheets("Сводные данные").Range("I:J") = Sheets("Сводные данные").Range("I:J").Value
    'Worksheets("Номенклатура WB").Cells.ClearContents
  

2. Перфекто не дремлет, и хотелось бы реализовать эту функцию в VBA. Готовые конструкции находил, но не смог разобраться с механикой функции и перекроить ее под себя. Взято с другого тематического форума.

Код
Sub ee150604_0806()
Dim i, n, s1
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = Excel.Worksheets("лист1")  ''справочник
Set ws2 = Excel.Worksheets("лист2")  ''основной

For i = 1 To 5
s1 = ws2.Cells(i, 1)

For n = 1 To 5
If ws1.Cells(n, 1) = s1 Then

ws2.Cells(i, 2) = ws1.Cells(n, 2)

Exit For
End If
Next n
Next i

End Sub

3. Не могу разобраться почему в коде ниже если убрать первую строку результат не появляется. Код взят тоже из Интернет и адаптирован под мои задачи
Код
    Sheets("Упаковочные листы").Select 'почему без этой строки цикл ниже не выдает результата?
    Dim vItem, avArr, li As Long
    ReDim avArr(1 To ActiveWorkbook.Worksheets("Упаковочные листы").Rows.Count, 1 To 1)
    With New Collection
        On Error Resume Next
        For Each vItem In ActiveWorkbook.Worksheets("Упаковочные листы").Range("C2", Cells(ActiveWorkbook.Worksheets("Упаковочные листы").Rows.Count, 3).End(xlUp)).Value
            'Cells(Rows.Count, 1).End(xlUp) – определяет последнюю заполненную ячейку в столбце А
            .Add vItem, CStr(vItem)
            If Err = 0 Then
                li = li + 1: avArr(li, 1) = vItem
            Else: Err.Clear
            End If
        Next
    End With
    If li Then Sheets("ШК_коробов").Range("A2").Resize(li).Value = avArr
    ActiveWorkbook.Worksheets("ШК_коробов").Sort.SortFields.Clear
    ActiveWorkbook.Worksheets("ШК_коробов").Sort.SortFields.Add2 Key:=Range("A:A"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
    With ActiveWorkbook.Worksheets("ШК_коробов").Sort
        .SetRange Range("A:A")
        .Header = xlGuess
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

Любая критика приветствуется! Я уверен что код можно еще больше сжать и использовать более удобные и "правильные" конструкции.
И если Вам не сложно пишите комментарии к Вашему коду, чтоб была возможность потом самостоятельно повторить написанное.

Спасибо!
 
stolniy, а можете просто написать что нужно с такого столбца взять то и найти это в другом и после сделать так если найдено, если не найдено сделать так...у вас куча листов - разбирать код, капашиться в листах так себе вариант...
лучше показать где желаемый результат после обработки макроса
Изменено: Mershik - 30.08.2021 11:03:39
Не бойтесь совершенства. Вам его не достичь.
 
Если я Вас правильно понял:
Нужно сравнить данные из листа (Реализация 1С), столбец Q (Штрихкоды), с данными из листа (Номенклатура WB), столбец I (Баркоды)
Результат в лист (Сводные данные), столбец I (Баркоды WB)
Т.е. мне нужно сравнить данные из 1C c данными с сайта, и если они совпадают подставить данные сайта в колонку, если не совпадают  или их нет в данных сайта, как то это отразить....
 
КОД на словарях для подстановки значений по ключам в общем виде
Файл: VBA. VLookUp.xlsb (24.29 КБ)
Изменено: Jack Famous - 31.08.2021 13:32:03
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Слишком много разных вопросов в одной теме. Понятно, что они все к одному коду относятся, но они практически не связаны друг с другом ничем более. Модераторы будут ругаться. Отвечу только на последний:
Цитата
stolniy написал:
почему в коде ниже если убрать первую строку результат не появляется.
потому что код написан криво, хотя попытки сделать его более "прямым" есть. Вот в этой строке затык:
Цитата
stolniy написал:
For Each vItem In ActiveWorkbook.Worksheets("Упаковочные листы").Range("C2", Cells(ActiveWorkbook.Worksheets("Упаковочные листы").Rows.Count, 3).End(xlUp)).Value
практически по всем элементам здесь идет обращение к Worksheets("Упаковочные листы"). Но вот перед Cells этого нет. Что и заставляет в итоге код отрабатывать неверно, если не выделить этот самый лист. Если уберете строку On Error Resume Next, то увидите, что на этой строке будет ошибка обращения к диапазону.
Если написать правильно:
Код
For Each vItem In ActiveWorkbook.Worksheets("Упаковочные листы").Range("C2", ActiveWorkbook.Worksheets("Упаковочные листы").Cells(ActiveWorkbook.Worksheets("Упаковочные листы").Rows.Count, 3).End(xlUp)).Value
то все будет работать без активации листа. Подробнее про подобные нюансы расписывал здесь: Как обратиться к диапазону из VBA
Правда дальше у Вас есть такая же ошибка - при сортировке везде указывается конкретный лист, кроме установки ключа и диапазона.  
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
stolniy, вернитесь в #3 и приведите его в порядок: не цитата там, а копия предыдущего сообщения.
И Дмитрий совершенно верно написал Вам, напоминая правила: один вопрос - одна тема.
 
Цитата
Дмитрий(The_Prist) Щербаков написал: при сортировке везде указывается конкретный лист, кроме установки ключа и диапазона.  
Спасибо, сделал все по Вашему совету работает!

Цитата
Дмитрий(The_Prist) Щербаков написал: Модераторы будут ругаться
Да простят меня модераторы ;) , не хотел создавать 10 тем...
Изменено: vikttur - 07.09.2021 13:36:05
 
Цитата
stolniy написал:
не хотел создавать 10 тем.
А создавать 10 разных вопросов в одной теме лучше?
 
Вину признаю, разбить на темы?  
 
Откуда мне знать? Если нужны ответы на оставшиеся вопросы, то следует создать новые темы. Если всё уже понятно - не создавайте.
 
Цитата
Jack Famous написал:
Файл:  VBA. VLookUp.xlsb  (18.6 КБ)

Скопировал Ваш код на отдельный макрос, но запустить не могу, ругается на словарь... В какую сторону копать?
 
Код
Если было так
    Dim dic As Dictionary
    Set dic = New Dictionary

Сделайте так
    Dim dic As Object
    Set dic = CreateObject("Scripting.Dictionary")
 
МатросНаЗебре, +
stolniy, читаем матчасть
Изменено: Jack Famous - 31.08.2021 10:54:00
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
МатросНаЗебре ... читаем  матчасть
А мне это зачем? Или в моём сообщении было нечто такое, что заставило предположить, что я этого не знаю? )
 
Ну здрасьте приехали )))
Изменено: Jack Famous - 31.08.2021 11:16:48
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
А, понял. Это был не оператор сложения, это был оператор одобрения )
 
МатросНаЗебре, так точно  8) благодарю  ;)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Код
For Each ar In Range("_insert")                                     ' цикл по всем областям диапазона вставки (именованный диапазон "_insert")
Коллеги, как можно заменить диапазон _insert, на Sheets("Сводные данные").range("H2:последняя заполненная ячейка")?
 
Цитата
МатросНаЗебре написал:
   Dim dic As Object    Set dic = CreateObject("Scripting.Dictionary")
Спасибо! Прилепил, заработало
Цитата
Jack Famous написал:
stolniy , читаем  матчасть
Спасибо! Прочитал, нашел предложение МатросНаЗебре, прилепил заработало
 
stolniy,
Код
For Each ar In Sheets("Сводные данные").range("H2:последняя заполненная ячейка")
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Что то мне подсказывает что так работать не будет...  :)  Видимо вопрос нужно конкретизировать, как изменить код, чтобы он обращался к конкретному столбцу, со второй ячейки и до последней заполненной? Пробывал ставить Sheets("Сводные данные").Range("H:H") вместо Range("_insert"), он обрабатывает весь столбец и начинает заметно тормозить
 
LastRow = 100 'номер последней строки
For Each ar In Sheets("Сводные данные").range("H2:H" & LastRow)
 
Цитата
New написал: For Each ar In Sheets("Сводные данные").range("H2:H" & LastRow)
Спасибо, New! Я пробовал подобное но ошибся в написании, закрыл кавычками весь путь... : Range("H2:H & LastRow" ) А по незнанию подумал что тут так не сделать.
Код
Dim LastRow As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row

For Each ar In Sheets("Сводные данные").Range("H2:H" & LastRow)
 
Цитата
stolniy: Что то мне подсказывает что так работать не будет
я думал, что вы имеете ввиду конкретный диапазон или переменную последней строки
Вопрос данной темы не касается - смотрите тут, где-то ещё или создавайте новую тему для этого нового вопроса
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Вдруг кому-то пригодится. Итоговый код от Jack Famous, с небольшими изменениями: вместо диспетчера имен (Ctrl+F3) с диапазоном "_insert", обращение к конкретному листу и столбцу, в котором проверяем значения.
Код
Option Explicit
'====================================================================================================
Sub Test()
Dim dic As Object
Set dic = CreateObject("Scripting.Dictionary")
Dim ar As Range
Dim arrK, arrV, arrOne(1 To 1, 1 To 1)
Dim t!, r&, c&, n&, AC&
Dim LastRow As Long
LastRow = Cells(Rows.Count, "A").End(xlUp).Row
t = Timer                                           ' засекаем время
arrK = Worksheets("Номенклатура WB").Range("I:I").Value  ' берём в массив диапазон КЛЮЧЕЙ с листа
arrV = Worksheets("Номенклатура WB").Range("I:I").Value  ' берём в массив диапазон соответствующих ключам ЗНАЧЕНИЙ с листа (В аналогии ВПР - это номер столбца)

For r = 1 To UBound(arrK, 1)                                            ' цикл по массивам с наполнением словаря
    If Not dic.Exists(arrK(r, 1)) Then dic.Add arrK(r, 1), arrV(r, 1)   ' если очередное значение из массива КЛЮЧЕЙ ещё не было добавлено, то добавляем пару КЛЮЧ-ЗНАЧЕНИЕ из двух массивов
Next r
arrV = 0                                                                ' очищаем переменную с массивом значений


Application.ScreenUpdating = False                                          ' отключаем обновление экрана
AC = Application.Calculation: Application.Calculation = xlCalculationManual ' запоминаем, какой пересчёт установлен в книге и ставим ручной

For Each ar In Sheets("Сводные данные").Range("H2:H" & LastRow)                                    ' цикл по всем областям диапазона вставки (это столбец который проверяется на соответствие значению, если значение не совпадает с ключами подставляется !!! NO KEY >)
    arrK = ar.Value                                                 ' забираем область в массив
    If Not IsArray(arrK) Then arrOne(1, 1) = arrK: arrK = arrOne    ' если получили НЕ массив, значит область состояла из одной ячейки. Преобразуем это значение в двумерный массив

    For c = 1 To UBound(arrK, 2)                                    ' цикл по столбцам массива
        For r = 1 To UBound(arrK, 1)                                ' цикл по строкам массива
            If dic.Exists(arrK(r, c)) Then                      ' если очередное значение массива ЕСТЬ в словаре в качестве КЛЮЧА …
                n = n + 1: arrK(r, c) = dic(arrK(r, c))             ' увеличиваем счётчик найденных ключей и заменяем этот КЛЮЧ на соответствующее ему ЗНАЧЕНИЕ
            Else                                                ' если такого ключа НЕТ …
                arrK(r, c) = "!!! NO KEY > " & arrK(r, c)       ' добавляем к значению префикс для удобства поиска
            End If
        Next r
    Next c

    ar.Value = arrK
Next ar

Application.ScreenUpdating = True: Application.Calculation = AC ' включаем обновление экрана и восстанавливаем пересчёт
MsgBox "Was inserted Values by Keys: " & Format$(n, "#,##0") & " out of " & Format$(Range("_insert").Cells.Count, "#,##0"), vbInformation, Format$(Timer - t, "0.00 sec")
End Sub
'====================================================================================================
'====================================================================================================

 
Цитата
stolniy: Итоговый код от  Jack Famous , с небольшими изменениями
не-не - я к этому Франкенштейну отношение иметь не хочу:
    1. массив ключей и массив значений это один и тот же массив - это вообще зачем тогда весь макрос, смысл которого заменить КЛЮЧИ на ЗНАЧЕНИЯ (а не КЛЮЧИ на КЛЮЧИ)?
    2. массив берёте на весь столбец - это 2 массива по более чем миллиона значений в каждом
Браво! Хорошо хоть пустой ключ будет всего один, благодаря словарям …
    3. Учитывая п.1 не понимаю, что у вас в конце изменится

Вы хоть тестили, что предлагаете? Всё нормально, всё устраивает?  :D
Изменено: Jack Famous - 31.08.2021 13:05:18
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Вроде все работает  :) .
Я сравнивал штрихкоды двух столбцах в разных листах, логика такая если значение совпадет то все ок, если нет, цепляется !!! NO KEY >
 
Цитата
stolniy: если значение совпадет то все ок, если нет, цепляется !!! NO KEY >
обновил #4
А также, для вашего случая …
Изменено: Jack Famous - 31.08.2021 13:50:03
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
А также, для вашего случая
Не понял, куда в макросе CheckKeys вставить этот фрагмент....
 
КОД (не тестил)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1 2 След.
Наверх