Страницы: 1 2 След.
RSS
VBA - VLOOKUP с обращением к другой книге
 
Добрый день Ув. знатоки =)  
Проблема след. характера.  
Имеется база в 1 файле, рабочая книга в другом.    
Необходимо средствами VBA сделать тоже самое как показано в примере функцией VLOOKUP (ВПР) с обращением к другому файлу.    
 
П.С. Где-то видел пример, как сделано то же самое простым перебором (без обращения к другому файлу), но никак не могу найти (Везде через x=Application.VLookup(arg1, arg2, arg3, arg4)). Реальная база имеет около 2000 строк, перебором не выход?  
 
Спасибо
 
На просторах интернета нашел след. функцию:  
 
Private Function GetValue(path, file, sheet, ref)  
'   Retrieves a value from a closed workbook  
   Dim arg As String  
'   Make sure the file exists  
   If Right(path, 1) <> "\" Then path = path & "\"  
   If Dir(path & file) = "" Then  
       GetValue = "File Not Found"  
       Exit Function  
   End If  
'   Create the argument  
   arg = "'" & path & "[" & file & "]" & sheet & "'!" & _
     Range(ref).Range("A1").Address(, , xlR1C1)  
'   Execute an XLM macro  
   GetValue = ExecuteExcel4Macro(arg)  
End Function  
 
Sub TestGetValue()  
   p = "c:\excel\"  
   f = "DATABASE.xls"  
   s = "DATABASE"  
   a = "A1"  
   MsgBox GetValue(p, f, s, a)  
End Sub  
 
Но, можно как-то под мою задачу переделать ?
 
{quote}{login=metrox}{date=09.12.2012 05:17}{thema=VBA - VLOOKUP с обращением к другой книге}{post}Имеется база в 1 файле, рабочая книга в другом. <...> Где-то видел пример, как сделано то же самое простым перебором (<STRONG>без обращения к другому файлу</STRONG>){/post}{/quote}Перечитайте своё сообщение :-)
 
Все правильно написал =)  
Имел ввиду, что был макрос который мне нужен, но он был без возможности обращаться к стороннему файлу!  
 
Пока что написал подобный макрос, с простым перебором данных (прошу проверить на правильность если можно):  
 
Sub VLOOKUPMY2()  
Dim Table As Range  
Dim Column As Integer  
Dim Value As String  
Dim ResultColumn As Integer  
 
Set Table = Worksheets("DATABASE").Range("A2:K11")  
Column = "1"  
Value = "NAME2"  
ResultColumn = "3"  
 
Dim i%  
   For i = 1 To Table.Rows.Count  
       If Table.Cells(i, Column) = Value Then  
               MsgBox Table.Cells(i, ResultColumn)  
           Exit For  
       End If  
   Next i  
End Sub  
 
Как теперь сделать так, чтобы этот код работал в книге WORKBOOK и брал данные из DATABASE? Пример тот же в первом посте.  
 
Спасибо
 
Если вставить:  
Dim wkbk As Workbook  
Set wkbk = Workbooks.Open("C:\excel\DATABASE.xls")  
То работает, но с открытием файла. Надо бы сделать без - это возможно?  
 
П.С. А вообще вопрос, я тут надоел своими непонятными никому вопросами?  
Вы скажите, не буду надоедать, так сказать =)
 
Конечно непонятными: взять данные из другого файла без обращения к этому файлу.
 
Где я написал такую околесицу?
 
Я уже цитировал. Или я неправильно истолковал?
 
Ладно, тема закрыта.  
Разберусь ;)  
 
P.S. Перефразирую:  
Где-то видел пример, как сделано то же самое простым перебором (но там нет возможности обращаться к другому файлу).
 
Не понимаю... ВПР() ведь работает с закрытыми книгами:  
 
=ВПР(C6;'C:\Temp\metrox\[DATABASE.xls]DATABASE'!$A$2:$K$11;2;0)
 
Прекрасно тянет для всех NAMEn
 
