Домашняя страница Undo Do New Save Карта сайта Обратная связь Поиск по форуму
МИР MS EXCEL - Гость.xls

Вход

Регистрация

Напомнить пароль

 

= Мир MS Excel/Поиск значения по двум параметрам - Мир MS Excel

Старая форма входа
  • Страница 1 из 1
  • 1
Модератор форума: китин, _Boroda_  
Мир MS Excel » Вопросы и решения » Вопросы по VBA » Поиск значения по двум параметрам (Макросы/Sub)
Поиск значения по двум параметрам
andr89 Дата: Воскресенье, 29.03.2015, 14:58 | Сообщение № 1
Группа: Пользователи
Ранг: Новичок
Сообщений: 14
Репутация: 0 ±
Замечаний: 0% ±

Excel 2010
Добрый день

Подскажите, как при помощи макроса, по двум параметрам (в примере "номер продукта" и "номер магазина") из первой таблицы, записать значение третьего параметра (в примере "цена") во вторую таблицу.
Функция ВПР не подходит, т.к. работает слишком долго (обычно приходится работать с файлами, где содержится более 50 тыс строк информации).
Возможно сделать, что-то наподобие запроса в MS Access?

Если такая тема уже существует, скиньте плз ссылку.

Спасибо.
К сообщению приложен файл: 2967439.xlsx (9.7 Kb)
 
Ответить
СообщениеДобрый день

Подскажите, как при помощи макроса, по двум параметрам (в примере "номер продукта" и "номер магазина") из первой таблицы, записать значение третьего параметра (в примере "цена") во вторую таблицу.
Функция ВПР не подходит, т.к. работает слишком долго (обычно приходится работать с файлами, где содержится более 50 тыс строк информации).
Возможно сделать, что-то наподобие запроса в MS Access?

Если такая тема уже существует, скиньте плз ссылку.

Спасибо.

Автор - andr89
Дата добавления - 29.03.2015 в 14:58
Leanna Дата: Воскресенье, 29.03.2015, 15:55 | Сообщение № 2
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 189
Репутация: 78 ±
Замечаний: 0% ±

excel 2010
Макрос с той же логикой что и ВПР для вашей таблицы
К сообщению приложен файл: 5314183.xlsm (20.8 Kb)


Лучше день потерять, потом за пять минут долететь!
 
Ответить
СообщениеМакрос с той же логикой что и ВПР для вашей таблицы

Автор - Leanna
Дата добавления - 29.03.2015 в 15:55
andr89 Дата: Воскресенье, 29.03.2015, 16:24 | Сообщение № 3
Группа: Пользователи
Ранг: Новичок
Сообщений: 14
Репутация: 0 ±
Замечаний: 0% ±

Excel 2010
Спасибо большое
 
Ответить
СообщениеСпасибо большое

Автор - andr89
Дата добавления - 29.03.2015 в 16:24
andr89 Дата: Понедельник, 30.03.2015, 22:25 | Сообщение № 4
Группа: Пользователи
Ранг: Новичок
Сообщений: 14
Репутация: 0 ±
Замечаний: 0% ±

Excel 2010
Попробовал применить макрос на практике.
Из табл. с 70 ты строками подтягиваются значения в таблицу с 70 тыс строками. В итоге excel безнадежно завис.
Насколько я понял, дело в таблице откуда выбираются данные.
Подскажите, возможно как-нибудь оптимизировать работу макроса, чтобы он работал с таблицами где > 200 тыс строк?

Файл во вложении содержит таблицы с 2-мя тыс строк.

Заранее спасибо.
К сообщению приложен файл: _____-1-.xlsb (85.5 Kb)
 
Ответить
СообщениеПопробовал применить макрос на практике.
Из табл. с 70 ты строками подтягиваются значения в таблицу с 70 тыс строками. В итоге excel безнадежно завис.
Насколько я понял, дело в таблице откуда выбираются данные.
Подскажите, возможно как-нибудь оптимизировать работу макроса, чтобы он работал с таблицами где > 200 тыс строк?

Файл во вложении содержит таблицы с 2-мя тыс строк.

