Для работы с Excel 2003 (.Xls) можно использовать провайдер Microsoft Jet OLE DB 4.0.
SELECT * FROM OPENROWSET(
'Microsoft.Jet.OLEDB.4.0',
'Excel 12.0;Database=d:\tmp\TimeSheets.xlsx;HDR=YES;IMEX=1',
'SELECT * FROM [Sheet1$]');
Для работы с Excel 2007 (.Xlsx) - Microsoft ACE OLEDB 12.0.
SELECT * FROM OPENROWSET (
'Microsoft.ACE.OLEDB.12.0',
'Excel 12.0;Database=d:\tmp\TimeSheets.xlsx;HDR=YES;IMEX=1',
'SELECT * FROM [Sheet1$]');
В Windows 10 открыть настройки источников данных ODBC можно написав "Источники данных ODBC" или через Панель управления \ Администрирование.
HDR=YES|NO
. HDR=YES означает, что первую строку листа, следует рассматривать как заголовки колонок. Т.о. значение из первой строки можно использовать как имена полей в sql запросах (любых: select, insert, update, delete).IMEX=1|3
. 1 - открыть соединение для чтения. 3 - для записи.
EXEC sp_addLinkedServer
@server= N'XLSX_2010',
@srvproduct = N'Excel',
@provider = N'Microsoft.ACE.OLEDB.12.0',
@datasrc = N'd:\tmp\TimeSheets.xlsx',
@provstr = N'Excel 12.0; HDR=Yes';
GO
После создания связанного сервера можно будет просмотреть имена доступных листов.
Затем, чтобы обратиться к сервису:
SELECT * FROM OPENQUERY (XLSX_2010, 'Select * from [Sheet1$]')
или
SELECT * FROM [XLSX_2010]...[Лист1$]
Для обращения к листу из SQL запроса нужно использовать имя листа, например: [Sheet1$]
или [Лист1$]
. Обращение к диапазону: [Sheet1$A16:F16]
.
Примеры указания диапазона при вставке строк (insert
)
- [table1$B4:E20]
- [table1$S4:U]
- [table1$F:G]
При вставке должны выполняться следующие условия:
- Первая строчка указанного диапазона дожна входить в диапазон ячеек с данными. Чтобы создать на листе диапазон с данными достаточно в углах некоторого прямоугольного диапазона (в левом верхнем и правом нижнем) вписать значение (C4:I7 на скриншоте). Т.е. сама первая строчка указанного в
insert
диапазона данные содержать не обязана, достаточно, чтобы она просто входила в такой диапазон. Иначе возникнет ошибка"This table contains cells that are outside the range of cells defined in this spreadsheet"
- Хвост диапазона должен содержать пустые строки (хотя бы одну).
Пример: Дан лист, где заполнены только 2 ячейки: C4, I7. После выполнения команды INSERT INTO [table1$E6:G] VALUES(2, 'FF','2014-01-03')
результат будет как на скриншоте. Поясним: строка E6:G6 является первой строкой диапазона для вставки. Она входит в заполненный диапазон C4:I7. Поэтому данные были вставлены на следующей пустой строке - 8. Из этого примера становится ясно, что через OleDb нельзя работать с несколькими независимыми диапазонами на одном листе, используя вставку (update
будет работать).
System.Data.OleDb.OleDbException (0x80004005): Operation must use an updateable query
. Соединение открыто для чтение, при этом происходит попытка внести изменения (выполнить insert, update или delete). Решение: открыть соединение для записи, установив свойство провайдера в строке соединения IMEX=3 (см. выше).System.Data.OleDb.OleDbException (0x80004005): "This table contains cells that are outside the range of cells defined in this spreadsheet"
. Такая ошибка возникает при подпытке обновить (update
) или вставить (insert
) значения в диапазоне, в котором отсутствуют данные на листе.- Если нужно произвести запись в определенные ячейки инструкцией update, то
- https://www.codeproject.com/Tips/705470/Read-and-Write-Excel-Documents-Using-OLEDB
- https://stackoverflow.com/questions/36987636/cannot-create-an-instance-of-ole-db-provider-microsoft-jet-oledb-4-0-for-linked
- https://stackoverflow.com/questions/26267224/the-ole-db-provider-microsoft-ace-oledb-12-0-for-linked-server-null
- http://www.ashishblog.com/importexport-excel-xlsx-or-xls-file-into-sql-server/
- https://yoursandmyideas.com/2011/02/05/how-to-read-or-write-excel-file-using-ace-oledb-data-provider/
- https://stackoverflow.com/questions/46373895/how-to-open-a-huge-excel-file-efficiently Несколько способов открыть большой Excel файл, в т.ч. с помощью OleDb.
Спасибо за код. Пригодился.
Не подскажите ли мне, как узнать номер строки у ячейки? Мне нужно циклами SQL обойти таблицу, которая начинается с именованной ячейки.
Значение самой ячейки я получаю так
Set rs = objConn.execute("SELECT * FROM CustomerName")
Т.е. в rs записываю значение из ячейки с именем CustomerName.
Но как мне в переменную записать номер строки этой ячейки?