Sql vba запрос: SQL запрос из Excel VBA
Содержание
SQL запрос из Excel VBA
ВВЕРХ
SQL расшифровывается как Structured Query Language (структурированный язык запросов) и является языком, который используется для получения информации из баз данных (таких как Access , SQL Server from Microsoft , Oracle , Sybase , SAP и других). Вы также можете получать данные из интернета, текстовых файлов или других Excel или CSV файлов.
Итак, нам нужно соединение с базой данных (переменная varConn в макросе ниже) и SQL запрос (переменная varSQL ), чтобы автоматизировать получение данных из базы для отчета. В примере ниже есть SQL запрос , который получает данные с малой базы данных в Access.
Нажмите скачать базу данных Access . Для корректного соединения база данных должна быть в папке «Мои документы«. Файл Access будет выглядеть:
Давайте напишем свой макрос, который будет осуществлять SQL запрос .
Меню Сервис — Макрос — Редактор Visual Basic , вставьте новый модуль (меню Insert — Module ) и скопируйте туда текст макроса:
Sub SQLQuery_1() Dim varConn As String Dim varSQL As String Range("A1").CurrentRegion.ClearContents varConn = "ODBC;DBQ=test.mdb;Driver={Driver do Microsoft Access (*.mdb)}" varSQL = "SELECT Month, Product, City FROM Sumproduct" With ActiveSheet.QueryTables.Add(Connection:=varConn, Destination:=Range("A1")) .CommandText = varSQL .Name = "Query-39008" .Refresh BackgroundQuery:=False End With End Sub
Нажимаем сохранить и возвращаемся к Excel . Выбираем в меню Вид — Макросы (Alt + F8) название нашего макроса « SQLQuery_1 «.
Теперь видим, что наш макрос-запрос подтянул колонки Month , Product и City из таблицы Sumproduct из базы данных test.mdb в файл Excel.
Аналогично мы можем получать данные из обычного файла Excel, как из базы данных. Для этого код нашего макроса нужно немного переписать и изменить драйвер подключения с Access на Excel.
Экспортируем таблицу Sumproduct из Access в Excel и сохраняем файл. Далее, вставляем наш измененный код в новый модуль и запускаем макрос:
Sub SQLQuery_1() Dim varConn As String Dim varSQL As String Range("A1").CurrentRegion.ClearContents varConn = "ODBC;Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)}" varSQL = "SELECT Month, Product, City FROM Sumproduct" With ActiveSheet. QueryTables.Add(Connection:=varConn, Destination:=Range("A1")) .CommandText = varSQL .Refresh BackgroundQuery:=False End With End Sub
Появится окно, в котором мы можем выбрать наш файл Excel (должно называться Sumproduct.xlsx или другим расширением).
Находим и выбираем его. Жмем ОК, и получаем те же данные, что и из файла Access.
Статьи по теме:
Импорт данных с Access в Excel
Используйте функции Excel и VBA в MDX-запросах
Самородов Федор Анатольевич: Используйте функции Excel и VBA в MDX-запросах
А вы знаете, что из MDX-запроса можно вызывать экселевские (и ВБА) функции? Да, это то самое чувство, когда вы легко можете добиться желаемого результата в Экселе, а вот в MDX…
Попробуйте обратиться к внешним функциям через префикс Excel! или VBA!. Вот так:
Студия подчёркивает вызов функции Format красным — это ошибка? Ведь такой функции нет в языке MDX! Верно, нет. Но зато она есть в VBA.
Обращаться к функциям VBA можно либо через приставку «VBA!», либо через «VBAMDX.», а можно и вообще без префикса:
А ещё вы можете аналогичным образом задействовать функции Excel. Вот так:
Однако, прежде чем использовать такой «ход конём», примите во внимание три вещи.
Во-первых, вам доступны не все функции, а только те, использование которых в контексте MDX-запроса не противоречит здравому смыслу. Из всего богатства ВБА можете использовать вот эти девяносто функций:
|
|
|
|
|
|
Во-вторых, учтите, что если вам понадобятся функции из Экселя, то вам придётся установить сам эксель на машину с аналитическим сервером (следите за совпадением битности). И, кстати, экселевские функции также доступны далеко не все.
И в-третьих, не ждите от этого механизма высокой производительности. Если требуется высокомасштабируемое решение, то применять функции VBA и Excel следует с осторожностью.
Подробнее об этом вы сможете узнать на курсе: М50578A: Язык запросов MDX для аналитических служб SQL Server (OLAP)
sql server — Использование Excel VBA для запуска SQL-запроса
Задавать вопрос
спросил
Изменено
3 года, 4 месяца назад
Просмотрено
291 тысяч раз
Я новичок в SQL и VBA. Я написал SQL-запрос, который я хотел бы вызывать и запускать из подпрограммы VBA в книге Excel, а затем переносить результаты запроса в книгу. Я нашел некоторые подпрограммы в Интернете (stackoverflow и другие места), которые утверждают, что делают это, но у меня возникли проблемы с их пониманием, поскольку они не содержат объяснений. Например, вот саб, который я нашел в Интернете:
Sub ConnectSqlServer() Dim conn As ADODB.Connection Dim rs As ADODB.Recordset Dim sConnString как строка ' Создайте строку подключения. sConnString = "Provider=SQLOLEDB;Источник данных=INSTANCE\SQLEXPRESS;" & _ "Исходный каталог=MyDatabaseName;" & _ "Интегрированная безопасность=SSPI;" ' Создайте объекты Connection и Recordset. Установить conn = новый ADODB.Connection Установить rs = новый ADODB.Recordset 'Открываем соединение и выполняем. conn.Open sConnString Установите rs = conn.Execute("SELECT * FROM Table1;") 'Проверьте, у нас есть данные. Если Не rs.EOF Тогда ' Результат передачи. Листы(1).Range("A1").CopyFromRecordset rs ' Закрыть набор записей rs. Закрыть Еще MsgBox «Ошибка: записи не возвращены.», vbCritical Конец, если ' Очистить Если CBool(conn.State и adStateOpen), то conn.Close Установить соединение = Ничего Установить rs = Ничего Конец сабвуфера
Прежде всего, это сработает? Во-вторых, что мне нужно заменить в подразделе (это выглядит как поставщик, источник данных, исходный каталог и т. д.) и где я могу найти информацию, чтобы заменить их?
Я надеюсь, что этот вопрос не слишком запутан, и я ценю вашу помощь!
- sql
- sql-сервер
- vba
- excel
10
Ниже приведен код, который я сейчас использую для извлечения данных из MS SQL Server 2008 в VBA. Вы должны убедиться, что у вас есть правильная ссылка на ADODB [ VBA Editor->Tools->References ] и убедитесь, что у вас отмечена Microsoft ActiveX Data Objects 2.8 Library , которая является второй снизу отмеченной строкой (я использую Excel 2010 в Windows 7; вы можете имеют немного другую версию ActiveX, но она все равно будет начинаться с Microsoft ActiveX):
Подмодуль для подключения к MS SQL с удаленным хостом и именем пользователя/паролем
Sub Download_Standard_BOM() 'Инициализирует переменные Dim cnn As New ADODB. Connection Dim сначала как новый ADODB.Recordset Dim ConnectionString как строка Dim StrQuery как строка 'Настройте строку подключения для доступа к базе данных MS SQL 'Обязательно измените: '1: ПАРОЛЬ '2: ИМЯ ПОЛЬЗОВАТЕЛЯ '3: УДАЛЕННЫЙ_IP_АДРЕС '4: БАЗА ДАННЫХ ConnectionString = "Provider=SQLOLEDB.1;Password=PASSWORD;Persist Security Info=True;ID пользователя=USERNAME;Источник данных=REMOTE_IP_ADDRESS;Использовать процедуру для подготовки=1;Автоматический перевод=True;Размер пакета=4096;Использовать шифрование для данных=False;Тегировать с сопоставлением столбцов, когда это возможно=False;Исходный каталог=BASE DATABASE" 'Открывает соединение с базой данных cnn.Open ConnectionString 'Ошибка тайм-аута в секундах для выполнения всего запроса; это будет работать за 15 минут до тайм-аута VBA, но ваша база данных может истечь до истечения этого значения cnn.CommandTimeout = 900 'Это ваш фактический запрос MS SQL, который вам нужно выполнить; вы должны сначала проверить этот запрос, используя более надежный редактор SQL (например, HeidiSQL), чтобы убедиться, что ваш запрос действителен. StrQuery = "ВЫБЕРИТЕ ТОП-10 * ИЗ tbl_table" 'Выполняет фактический запрос rst.Open StrQuery, cnn 'Выводит все результаты StrQuery в ячейку A2 первого листа активной книги. Листы(1).Range("A2").CopyFromRecordset сначала Конец сабвуфера
5
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Требуется, но никогда не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Как встроить длинные и сложные sql-запросы в код Excel VBA?
спросил
Изменено
9 месяцев назад
Просмотрено
16 тысяч раз
У меня есть приведенный ниже код VBA, который успешно работает при получении данных из базы данных SQL на лист Excel, когда мне нужно встроить простой запрос (например, Выберите * из таблицы1
), но этот код не работает и показывает
Ошибка компиляции: определяемый пользователем тип не определен.
при сложных и длинных запросах:
Sub ConnectSqlServer() Dim conn As ADODB.Connection Dim rs As ADODB.Recordset Dim sConnString как строка ' Создайте строку подключения. sConnString = "Поставщик = SQLOLEDB; Источник данных = vrsqladhoc;" & _ "Исходный каталог=TACT_REV;" & _ "Интегрированная безопасность=SSPI;" ' Создайте объекты Connection и Recordset. Установить conn = новый ADODB.Connection Установить rs = новый ADODB.Recordset 'Открываем соединение и выполняем. conn.Open sConnString Установить rs = conn.Execute("выбрать отдельный столбец1 из таблицы1;") 'Проверьте, у нас есть данные. Если Не rs.EOF Тогда ' Результат передачи. Листы(2).Range("A2").CopyFromRecordset rs ' Закрыть набор записей rs.Закрыть Еще MsgBox «Ошибка: записи не возвращены.», vbCritical Конец, если Конец сабвуфера
Длинный запрос, который я собираюсь встроить в код VBA, выглядит примерно так:
SELECT Count(column1) as status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола1 см внутреннее соединение table2 md на md. column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола2 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола3 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола4 см внутреннее соединение table2 md на md. column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола5 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола6 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type ОТ стола7 см внутреннее соединение table2 md на md. column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец Союз Все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type ОТ стола8 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем «Отсутствует», иначе «Доступно» конец
Подскажите, пожалуйста, как можно без ошибок внедрить длинные SQL-запросы в код VBA.
- Excel
- ВБА
11
Как именно вы строите строку подключения:
sConnString = "Provider=SQLOLEDB;Источник данных=vrsqladhoc;" & _ "Исходный каталог=TACT_REV;" & _ "Интегрированная безопасность=SSPI;"
Путем объединения строковых литералов.
Одна из проблем, с которой вы столкнетесь при таком длинном запросе, заключается в том, что VBA не позволит вам создать логических строк кода, которые охватывают гораздо больше, чем 10-15 физических строк кода. Видите ли, приведенный выше оператор представляет собой одну единственную логическую строку кода, но он охватывает 3 физических строк, которые включают 2 токенов продолжения строки .
Итак, вы просто делаете это:
Dim sql As String sql = "SELECT Count (column1) как status_count, случай, когда " & _ "..." и _ "..." и _ "..." и _ "и так далее"
И когда компилятор начинает жаловаться, что слишком много продолжений строки, вы просто конкатенируете его с собой:
sql = sql & "остальные" & _ " ...запрос"
Очевидно, это станет очень уродливым, очень быстро. Исправление ошибки в этом запросе будет кошмаром. Поддержание этого запроса будет кошмаром. Просто , глядя на в этом запросе, вызовет у вас кошмары.
Независимо от языка, такие сложные запросы не относятся к исходному коду . Они принадлежат серверу, представлению или хранимой процедуре . Если вы не можете создать представление или хранимую процедуру в базе данных, отправьте запрос тому, кто может.
Если нет абсолютно никакого способа избежать этого, то я настоятельно рекомендую вам использовать StringBuilder
для объединения строк. Результат, по крайней мере, будет намного чище, чем беспорядок чередующихся конкатенаций, продолжающихся строкой, и будет работать лучше.
Dim sql как строка С новым StringBuilder .Добавить "ВЫБРАТЬ..." .Добавить "..." .Добавить "..." .Добавить "..." .Добавить "..." .Добавить "..." SQL = .ToString Конец с
Примечание: что бы вы ни делали, никогда не объединяйте пользовательский ввод в SQL-запрос. Вместо этого параметризируйте его.
0
Чтобы преобразовать SQL в VBA, сделайте следующее:
Dim sql As String sql = "SELECT Count (column1) как status_count, случай, когда " & _ «missing_flag = 1, затем «Отсутствует», иначе «Доступно» заканчивается как статус, «Имя» как Document_Type» и _ "ИЗ таблицы1 см" &_ "внутреннее соединение table2 md на md.column1 = cm.column2" & _ "ГДЕ cm.column3 = 'R'" & _ "и cm.column4 = 3" & _ "группировать по регистру, когда" & _ "missing_flag1 = 1, затем "Отсутствует", иначе "Доступно" конец " sql = sql & "ОБЪЕДИНИТЬ ВСЕ" sql = sql & "продолжайте в том же духе..."
Вы можете сделать это в одном операторе, если это короткий SQL и легко читаемый, но с длинными операторами вы столкнетесь с проблемами строки продолжения ( _
) в VBA. Именно поэтому я разбил его на несколько настроек sql
.
Это грубая сила, а не идеальное решение, кошмар для отладки и обслуживания!
Лучше всего хранить в БД непосредственно как хранимую процедуру и вызывать ее в excel vba.
1
Обычно я пишу SQL-запросы для встраивания в Excel/VBA в Notepad++, а затем сохраняю их в виде простого (текстового) файла .sql. У меня есть скрипт, который с помощью .fso(FileSystemObject) считывает содержимое файла и использует его для формирования запроса (все соединения с моими БД стандартные).
Когда файл готов к развертыванию в бизнесе, я копирую весь SQL-запрос в текстовое поле на рабочем листе, затем на него можно ссылаться:
strSQL = ThisWorkbook.Sheets("SQL_Query").TextBoxes( "SQL_Text").Текст
Преимущество этого в том, что все отступы из Notepad++ остаются на месте.
На последнем этапе необходимо убедиться, что для свойства Visible рабочего листа задано значение .xlSheetVeryHidden и, конечно же, код защищен паролем.
1
Это должно быть довольно просто. Просто следите за переносом слов!
Sub ADOExcelSQLServer() Dim Cn As ADODB.Connection Dim Server_Name как строка Dim Database_Name как строка Dim User_ID как строку Dim Пароль как строка Dim SQLStr как строка Dim rs As ADODB. Recordset Установить rs = новый ADODB.Recordset Server_Name = "Your_Server_Name" ' Введите здесь имя вашего сервера Database_Name = "Northwnd" ' Введите здесь имя вашей базы данных User_ID = "" ' введите здесь свой ID пользователя Пароль = "" 'Введите свой пароль здесь SQLStr = "ВЫБЕРИТЕ Поле1, Поле2, Поле3, Поле4" SQLStr = SQLStr & " FROM Orders Where Order ID = 100 " ' Введите здесь свой SQL Установите Cn = Новый ADODB.Connection Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & _ ";Uid=" & User_ID & ";Pwd=" & Password & ";" rs.Open SQLStr, Cn, adOpenStatic С рабочими листами («Лист1»). Диапазон («A1: Z500») .ClearContents .CopyFromRecordset rs Конец с rs.Закрыть Установить rs = Ничего Сп.Закрыть Установите Cn = Ничего Конец сабвуфера Вспомогательная рабочая2 () Dim con As Connection Dim сначала как набор записей Dim strConn как строка Установить con = новое соединение strConn = "EXCEL-PC\SQLEXPRESS;база данных=Борей;Trusted_Connection=True" con. Open strConn 'Поместите название страны в ячейку E1 Установите rst = con.Execute("Exec dbo.MyOrders '" & ActiveSheet.Range("E1").Text & "'" & ActiveSheet.Range("E2").Text & "'") 'Общее количество записей возвращается в ячейку A5 ActiveSheet.Range("A5").CopyFromRecordset сначала рст.Закрыть кон.Закрыть Конец сабвуфера
Оставляйте пробел перед и после каждой двойной кавычки.
Итак, для вас, я думаю, это должно быть примерно так…
SQLStr = " SELECT Count(column1) as status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола1 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем 'Отсутствует', иначе 'Доступно' end " SQLStr = SQLStr & "Объединить все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола2 см внутреннее соединение table2 md на md. column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем 'Отсутствует', иначе 'Доступно' end " SQLStr = SQLStr & "Объединить все SELECT Count(column1) как status_count, случай, когда missing_flag = 1, затем 'Отсутствует', иначе 'Доступно' заканчивается как статус, 'Имя' как Document_Type СО стола3 см внутреннее соединение table2 md на md.column1 = cm.column2 ГДЕ cm.column3 = 'R' и см.столбец4 = 3 группировать по случаям, когда missing_flag1 = 1, затем 'Отсутствует', иначе 'Доступно' end "
Я наткнулся на эту тему, но решил добавить решение, которое нашел удобным.
Решение, которое я нашел полезным для этого, заключается в сохранении запросов на рабочем листе и последующем обращении к значениям (например, sQuery = Sheets("Queries").Range("A1").Value
). В завершенных проектах электронная таблица, содержащая сохраненные запросы, скрыта от обычного просмотра.
Используя стандартный текстовый редактор, вы можете написать запрос, а затем вырезать и вставить его в ячейку, и он будет отображаться так же, как в текстовом редакторе. Это облегчает чтение, не загромождает ваш код и позволяет легко изменить/обновить позже, если это необходимо.
Вот пример, который я вырезал и вставил из одного из моих рабочих листов в этот редактор:
ВЫБРАТЬ инвойс_идентификатор, temp.invoice_number, temp.open_date, temp.close_date, Код товара, описание, линия_итого, облагаемый налогом ОТ позиции ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБИРАТЬ invoice_id, invoice_number, open_date, close_date ОТ счета-фактуры ГДЕ close_date МЕЖДУ [дата_начала] И [дата_окончания]) AS temp USING (invoice_id) ГДЕ taxable=1 ИЛИ product_id LIKE '%TAX%';
В приведенном выше примере я использую функцию replace()
для замены параметров [start_date]
и [end_date]
правильными значениями до выполнения запроса.
На практике я использую несколько столбцов на листе, где хранятся запросы. Первый столбец содержит имя ссылки для запроса, второй столбец содержит запрос, а третий столбец содержит описание и любые дополнительные комментарии/примечания.
Использование некоторых творческих функций ( GetStoredQuery()
, PutStoredQuery()
, ExecuteStoredQuery()
и т. д.) это очень похоже на использование хранимых процедур в SQL, за исключением того, что ваши хранимые процедуры хранятся в вашем проекте VB, а не на сервере SQL.
Мое решение состоит в том, чтобы обернуть длинный код sql в процедуру на части сервера sql. Следовательно, вам не нужно писать длинный код sql в vba. Процедура может иметь параметры, поэтому вам не нужно ничего менять в коде sql. Просто вызовите процедуру из vba с помощью sqlcommand и все.
3
Я бился головой о стену с той же проблемой. Самый простой способ решить эту проблему — сохранить сложный код как хранимую процедуру в самой базе данных.