Заранее спасибо.

Автор - andr89
Дата добавления - 30.03.2015 в 22:25
Hugo Дата: Понедельник, 30.03.2015, 22:42 | Сообщение № 5
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3255
Репутация: 707 ±
Замечаний: 0% ±

2019
Если вот этот цикл написать так - скорость увеличивается в 2 раза!
[vba]
Код
    For ii = 1 To a
          If b(ii, 1) = d(i, 1) Then
          If b(ii, 2) = d(i, 2) Then e(i, 1) = b(ii, 4): Exit For
          End If
      Next
[/vba]

А так будет значительно быстрее (на словаре):
[vba]
Код
Sub Категория_товара3()
     Dim tm!: tm = Timer
     Dim t$

     With Worksheets("Группа погрузки")
         a = .Cells(.Rows.Count, 2).End(xlUp).Row
         b = .Range("B1", "E" & a)
     End With
     With Worksheets("Исходные данные")
         c = .Cells(.Rows.Count, 3).End(xlUp).Row
         d = .Range("C1", "D" & c)
         e = .Range("M1", "M" & c)
     End With

     With CreateObject("scripting.dictionary"): .comparemode = 1
         For i = 1 To a
             .Item(b(i, 1) & "|" & b(i, 2)) = b(i, 4)
         Next
         For i = 1 To c
             t = d(i, 1) & "|" & d(i, 2)
             If .exists(t) Then e(i, 1) = .Item(t)
         Next
     End With

     Range("M1", "M" & c) = e

     Debug.Print "код3=" & Timer - tm
End Sub
[/vba]
Вот сравнение по времени (по 3 попытки):

код1=0,7109375
код1=0,7265625
код1=0,71875
код2=0,34375
код2=0,34375
код2=0,3515625
код3=0,0625
код3=0,0625
код3=0,0625


excel@nxt.ru
webmoney: E265281470651 Z422237915069


Сообщение отредактировал Hugo - Понедельник, 30.03.2015, 22:56
 
Ответить
СообщениеЕсли вот этот цикл написать так - скорость увеличивается в 2 раза!
[vba]
Код
    For ii = 1 To a
          If b(ii, 1) = d(i, 1) Then
          If b(ii, 2) = d(i, 2) Then e(i, 1) = b(ii, 4): Exit For
          End If
      Next
[/vba]

А так будет значительно быстрее (на словаре):
[vba]
Код
Sub Категория_товара3()
     Dim tm!: tm = Timer
     Dim t$

     With Worksheets("Группа погрузки")
         a = .Cells(.Rows.Count, 2).End(xlUp).Row
         b = .Range("B1", "E" & a)
     End With
     With Worksheets("Исходные данные")
         c = .Cells(.Rows.Count, 3).End(xlUp).Row
         d = .Range("C1", "D" & c)
         e = .Range("M1", "M" & c)
     End With

     With CreateObject("scripting.dictionary"): .comparemode = 1
         For i = 1 To a
             .Item(b(i, 1) & "|" & b(i, 2)) = b(i, 4)
         Next
         For i = 1 To c
             t = d(i, 1) & "|" & d(i, 2)
             If .exists(t) Then e(i, 1) = .Item(t)
         Next
     End With

     Range("M1", "M" & c) = e

     Debug.Print "код3=" & Timer - tm
End Sub
[/vba]
Вот сравнение по времени (по 3 попытки):

код1=0,7109375
код1=0,7265625
код1=0,71875
код2=0,34375
код2=0,34375
код2=0,3515625
код3=0,0625
код3=0,0625
код3=0,0625

Автор - Hugo
Дата добавления - 30.03.2015 в 22:42
Leanna Дата: Понедельник, 30.03.2015, 22:56 | Сообщение № 6
Группа: Проверенные
Ранг: Форумчанин
Сообщений: 189
Репутация: 78 ±
Замечаний: 0% ±

excel 2010
Я ещё на словарях попробовала. В 10 раз быстрее получилось, не ожидала что словари быстрее циклов в массивах, буду теперь ими чаще пользоваться)
Проверьте только правильно ли оно там вставляет, а то голову сломала об эти a b c d e

