1

Тема: VBS: SQL запрос к листу Excel

Коллеги, приветствую !
Знаю что можно сделать SQL запрос к Листу Excel, но все примеры сделаны на основе ADO, а мне надо - используя DAO, выдаёт синтаксическую ошибку, может кто встречался с подобным, что делаю не так...

Set Engine = CreateObject("DAO.DBEngine.36")
Set mdb = Engine.OpenDatabase("c:\util\base.xls")
Set rset=mdb.OpenRecordset("select * from Лист1$")
msgbox rset.fields(0)
Времени не хватает... :-(

2 (изменено: Евген, 2013-01-25 09:43:48)

Re: VBS: SQL запрос к листу Excel

Гы-ы-ы-ы....   вообщем сам тупанул (но видать вместе с компиком)
Дело в том, что вчера я запускал оное на Win7 x64, а чот видать из памяти выбило, что на такой винде нет объекта DAO, но что примечательно - винда вчера не ругалась (что невозможно создать такой объект), а вот сегодня - на неё нашло просветление и она мне подсказала
Ну и после оного поднял виртуал с хрюшкой, и дозаточил щас робит...

Set Engine = CreateObject("DAO.DBEngine.36")
Set mdb = Engine.OpenDatabase("c:\util\base.xls",True,False,"Excel 8.0")

' выводит имеющиеся имена таблиц
for each td in mdb.tabledefs
msgbox td.name
next


Set rs=mdb.OpenRecordset("1$")
msgbox rs.fields(0)

Ах да, ещё вот какая грабля оказалась,

rset

- видать какое-то зарезервированное слово (я его хотел использовать в качестве сокращения для Recordset), его нельзя использовать в качестве переменной, но я почему-то опять был не в курсе...
видать длительный простой незамедлительно сказывается...

Времени не хватает... :-(

3 (изменено: Евген, 2013-02-05 09:35:31)

Re: VBS: SQL запрос к листу Excel

Чтобы окончательно раскрыть тему, доведу дело до реального запроса...

Set Engine = CreateObject("DAO.DBEngine.36")
Set mdb = Engine.OpenDatabase("c:\util\base.xls", True, False, "Excel 8.0")

tn = mdb.TableDefs(0).Name                   ' название листа (таблицы)
fn = mdb.TableDefs(0).fields(2).Name         ' название поля (колонки)
dn = mdb.TableDefs(0).fields(3).Name        ' название поля (колонки)

Set rs = mdb.OpenRecordset("select * from [" & tn & "] where [" & fn & "]='C002' and [" & dn & "] like '*10.01.2013*'")
rs.movelast
MsgBox rs.RecordCount

Это запросец к выгрузке базы из СЭО АКИС

Времени не хватает... :-(

4 (изменено: Flasher, 2013-05-04 09:44:30)

Re: VBS: SQL запрос к листу Excel

Господа, а то же самое (название листа/колонки) с помощью ADO можно получить?
Add: С листом

+ разобрался
Set Conn = CreateObject("ADODB.Connection")
Conn.Open "..."
Set Catalog = CreateObject("ADOX.Catalog")
Set Catalog.ActiveConnection = Conn
WScript.Echo Catalog.Tables(<№ листа>).Name

С колонками не очень.
Первую получаю, допустим, так: .Execute("SELECT * FROM [чего-то там]").Fields(0).Name, а дальше?
Запись Catalog.Tables(<№ листа>).Columns(<№ колонки>) выдаёт сумятицу..

Также интересует получение заголовков табуляторов в соответствии со стилем ссылок (A1/R1C1).
Это возможно?

Ещё: у ADO (Recordset/Execute) есть метод GetString, а тут я не увидел. Имеется подобное в DAO?
И если в ADO я выделяю диапазон всего столбца (D:D, например), то GetString возвращает несколько лишних разделителей (возврат каретки по умолчанию) на конце списка. Причина этого в чём?

5

Re: VBS: SQL запрос к листу Excel

А чем Вам не ADO выше:

tn = mdb.TableDefs(0).Name ' название листа (таблицы)

Про остальное мне что-то вовсе не понятно.

6 (изменено: Flasher, 2013-05-04 14:18:30)

Re: VBS: SQL запрос к листу Excel

alexii
Это DAO. Про лист дописал.

alexii пишет:

Про остальное мне что-то вовсе не понятно.

Детальней напишите, пож-та, постараюсь разжевать.

7

Re: VBS: SQL запрос к листу Excel

Никто не ответит?
BeS Yara, может, Вы знаете?
Интересует прежде всего название колонки (без задания диапазона в Execute; если нельзя, то в заданном) и стиль ссылок для заголовков.

8

Re: VBS: SQL запрос к листу Excel

Flasher пишет:

Никто не ответит?
BeS Yara, может, Вы знаете?
Интересует прежде всего название колонки (без задания диапазона в Execute; если нельзя, то в заданном) и стиль ссылок для заголовков.

В ADO для использования названия колонок из первой строки нужно было в connection string это указывать(HDR=YES). В DAO ситуация аналогичная - ADO Connection Strings. Ну и для запроса без диапазона нужно было указывать лист а не диапазон. Как с этим обстоит дело в DAO сказать затрудняюсь(никогда с DAO не работал), но скорее всего ситуация аналогична ADO. Попробуйте посмотреть этот пример: Use a closed workbook as a database (DAO).

P.S. Майкрософт  рекомендует отказаться от использования DAO :

Майкрософт рекомендует для новых проектов использовать OLE DB или ODBC. DAO следует использовать только для обслуживания существующих приложений.

9

Re: VBS: SQL запрос к листу Excel

Спасибо за подключение!

BeS Yara пишет:

В ADO для использования названия колонок из первой строки нужно было в connection string это указывать(HDR=YES). В DAO ситуация аналогичная - ADO Connection Strings.

Добавил, пишет:

Ошибка: Невозможно найти устанавливаемый ISAM.
Код: 80004005
Источник: Microsoft JET Database Engine

BeS Yara пишет:

Ну и для запроса без диапазона нужно было указывать лист а не диапазон. Как с этим обстоит дело в DAO сказать затрудняюсь(никогда с DAO не работал), но скорее всего ситуация аналогична ADO.

Что указывать после FROM понятно. А как из диапазона листа получить правильное название заголовка нужного столбца по индексу? Я выше привёл пример, но он выдаёт некорректные результаты.
И что по заголовкам табуляторов (№/A-Z), как их получить по индексу?

BeS Yara пишет:

Попробуйте посмотреть этот пример: Use a closed workbook as a database (DAO).

Спасибо, ознакомлюсь.

10

Re: VBS: SQL запрос к листу Excel

Flasher, я не уверен что верно понял задачу.
Нужно делать выборку по имени колонки? Или нужно делать вывод по имени колонки?

Сделал таблицу в три столбца, в первой строке листа - названия колонок: user, Tel, Net.
В коде выбираем строки для которых число телефонных розеток равно 3:


Option Explicit

Dim oDAO, oDB
Set oDAO = CreateObject("DAO.DBEngine.36")
Set oDB = oDAO.OpenDatabase("tab1.xls", False, True, "Excel 8.0;HDR=Yes;")

Dim strSQL, oRS
strSQL = "SELECT * FROM [Лист1$] WHERE Tel = 3"
Set oRS = oDB.OpenRecordset(strSQL)

Do While Not oRS.EOF
   wscript.echo "Группа пользователей: " & oRs("user")
   wscript.echo "Кол-во телефонных розеток: " & oRs("Tel")
   wscript.echo "Кол-во езернет-розеток: " & oRs("Net")
   oRS.MoveNext
Loop

oRS.Close
oDB.Close
Set oRS = Nothing
Set oDB = Nothing
Set oDAO = Nothing

Это для случая когда названия колонок в первой строке листа, для диапазонов листа не пробовал.

По поводу получения адресов ячеек в стиле экселя - сильно сомневаюсь в такой возможности из коробки. Всё таки DAO предназначено для работы с БД, а там номера строки в экселевском представлении нет. Хотя, если не делать выборку, и не использовать сортировку - при переборе никто не мешает посчитать номер строки для конкретного набора данных. Но нужно быть на 100% уверенным, что DAO прочтёт строки именно в том порядке который имеется в листе. Это было бы логично, но я не уверен что всё именно так и есть . Номер колонки(для стиля R1C1) можно получить из свойств поля - oRs("user").OrdinalPosition + 1(нумерация полей в рекордсете от 0 идёт). Другие св-ва рекордсета можно посмотреть в студийном отладчике(я пользуюсь 2008-ой студией для таких случаев).

По ошибке - MDAC установлен? Какой именно код вызывает ошибку?

P.S. кажется я был немного невнимателен - тема плавно с DAO на ADO(а я всё про DAO, да про DAO )... Собственно по какому объекту сейчас обсуждение идёт?

11 (изменено: Flasher, 2013-05-07 16:19:31)

Re: VBS: SQL запрос к листу Excel

BeS Yara пишет:

Flasher, я не уверен что верно понял задачу.
Нужно делать выборку по имени колонки? Или нужно делать вывод по имени колонки?

Ни то, ни другое. По имени - проблем нет. Нужно по индексу (номер колонки - 1) узнавать имя колонки.

BeS Yara пишет:

Это для случая когда названия колонок в первой строке листа, для диапазонов листа не пробовал.

Это я могу получать только при задании диапазона колонки. В первом посте пример. Но мне не хочется для каждой колонки вызывать Execute, я хочу получать либо до вызова метода, либо после задания диапазона всего листа.

BeS Yara пишет:

Номер колонки(для стиля R1C1) можно получить из свойств поля - oRs("user").OrdinalPosition + 1(нумерация полей в рекордсете от 0 идёт). Другие св-ва рекордсета можно посмотреть в студийном отладчике(я пользуюсь 2008-ой студией для таких случаев).

Объясню конкретней. Я не хочу получить ошибку, если в Execute буду задавать диапазон, не соответствующий текущему стилю. Поэтому мне надо предварительно выяснить заголовок табулятора, чтобы правильно задать его через Select.
Свойства смотрел через VbsEdit.


BeS Yara пишет:

По ошибке - MDAC установлен? Какой именно код вызывает ошибку?

+ Такой:
File = "C:\file.xls"
CreateObject("ADODB.Connection").Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & File & ";Extended Properties=Excel 8.0;HDR=Yes;"
BeS Yara пишет:

Собственно по какому объекту сейчас обсуждение идёт?

Сейчас ADO приоритетней, т.к. в DAO не вижу, как уже писал выше, аналога GetString (кстати, что по нему?). DAO обсуждаем как альтернативу.

12

Re: VBS: SQL запрос к листу Excel

Flasher пишет:

Это я могу получать только при задании диапазона колонки. В первом посте пример. Но мне не хочется для каждой колонки вызывать Execute, я хочу получать либо до вызова метода, либо после задания диапазона всего листа.

Зачем вызывать Execute для получения каждой колонки? По первому запросу мы получаем таблицу(recordset), в нём уже имеется вся информация по числу колонок, по их номерам, по их именам(если HDR=YES). В моём примере запрос запускался один раз. Может я не тот пример смотрю?

Flasher пишет:

Объясню конкретней. Я не хочу получить ошибку, если в Execute буду задавать диапазон, не соответствующий текущему стилю. Поэтому мне надо предварительно выяснить заголовок табулятора, чтобы правильно задать его через Select.

Выяснить стиль ссылок точно можно прочитав экселевский файл(свойство ReferenceStyle объекта Workbook.Application; xlR1C1 = -4150, xlA1 = 1). Правда понадобится установленный Excel. Можно ли проверить это свойство силами ADO или DAO сказать не берусь(пока).

По работе с диапазонами сейчас ничего сказать не могу, так как с данной спецификой не сталкивался(в моих задачах всегда требовалось обрабатывать весь лист). Если выдастся время - попробую, тогда может быть что-то смогу подсказать по поводу имён колонок для диапазонов и определения стиля ссылок без использования  Excel.Application.

Flasher пишет:

Такой:

File = "C:\file.xls"
CreateObject("ADODB.Connection").Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & File & ";Extended Properties=Excel 8.0;HDR=Yes;"

Excel 8.0;HDR=Yes; - это одно строковое значение для свойства Extended Properties. А так как она содержит символ ";", являщийся разделителем, она должна быть заключена в кавычки(экранированые). Правильно будет примерно так:

File = "C:\file.xls"
CreateObject("ADODB.Connection").Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & File & ";Extended Properties=""Excel 8.0;HDR=Yes;"""

Почитал внимательнее приведённую мной же ссылку, оказалось что HDR=YES значение по умолчанию

С книгами Excel первая строка диапазона считается строку заголовка (или имена полей) по умолчанию. Если первый диапазон не содержит заголовков, можно указать HDR=NO в расширенных свойств в строке соединения. Если первая строка содержит заголовки, поставщик OLE DB автоматически имена полей автоматически (где F1 будет представлять первому полю, F2 бы представляют второе поле и так далее).

Надо будет всё таки потестировать разные варианты(включая именованные диапазоны и задаваемые вручную). Так, для собственного развития...

13

Re: VBS: SQL запрос к листу Excel

BeS Yara пишет:

Зачем вызывать Execute для получения каждой колонки?

Чтобы получить заголовок по .Fields(0).Name.

BeS Yara пишет:

В моём примере запрос запускался один раз. Может я не тот пример смотрю?

А какой пример? Где по номеру имя получаем?

BeS Yara пишет:

Правда понадобится установленный Excel. Можно ли проверить это свойство силами ADO или DAO сказать не берусь(пока).

Естественно, нужно без Exel.

BeS Yara пишет:

По работе с диапазонами сейчас ничего сказать не могу, так как с данной спецификой не сталкивался(в моих задачах всегда требовалось обрабатывать весь лист). Если выдастся время - попробую, тогда может быть что-то смогу подсказать по поводу имён колонок для диапазонов и определения стиля ссылок без использования  Excel.Application.

Меня по листу также интересует (писал выше).

BeS Yara пишет:

Правильно будет примерно так:

Понял.

BeS Yara пишет:

поставщик OLE DB автоматически имена полей автоматически (где F1 будет представлять первому полю, F2 бы представляют второе поле и так далее).

Не понял..

14

Re: VBS: SQL запрос к листу Excel

Flasher пишет:
BeS Yara пишет:

Зачем вызывать Execute для получения каждой колонки?

Чтобы получить заголовок по .Fields(0).Name.

Всё равно не понимаю - получили рекордсет, дальше вытаскиваем из него всё что нужно, включая имена колонок:


option explicit
Const adUseClient = 3 : Const adOpenStatic = 3 : Const adLockOptimistic = 3 : Const adCmdText = &H1
Const adSchemaTables = 20 : Const adSchemaColumns = 4
Dim FileSource
FileSource = "tab1.XLS"

Dim oConn
Set oConn = CreateObject("ADODB.Connection")
Dim oRS
Set oRS = CreateObject("ADODB.Recordset")
With oConn
    .Provider = "Microsoft.Jet.OLEDB.4.0"
    .ConnectionString = "Data Source=" & FileSource & ";Extended Properties=""Excel 8.0;HDR=Yes;"""
    .CursorLocation = adUseClient
    .Open
End With

Dim strSQL
strSQL = "SELECT * FROM [Лист1$] WHERE Tel = 3"
Set oRS = oConn.Execute(strSQL)

wscript.echo "колонка №1: " & oRS.Fields(0).Name
wscript.echo "колонка №2: " & oRS.Fields(1).Name
wscript.echo "колонка №3: " & oRS.Fields(2).Name

oRS.Close
oConn.Close
Set oRS = Nothing
Set oConn = Nothing
Flasher пишет:

А какой пример? Где по номеру имя получаем?

Проблема №1: приведите, пожалуйста полный код - поо проскальзывающим кускам сложно понять что требуется.
Проблема №2: опишите чего нужно достичь на прикладном уровне - например на примере конкретного xls-файла(с образцом данных).

Flasher пишет:

Не понял.

При открытии экселевского файла OLE DB пытается определить тип данных в колонках, анализируя первые 8(по умолчанию) строк. Подозреваю что речь о том, что если все 8 строк имеют одинаковый тип данных, OLE DB будет рассматривать это как отсутствие шапки у таблицы, и сам назначит колонкам имена(F1, F1 etc).

P.S. Зачем прятать код ещё и под спойлер(с непривычки даже не сразу понял что там код где-то в сообщении спрятан)? С "обрезкой" простыни успешно справляется тег code.

15

Re: VBS: SQL запрос к листу Excel

BeS Yara пишет:

Всё равно не понимаю - получили рекордсет, дальше вытаскиваем из него всё что нужно, включая имена колонок:

Просто у меня на некоторых xls даже при наличии в первых строках текста вмеcто содержимого выдаёт F1, F2...

BeS Yara пишет:

приведите, пожалуйста полный код - поо проскальзывающим кускам сложно понять что требуется.

Да, собственно, это для разных скриптов нужно. Ваш последний пример как частный случай подходит.

BeS Yara пишет:

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

Нужно по номеру листа,  табулятора, столбца, строки в правильно указанном диапазоне любого параметрически заданного файла получать/записывать/обрабатывать нужные данные полей.

BeS Yara пишет:

Подозреваю что речь о ...

Уже заметил. Ещё перепроверю файлы.

Найти бы определение стиля..