ADO: Excel: можно ли открыть набор записей по имени таблицы?
Я посмотрел в Интернете, но не нашел ответа. Так что я помещаю это здесь.
Фрагмент кода: (где случай 1 не работает..)
_bstr_t strCnn(L"Provider='Microsoft.ACE.OLEDB.12.0';DataSource=C:\\Book.xlsx;Extended Properties=\"Excel 12.0 Xml; HDR = YES\"");
hr = pConn->Open(strCnn, "", "", adConnectUnspecified); // success
**LPCSTR strQuery = "select * FROM Table1"; // case1: Not working**
LPCSTR strQuery = "select * FROM [Sheet1$]"; // case2: working
LPCSTR strQuery = "select * FROM [Sheet1$A1:D10]"; // case3: working
hr = pRst->Open(CComVariant(strQuery), _variant_t((IDispatch *)pConn, true),
adOpenStatic, adLockOptimistic,adCmdText); // fails for case 1
Это возможно в Excel? или что-то не так в приведенном выше коде.
ПРИМЕЧАНИЕ: я пробовал это с Microsoft Access, и привязка набора записей к имени таблицы там работает нормально.
1 ответ
Краткая версия:
"Таблица", вставленная в электронную таблицу Excel, не отображается как таблица в SQL.
Вам нужен именованный диапазон, или именованный рабочий лист, или полный адрес диапазона данных и заголовков таблицы; и кажущееся существование именованного диапазона, связанного с таблицей Excel, вводит в заблуждение.
Я думаю, что это требует некоторого объяснения, начиная с:
Что именно это "Таблица1"?
Это не именованный диапазон, это не лист, и он не может быть преобразован в объект диапазона Excel с помощью SQL. Напомним, что:
- Если вы создали именованный диапазон, глобально видимый в книге, и назвали его "Таблица1", он будет виден вашему запросу SQL как Таблица1.
- Если вы переименовали лист в "Table1", он будет виден вашему запросу SQL как Table1 $.
- Если вы создали именованный диапазон, локальный для области листа с именем "Sheet1", и назвали его "Table1", он будет виден вашему SQL как Sheet1 $ Table1.
"Таблица" в Excel не относится к таким вещам, поэтому она не отображается в виде таблицы для механизма базы данных.
Да, он отображается в диалоговом окне "Диспетчер имен" для именованных диапазонов, но "Таблица1" не является ни именем именованного диапазона, ни рабочей таблицы, ни при этом он не указывает диапазон с адресом, распознаваемым в SQL: быть одной из этих трех вещей, чтобы быть видимыми в виде таблицы базы данных для драйверов баз данных OLEDB и ODBC, доступных для Excel.
Объект, который вы создали как "Table1", является объектом ListObject, и вы можете запросить его в окне отладки IDE Excel VBA следующим образом:
Thisworkbook.Worksheets("Sheet1").ListObjects("Table1").Name
Так что вам нужен адрес диапазона ListObject, и это просто вопрос...
На самом деле, это совсем не просто.
... ListObject имеет DataBodyRange
свойство, которое охватывает строки данных под заголовком; и HeaderRowRange
что относится к заголовкам. Оба, будучи диапазонами, имеют адрес; и вам нужно UNION
чтобы получить один адрес, который ваш SQL может прочитать как именованную таблицу.
Или использовать Sheet1.ListObjects("Table1").Sort.Rng.address
потому что каждый ListObject имеет Sort
свойство объекта, независимо от того, отсортировано оно или нет; и Rng
Свойство - это весь диапазон, с явным пренебрежением к согласованным именам объектов и без намеков на сортировку адреса столбца или столбца.
... И эта информация бесполезна для вашего вопроса и вашего кода: вы ничего не можете вставить в SQL-запрос, который будет анализировать объект "Таблица" как допустимую таблицу.
Вы должны извлечь и проанализировать адрес полного диапазона 'table', прежде чем запускать SQL. Драйверы ADO и ODBC Excel будут работать с непрерывным диапазоном адресов в форме " SheetName$A1:Z1024 ", но у них нет возможности извлечь этот адрес из родительской рабочей книги объекта "Таблица" в Excel.
Извиняюсь за неутешительный ответ.
Кстати, вы знаете, что запрос Excel с любым из доступных драйверов ODBC и OLEDB SQL приводит к утечке памяти? По крайней мере, так будет, если вы сделаете это из VBA: я бы посоветовал вам не запускать это повторно, если вы не запустите Purify или аналогичный инструмент в своем коде и не изолируете проблему.