[vba]
Код
Sub Категория_товара2()
t = Timer
Application.ScreenUpdating = False
Set dic = CreateObject("Scripting.Dictionary")

a = Worksheets("Группа погрузки").Cells(Rows.Count, 2).End(xlUp).Row
b = Worksheets("Группа погрузки").Range("B1", "E" & a)

c = Worksheets("Исходные данные").Cells(Rows.Count, 3).End(xlUp).Row
d = Worksheets("Исходные данные").Range("C1", "D" & c)
e = Worksheets("Исходные данные").Range("M1", "M" & c)

For ii = 1 To a
      dic.Item(b(ii, 1) & "|" & b(ii, 2)) = b(ii, 4)
Next
For i = 1 To c
      If dic.exists(d(i, 1) & "|" & d(i, 2)) Then e(i, 1) = dic.Item(d(i, 1) & "|" & d(i, 2)) Else e(i, 1) = Empty
Next
Range("M1", "M" & c) = e

Application.ScreenUpdating = True
Debug.Print Timer - t
End Sub
[/vba]
UPD код подредактировала
хм.. так шапка затирается, лучше ставьте диапазон сразу тот что надо, а не с первой строки т.е. Range("C4", "D" & c) и тд


Лучше день потерять, потом за пять минут долететь!

Сообщение отредактировал Leanna - Понедельник, 30.03.2015, 23:11
 
Ответить
СообщениеЯ ещё на словарях попробовала. В 10 раз быстрее получилось, не ожидала что словари быстрее циклов в массивах, буду теперь ими чаще пользоваться)
Проверьте только правильно ли оно там вставляет, а то голову сломала об эти a b c d e

[vba]
Код
Sub Категория_товара2()
t = Timer
Application.ScreenUpdating = False
Set dic = CreateObject("Scripting.Dictionary")

a = Worksheets("Группа погрузки").Cells(Rows.Count, 2).End(xlUp).Row
b = Worksheets("Группа погрузки").Range("B1", "E" & a)

c = Worksheets("Исходные данные").Cells(Rows.Count, 3).End(xlUp).Row
d = Worksheets("Исходные данные").Range("C1", "D" & c)
e = Worksheets("Исходные данные").Range("M1", "M" & c)

For ii = 1 To a
      dic.Item(b(ii, 1) & "|" & b(ii, 2)) = b(ii, 4)
Next
For i = 1 To c
      If dic.exists(d(i, 1) & "|" & d(i, 2)) Then e(i, 1) = dic.Item(d(i, 1) & "|" & d(i, 2)) Else e(i, 1) = Empty
Next
Range("M1", "M" & c) = e

Application.ScreenUpdating = True
Debug.Print Timer - t
End Sub
[/vba]
UPD код подредактировала
хм.. так шапка затирается, лучше ставьте диапазон сразу тот что надо, а не с первой строки т.е. Range("C4", "D" & c) и тд

Автор - Leanna
Дата добавления - 30.03.2015 в 22:56
Hugo Дата: Понедельник, 30.03.2015, 23:14 | Сообщение № 7
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3255
Репутация: 707 ±
Замечаний: 0% ±

2019
Да, создать массив с нуля будет побыстрее чем взять с листа - но иногда нужно дополнить то, что уже есть на листе. Но в общем это копейки... e = Range("M1", "M" & 70000) отрабатывает за 0 или 0,0078125


excel@nxt.ru
webmoney: E265281470651 Z422237915069
 
Ответить
СообщениеДа, создать массив с нуля будет побыстрее чем взять с листа - но иногда нужно дополнить то, что уже есть на листе. Но в общем это копейки... e = Range("M1", "M" & 70000) отрабатывает за 0 или 0,0078125

Автор - Hugo
Дата добавления - 30.03.2015 в 23:14
Hugo Дата: Понедельник, 30.03.2015, 23:17 | Сообщение № 8
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3255
Репутация: 707 ±
Замечаний: 0% ±