Да, если это нужно сделать средствами VBA - то ответ на поверхности: пишем кодом в ячейку формулу, затем меняем её на полученный ею результат :)
 
Hugo, спасибо, но надо средствами VBA :(  
Поискал в интернете, как-то можно с помощью ADO и т.д.  
_www.exceltip.com/st/Use_a_closed_workbook_as_a_database_(ADO)_using_VBA_in_Microsoft_Excel/432.html  
Буду разбираться.  
 
В ходе дела появилась проблема с работой моего макроса, который писал выше.  
В прикрепленном файле пример.  
Предположим имеется большая таблица с 50 колонками и 2000+ строками. Из этой таблицы надо получить данные для дальнейшей работы с ними.  
Моя реализация проблемы ооочень не рациональная, как я понял в ходе разработки т.к. функция VLOOKUPMY вызывается каждый раз и каждый раз происходит поиск для всех 50 колонок.  
Можно как-то ускорить работу моего скрипта? Например 1 раз сделать поиск, записать это все в массив и потом уже выбирать данные из этого массива?  
Если не понятно объяснил суть проблемы, то спрашивайте.  
Спасибо
 
Не понимаю, почему нельзя использовать VLOOKUP() листа?  
Ну а если делать как у Вас - то можно сразу функцией VBA возвращать массив значений, которые затем перемножать.  
Прописывать в коде не буду - поздно уже. Да и исходные условия нам не известны - например количество параметров постоянно или может меняться?  
И в таком виде у Вас double только Cw, посмотрите в  Locals:  
Dim H, b, Tw, Tf, R1, Cf, Cw As Double
 
Доброе утро,  
Hugo, можно конечно сделать поиск на листе и потом использовать эти данные, но не то что хотельсо бы.  
Или Вы имели ввиду что-то на подобие:  
found = Application.Vlookup(lookFor.Value, rng, col, 0)  
Я не знаю конечно как это скажется на производительности.  
Проблема в том, что мне надо конечно же не только сделать перемножение как в последнем примере, а очень много операций с этими выбранными данными.  
Можно ли как-то одним массивом вывести искомые значения и потом задать каждому переменную или в любом случае для каждой переменной будет производиться поиск ?  
 
П.С. И в таком виде у Вас double только Cw, посмотрите в Locals:  
Dim H, b, Tw, Tf, R1, Cf, Cw As Double  
Почему только Cw? Double в таком виде назначается только для последней переменной если записано в таком виде ?
 
Доброе утро.  
Да, тип нужно указывать для каждой переменной. У Вас все остальные variant - это видно в Locals.  
По задаче - можно ведь сразу взять всю найденную строку (или нужную её часть) в массив, и затем уже его перебирать.  
Так будет всего один поиск, а не на каждый элемент.  
Ещё такой вариант - при открытии файла заполняем публичный словарь значениями, которые собираемся искать, каждому в item номер строки. Затем уже в процессе работы сразу по номеру строки из словаря берём данные, без поиска по листу.  
Если нужно обновить словарь - можно вывести кнопку запуска макроса на лист.  
Хотя на Ваши объёмы это роли не играет, разницы не заметите.  
С кодом сейчас не помогу - понедельник день тяжёлый, за выходные много работы навалило, нужно разгребать...
 
>>Да, тип нужно указывать для каждой переменной. У Вас все остальные variant - это видно в Locals.  
Ого, спасибо.  
>> По задаче - можно ведь сразу взять всю найденную строку (или нужную её часть) в массив, и затем уже его перебирать.  
Да, именно так и надо, но не знаю как это в коде будет. Соглашусь, что понедельник день тяжелы, я могу подождать.  
>>Ещё такой вариант    
Думаю для моей задачи это не сильно актуально, как Вы правильно заметили.  
Спасибо
 
Зачем 2 функции?  
Проще ведь всё делать в одной.  
На лист в ячейку (это если из закрытого файла тянем):  
=ECH(H15,'C:\Temp\[post_384074.xls]Sheet2'!$A$1:$BE$7,3,4,5,6,7)
 
 
Ну а код такой:  
Function ECH(Profile As String, table As Variant, ParamArray NeedColls())  
   Dim i&, el  
   If TypeName(table) = "Range" Then table = Intersect(table.Parent.UsedRange, table).Value  
   For i = 1 To UBound(table)  
       If table(i, 1) = Profile Then  
       ECH = 1  
           For Each el In NeedColls: ECH = ECH * table(i, el): Next  
           Exit For  
       End If  
   Next  
End Function  
 
Intersect для того, чтоб меньше просматривать, если указаны столбцы целиком (в этой книге!).  
При работе с закрытой книгой обязательно указывать конкретный диапазон, "целиком столбцы" не работает!
 
Забыл сказать - у меня ввод диапазона из другой книги через мастер не получался, всё время Эксель выпадал в ошибку и уходил на восстановление.  
Пришлось обмануть - задал диапазон в другой ячейке просто через =нужный_диапазон, закрыл другую книгу, скопировал полученную строку в мастер формулы ECH.
 
Hugo, спасибо за ответ.  
Но наверное я не так объяснил опять, не знаю.  
Расскажу что у меня имеется сейчас.  
Имеется таблица, такого же типа как и в примере. Функциями эксель (Через Vlookup) сделал выбор необходимых данных каждого столабца, в частности выбор необходимой строки. Предположим из примера для IPE 80.  
Потом ссылаясь на этот регион в VBA назначаю для каждого столбца строки переменную, пример:  
incells = Data.Value  
H = incells(1, 1)  
b = incells(1, 2)  
Где H, b и т.д. столбик определенной строки для IPE 80.  
Хотелось сделать назначение переменных H,B и т.д. на прямую без необходимости делать отделный выбор нужной строки.  
Для этого написал функцию:  
Function VLOOKUPMY(Value As String, ResultColumn As Integer)  
Dim i%  
Dim table As range  
Dim column As Integer  
Set table = Worksheets("Profiles").range("C8:BU2000")  
column = "1"  
   For i = 1 To table.Rows.Count  
       If table.Cells(i, column) = Value Then  
               VLOOKUPMY = table.Cells(i, ResultColumn)  
           Exit For  
       End If  
   Next i  
End Function  
 
И думал назначать таким образом:  
H = VLOOKUPMY(Profile, 3)  
b = VLOOKUPMY(Profile, 4)  
 
Но как писал выше - это не рационально т.к. производится поиск для каждой переменной каждый раз.  
Надеюсь понятна моя задача.
 
Я понял.  
Только не понял, почему не сделать всё проще, одной UDF? Или обязательно нужна эта куча переменных? Зачем?  
Мой код неправильно считает? Результаты сходятся.
 
Ув. Hugo, да, необходима потом эта куча переменных. Они используются для дальнейших расчетов всей программы.  
Спасибо
 
Непонятная задача.  
Как Вы собирались из UDF брать эти переменные?  
Ну ладно, может так - после пересчёта формулы жмите кнопку, на лист будет выгружен полученный в  UDF публичный массив. Может использовать его где угодно - присваивайте значения своим переменным (хотя это лишнее), или используйте по индексам.
 
Спасибо что помогаете =)  
Я думал использовать UDF для задания переменных.Мне не обязательна именно UDF, можно и через sub, но главное задать переменные.Не надо даже это все выводить на рабочий лист.  
 