2019
А шапку можно или не трогать (сдвинуть массивы пониже), или заполнить этот один элемент массива кодом.


excel@nxt.ru
webmoney: E265281470651 Z422237915069
 
Ответить
СообщениеА шапку можно или не трогать (сдвинуть массивы пониже), или заполнить этот один элемент массива кодом.

Автор - Hugo
Дата добавления - 30.03.2015 в 23:17
andr89 Дата: Вторник, 31.03.2015, 00:19 | Сообщение № 9
Группа: Пользователи
Ранг: Новичок
Сообщений: 14
Репутация: 0 ±
Замечаний: 0% ±

Excel 2010
Ребята, спасибо за помощь!
 
Ответить
СообщениеРебята, спасибо за помощь!

Автор - andr89
Дата добавления - 31.03.2015 в 00:19
KSV Дата: Вторник, 31.03.2015, 02:38 | Сообщение № 10
Группа: Друзья
Ранг: Ветеран
Сообщений: 770
Репутация: 255 ±
Замечаний: 0% ±

Excel 2013
а так еще чуть проще и чуть быстрее:
[vba]
Код
Sub Категория_товара()
     Dim a&, b(), c&, d(), e(), f As Range, i&
      
     With Worksheets("Группа погрузки")
         a = .Cells(.Rows.Count, 2).End(xlUp).Row
         b = .Range("B2:E" & a).Value
     End With
     With Worksheets("Исходные данные")
         c = .Cells(.Rows.Count, 3).End(xlUp).Row
         d = .Range("C4:D" & c).Value
         Set f = .Range("M4:M" & c)
         e = f
     End With
      
     With CreateObject("Scripting.Dictionary")
         For i = 1 To a - 1
             .Item(b(i, 1) & "|" & b(i, 2)) = b(i, 4)
         Next
         For i = 1 To c - 3
             e(i, 1) = .Item(d(i, 1) & "|" & d(i, 2))
         Next
     End With
     f = e
End Sub
[/vba]


KSV.VBA@gmail.com
Яндекс.Деньги: 410011921213333
 
Ответить
Сообщениеа так еще чуть проще и чуть быстрее:
[vba]
Код
Sub Категория_товара()
     Dim a&, b(), c&, d(), e(), f As Range, i&
      
     With Worksheets("Группа погрузки")
         a = .Cells(.Rows.Count, 2).End(xlUp).Row
         b = .Range("B2:E" & a).Value
     End With
     With Worksheets("Исходные данные")
         c = .Cells(.Rows.Count, 3).End(xlUp).Row
         d = .Range("C4:D" & c).Value
         Set f = .Range("M4:M" & c)
         e = f
     End With
      
     With CreateObject("Scripting.Dictionary")
         For i = 1 To a - 1
             .Item(b(i, 1) & "|" & b(i, 2)) = b(i, 4)
         Next
         For i = 1 To c - 3
             e(i, 1) = .Item(d(i, 1) & "|" & d(i, 2))
         Next
     End With
     f = e
End Sub
[/vba]

Автор - KSV
Дата добавления - 31.03.2015 в 02:38
Hugo Дата: Вторник, 31.03.2015, 08:30 | Сообщение № 11
Группа: Друзья
Ранг: Участник клуба
Сообщений: 3255
Репутация: 707 ±
Замечаний: 0% ±

2019
Можно не проверять на наличие в словаре - но это если не волнуют существующие данные на листе, и тогда нет смысла делать
[vba]
Код
        Set f = .Range("M4:M" & c)
         e = f
[/vba]
Проще создать пустой массив.
Кстати, зачем такой финт? В чём выгода?


excel@nxt.ru
webmoney: E265281470651 Z422237915069
 
Ответить
СообщениеМожно не проверять на наличие в словаре - но это если не волнуют существующие данные на листе, и тогда нет смысла делать
[vba]
Код
        Set f = .Range("M4:M" & c)
         e = f
[/vba]
Проще создать пустой массив.
Кстати, зачем такой финт? В чём выгода?

Автор - Hugo
Дата добавления - 31.03.2015 в 08:30
KSV Дата: Вторник, 31.03.2015, 15:13 | Сообщение № 12
Группа: Друзья
Ранг: Ветеран
Сообщений: 770
Репутация: 255 ±
Замечаний: 0% ±

Excel 2013
это не финт :)
это чтобы один раз получить ссылку на диапазон .Range("M4:M" & c)


KSV.VBA@gmail.com
Яндекс.Деньги: 410011921213333
 
Ответить
Сообщениеэто не финт :)
это чтобы один раз получить ссылку на диапазон .Range("M4:M" & c)

Автор - KSV
Дата добавления - 31.03.2015 в 15:13
RAN Дата: Вторник, 31.03.2015, 15:24 | Сообщение № 13
Группа: Друзья
Ранг: Экселист
Сообщений: 5660
Репутация: 1163 ±
Замечаний: 0% ±

2010
это чтобы один раз получить ссылку на диапазон

Это понятно. Но зачем?


Быть или не быть, вот в чем загвоздка!
 
Ответить
Сообщение
это чтобы один раз получить ссылку на диапазон

Это понятно. Но зачем?

Автор - RAN
Дата добавления - 31.03.2015 в 15:24
KSV Дата: Вторник, 31.03.2015, 18:00 | Сообщение № 14
Группа: Друзья
Ранг: Ветеран
Сообщений: 770
Репутация: 255 ±
Замечаний: 0% ±

Excel 2013
[offtop]как зачем? для удобочитаемости...
чтобы описание диапазона в коде было только в одном месте и, желательно, рядом с описанием других исходных данных (в данном случае - других диапазонов и имен листов книги), тогда, при необходимости переназначения диапазона, не придется "лазить" в поисках по всему коду (особенно, если код большой), и уже точно "не забудешь" переназначить ЭТОТ ЖЕ диапазон где-нибудь в другом месте кода, т.к. других мест просто не будет...
я думаю, что "лишняя" переменная, занимающая 4 байта памяти, это небольшая плата за такое удобство.
а если у этой переменной еще и осмысленное имя, то еще и код будет понятнее (более удобочитаемый)...


KSV.VBA@gmail.com
Яндекс.Деньги: 410011921213333
 
Ответить
Сообщение[offtop]как зачем? для удобочитаемости...
чтобы описание диапазона в коде было только в одном месте и, желательно, рядом с описанием других исходных данных (в данном случае - других диапазонов и имен листов книги), тогда, при необходимости переназначения диапазона, не придется "лазить" в поисках по всему коду (особенно, если код большой), и уже точно "не забудешь" переназначить ЭТОТ ЖЕ диапазон где-нибудь в другом месте кода, т.к. других мест просто не будет...
я думаю, что "лишняя" переменная, занимающая 4 байта памяти, это небольшая плата за такое удобство.
а если у этой переменной еще и осмысленное имя, то еще и код будет понятнее (более удобочитаемый)...

Автор - KSV
Дата добавления - 31.03.2015 в 18:00
RAN Дата: Вторник, 31.03.2015, 19:29 | Сообщение № 15
Группа: Друзья
Ранг: Экселист
Сообщений: 5660
Репутация: 1163 ±
Замечаний: 0% ±

2010
[offtop]
особенно, если код большой

и этот диапазон встречается многажды, тут вопросов нет. :D [/offtop]


Быть или не быть, вот в чем загвоздка!

Сообщение отредактировал RAN - Вторник, 31.03.2015, 19:31
 
Ответить
Сообщение[offtop]
особенно, если код большой

и этот диапазон встречается многажды, тут вопросов нет. :D [/offtop]

Автор - RAN
Дата добавления - 31.03.2015 в 19:29
Мир MS Excel » Вопросы и решения » Вопросы по VBA » Поиск значения по двум параметрам (Макросы/Sub)
  • Страница 1 из 1
  • 1
Поиск:

Яндекс.Метрика Яндекс цитирования
© 2010-2024 · Дизайн: MichaelCH · Хостинг от uCoz · При использовании материалов сайта, ссылка на www.excelworld.ru обязательна!