Может так будет проще:  
Предположим надо сделать то же самое, но через sub.  
Переменные:  
Profile="IPE 100", set table=Range("A1:BE7"), как ParamArray задать не знаю.  
 
В виде результата просто вывести сообщение на экран со значениями искомой строки для столбцов B=....,C=....,D=.... и т.д. (конечно не надо делать для всех).  
Если бы это было бы, то я на основе этого смог бы задать для каждого значения свою переменную и использовать их в дальнейших расчетах программы.  
Задача понятна в такой формулировке ?
 
В общем понятно, в деталях нет.  
Столбцы постоянны?  
Это Profile="IPE 100" тоже меняться не будет?  
Если эти значения не постоянные - как их собираетесь вводить?  
Если делать как в примере через UDF - то там в параметрах всё указывается - что, где, сколько каких столбцов. Если делать через sub, то как эти данные вводить, это Вы должны придумать.
 
Эти данные можно просто брать из ячейки.  
Предположим:  
A23 = IPE 100 - этот параметр меняется.  
A24 = A1:BE7 - этот параметр постоянен, его по идеи можно прописать прямо в sub.  
ParamArray - тоже параметр постоянен, количество столбцов не меняется. (В оригинале их 50)
 
Про "другую книгу" пока забыли :)  
Ну например так:  
 
Sub test()  
Dim a(), NeedColls, Profile$, i&, ii&, el  
a = [a1:be7].Value
Profile = [h15].Value
NeedColls = Array(4, 5, 6, 7, 9)  
 
   For i = 1 To UBound(a)  
       If a(i, 1) = Profile Then  
           ReDim workarr(1 To 1, 1 To UBound(NeedColls) + 1)  
           For Each el In NeedColls  
           ii = ii + 1  
           workarr(1, ii) = a(i, el)  
           Next  
           Exit For  
       End If  
   Next  
 
[a20].Resize(1, UBound(workarr, 2)) = workarr
End Sub  
 
Массив номеров столбцов можно заменить на цикл от-до, тогда и выходной массив можно объявить уже заранее известного размера.  
Если нужны переменные - перебрали массив workarr и присвоили им значения.  
 
Ну а обращение к другой книге можно дописать позже - открыли, взяли данные в a(), закрыли.
 
Hugo, спасибо, то что надо =)))  
ПРо другую книгу я уже как-то перестал и надеиться :D  
Набросал как сам вижу, но не работает что-то:  
 
Option Explicit  
Dim workarr  
 
Sub test()  
Dim wkbk As Workbook  
Dim a(), NeedColls, Profile$, i&, ii&, el  
 
Application.ScreenUpdating = False  
Set wkbk = Workbooks.Open("C:\excel\DATABASE.xls")  
Set a = wkbk.Worksheets("DATABASE").Range("A2:BE7")  
 
Profile = "IPE 100"  
NeedColls = Array(4, 5, 6, 7, 9)  
 
For i = 1 To UBound(a)  
If a(i, 1) = Profile Then  
ReDim workarr(1 To 1, 1 To UBound(NeedColls) + 1)  
For Each el In NeedColls  
ii = ii + 1  
workarr(1, ii) = a(i, el)  
Next  
Exit For  
wkbk.Close False  
End If  
Next  
ActiveWindow.DisplayZeros = False  
''[a20].Resize(1, UBound(workarr, 2)) = workarr
MsgBox workarr(1, 1)  
End Sub
 
Пример в приложении
 
Почти, совсем немного ошиблись:  
 
Sub test()  
 
   Dim a(), NeedColls, Profile$, i&, ii&, el  
 
   Application.ScreenUpdating = False  
   With Workbooks.Open("c:\Temp\metrox\DATABASE.xls")  
       a = .Worksheets("Sheet2").Range("A2:BE7").Value  
       .Close 0  
   End With  
 
   Profile = "IPE 100"  
   NeedColls = Array(4, 5, 6, 7, 9)  
 
   For i = 1 To UBound(a)  
       If a(i, 1) = Profile Then  
           ReDim workarr(1 To 1, 1 To UBound(NeedColls) + 1)  
           For Each el In NeedColls  
               ii = ii + 1  
               workarr(1, ii) = a(i, el)  
           Next  
           Exit For  
       End If  
   Next  
   ActiveWindow.DisplayZeros = False  
 
   ''[a20].Resize(1, UBound(workarr, 2)) = workarr
   MsgBox workarr(1, 1)  
 
End Sub
 
Во, спасибо ;)  
Попробую "запилить" в свой рабочий файл.
Страницы: 1 2 След.
Читают тему
Наверх