Excel sql запрос к листу vba: Как сформировать SQL запросы в Excel? — Разработка на vc.ru

Как сформировать SQL запросы в Excel? — Разработка на vc.ru

Представьте себе ситуацию, Вы получили целевую выборку из одной базы данных, но для полноты картины, как всегда, нужны дополнительные данные. Проблема может быть в том, что нужная информация хранится в другой базе данных и возможности создать на ней свою таблицу нет, подключиться используя link тоже нельзя, да и количество элементов, по которым нужно получить данные, несколько больше, чем допустимое на данном источнике. Вот и получается, что возможность написать SQL запрос и получить нужные данные есть, но написать придется не один запрос, а потом потратить время на объединение полученных данных.

22 752
просмотров

Выйти из подобной ситуации поможет Excel.

Уверен, что ни для кого не секрет, что MS Excel имеет встроенный модуль VBA и надстройки, позволяющие подключаться к внешним источникам данных, то есть по сути является мощным инструментом для аналитики, а значит идеально подходит для решения подобных задач.

Для того чтобы обойти проблему, нам потребуется таблица с целевой выборкой, в которой содержатся идентификаторы, по которым можно достаточно корректно получить недостающую информацию (это может быть уникальный идентификатор, назовем его ID, или набор из данных, находящихся в разных столбцах), ПК с установленным MS Excel, и доступом к БД с недостающей информацией и, конечно, желание получить ту самую информацию.

Создаем в MS Excel книгу, на листе которой размещаем таблицу с идентификаторами, по которым будем в дальнейшем формировать запрос (если у нас есть уникальный идентификатор, для обеспечения максимальной скорости обработки таблицу лучше представить в виде одного столбца), сохраняем книгу в формате *.xlsm, после чего приступаем к созданию макроса.

Через меню «Разработчик» открываем встроенный VBA редактор и начинаем творить.

Sub job_sql() — Пусть наш макрос называется job_sql.

Пропишем переменные для подключения к БД, записи данных и запроса:

Dim cn As ADODB. Connection
Dim rs As ADODB.Recordset
Dim sql As String

Опишем параметры подключения:

sql = «Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=True;Data Source=Storoge.company.ru\ Storoge.»

Объявим процедуру свойства, для присвоения значения:

Set cn = New ADODB.Connection
cn.Provider = » SQLOLEDB.1″
cn.ConnectionString = sql
cn.ConnectionTimeout = 0
cn.Open

Вот теперь можно приступать непосредственно к делу.

Организуем цикл:

For i = 2 To 1000

Как вы уже поняли конечное значение i=1000 здесь только для примера, а в реальности конечное значение соответствует количеству строк в Вашей таблице. В целях унификации можно использовать автоматический способ подсчета количества строк, например, вот такую конструкцию:

Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Row — 1 + ActiveSheet.UsedRange.Rows.Count

Тогда открытие цикла будет выглядеть так:

For i = 2 To LastRow

Как я уже говорил выше MS Excel является мощным инструментом для аналитики, и возможности Excel VBA не заканчиваются на простом переборе значений или комбинаций значений. При наличии известных Вам закономерностей можно ограничить объем выгружаемой из БД информации путем добавления в макрос простых условий, например:

If Cells(i, 2) = «Ваше условие» Then

Итак, мы определились с объемом и условиями выборки, организовали подключение к БД и готовы формировать запрос. Предположим, что нам нужно получить информацию о размере ежемесячного платежа [Ежемесячный платеж] из таблицы [payments].[refinans_credit], но только по тем случаям, когда размер ежемесячного платежа больше 0

sql = «select [Ежемесячный платеж] from [PAYMENTS].[refinans_credit] » & _
«where [Ежемесячный платеж]>0 and [Номер заявки] ='» & Cells(i, 1) & «‘ «

Если значений для формирования запроса несколько, соответственно прописываем их в запросе:

«where [Ежемесячный платеж]>0 and [Номер заявки] = ‘» & Cells(i, 1) & «‘ » & _
» and [Дата платежа]='» & Cells(i, 2) & «‘»

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

Cells(i, 3) = sql

в третьем столбце записываются запросы.

Выполняем SQL запрос:

Set rs = cn.Execute(sql)

А чтобы хоть как-то наблюдать за выполнением макроса выведем изменение i в статус-бар

Application.StatusBar = «Execute script …» & i
Application.ScreenUpdating = False

Теперь нам нужно записать полученные результаты. Для этого будем использовать оператор Do While:

j = 0
Do While Not rs.EOF
For ii = 0 To rs.Fields.Count — 1
Cells(i, 4 + j + ii) = rs.Fields(0 + ii) ‘& «;»

Указываем ячейки для вставки полученных данных (4 в примере это номер столбца с которого начинаем запись результатов)

Next ii
j = j + rs.Fields.Count
s.MoveNext
Loop
rs.Close
End If

— закрываем цикл If, если вводили дополнительные условия

Next i
cn.Close
Application.StatusBar = «Готово»
End Sub

— закрываем макрос.

В дополнение хочу отметить, что данный макрос позволяет обращаться как к БД на MS SQL так и к БД Oracle, разница будет только в параметрах подключения и собственно в синтаксисе SQL запроса.

В приведенном примере для авторизации при подключении к БД используется доменная аутентификация.

А как быть если для аутентификации необходимо ввести логин и пароль? Ничего невозможного нет. Изменим часть макроса, которая отвечает за подключение к БД следующим образом:

sql = «Provider= SQLOLEDB.1;Password=********;User ID=********;Data Source= Storoge.company.ru\ Storoge;APP=SFM»

Но в этом случае при использовании макроса возникает риск компрометации Ваших учетных данных. Поэтому лучше программно удалять учетные данные после выполнения макроса. Разместим поля для ввода пароля и логина на листе и изменим макрос следующим образом:

sql = «Provider= SQLOLEDB.1;Password=» & Sheets(«Лист аутентификации»).TextBox1.Value & «;UserЛист аутентификации «).TextBox2.Value & «;Data Source= Storoge.company.ru\ Storoge;APP=SFM»

Место для расположения текстовых полей не принципиально, можно расположить их на листе с таблицей в первых строках, но мне удобней размещать поля на отдельном листе. Чтобы введенные учетные данные не сохранялись вместе с результатом выполнения макроса в конце исполняемого кода дописываем:

Sheets(«Выгрузка»).TextBox1.Value = «« Sheets(»Выгрузка«).TextBox2.Value = »»

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

Вот такое вполне жизнеспособное решение, позволяющее сократить трудозатраты при получении и обработке данных, я использую. Надеюсь мой опыт применения SQL запросов в Excel будет полезен и вам в решении текущих задач.

Excel VBA. SQL-запросы в подключениях — Эффективная работа в MS Office

UPDATE 21.10.15 Добавил «обратный» макрос — VBA в SQL и макрос для доступа к строке запроса SQL

Некоторое время назад я прошел несколько курсов по SQL. И мне было очень интересно — какую часть из мощного инструмента под названием T-SQL можно применять без использования SQL-Server (не дают мне сервачек под мои нужды, хнык-хнык).

Итак… Начнем с простого — подключение через Query Table в VBA. Можно записать через макрорекордер — для этого нужно создать подключение через Microsoft Query.

Выбираем Excel Files, указываем путь к файлу (пытаясь при этом не ругать разработчиков за интерфейс из 90х годов), фильтруем как-угодно поля. Нам сейчас это не важно — главное получить код, который дальше можно будет корректировать.

Должно получится что-то вроде этого:


Sub Макрос1()
    With ActiveSheet.ListObjects.Add(SourceType:=0, Source:=Array(Array( _
        "ODBC;DSN=Excel Files;DBQ=D:\Dropbox\Excel\тест excel_SQL-2015.xlsx;DefaultDir=D:\Dropbox\Excel;DriverId=1046;MaxBufferSize=2048;Page" _
        ), Array("Timeout=5;")), Destination:=Range("$A$1")).QueryTable
        .CommandType = 0
        .CommandText = Array( _
        "SELECT Продажи.F2, Продажи.F3" & Chr(13) & "FROM `D:\Dropbox\Excel\тест excel_SQL-2015.xlsx`.Продажи Продажи" _
        )
        . RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .BackgroundQuery = True
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .PreserveColumnInfo = True
        .ListObject.DisplayName = "Таблица_Запрос_из_Excel_Files"
        .Refresh BackgroundQuery:=False
    End With
End Sub

Строчка .CommandText = «SELECT…» — отвечает за SQL запрос. Если хотя бы немного почитать поисковую выдачу google по запросу QueryTable можно упростить код до следующего:


Sub CopyFromRecordset_To_Range()
  
  DBPath = "C:\InputData.xlsx"
  sconnect = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
  Conn.Open sconnect
  sSQLSting = "SELECT * FROM [Sheet1$]"

  rs. Open sSQLSting, Conn
  Set QT1 = ActiveSheet.QueryTables.Add(rs, Range("A1"))
  QT1.Refresh

  rs.Close
  Conn.Close

End Sub

Теперь начинаем копаться глубже — какого уровня запросы можно строить из VBA. Самые-самые базовые, основные конструкции — все работает, все ок.

Заполнение нового столбца одинаковым значением


SELECT  'YTikhonov', * 
FROM    [Sheet1$]

Переименование столбцов


SELECT  [Advertiser] AS 'Рекламодатель', [Quantity] AS 'Количество'
FROM    [Sheet1$]

Фильтрация записей


SELECT  * 
FROM    [Sheet1$]
WHERE   [Year] = 2014

Сортировка


SELECT   * 
FROM     [Sheet1$]
ORDER BY [Advertiser] DESC

Агрегация записей


SELECT   [Advertiser], Sum([Cost]) 
FROM     [Sheet1$]
GROUP BY [Advertiser]

Работа с датой

Дату можно впрямую через конструкцию


[SomeDateField] = {ts '2015-01-01 00:00:00'}

Но я люблю отталкиваться от текущей даты. За пару текущая дата-время отвечает функция SYSDATETIME() и она может вернуть в том числе текущий день. Для этого нужна еще одна функция  — CONVERT(type,value)


SELECT CONVERT(date,SYSDATETIME())

С функцией DATEFROMPARTS строка запроса в Excel почему-то не дружит, поэтому придется использовать костыли функцию DATEADD:


DATEADD(minute, 59, DATEADD(hour, 23, DATEADD(month, MONTH(SYSDATETIME())+1, DATEADD(year, YEAR(SYSDATETIME()) - 1900, 0))))-1

Эта строчка в любой день октября 2015 вернет значение — 30.11.15 23:59

А теперь — немного best practice!

Объединение + Агрегация + Join + Подзапросы. И самое интересное — подключение к нескольким источникам:


SELECT [Year], O.Numbers, SCost, SVolume, SQuantity FROM
 (
  SELECT [Year], Month, SUM([Cost RUB]) AS SCost, SUM(Volume) AS SVolume, SUM(Quantity) AS SQuantity FROM
   (
     SELECT Advertiser, 2013 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:\GK\Radio\Маркетинг\Служебный\2013. xlsb].[Мониторинг$]
      UNION
     SELECT Advertiser, 2014 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:\GK\Radio\Маркетинг\Служебный\2014.xlsb].[Мониторинг$]
       UNION
     SELECT Advertiser, 2015 as [Year], Month, [Cost RUB], Quantity, Volume
     FROM [N:\GK\Radio\Маркетинг\Служебный\2015.xlsb].[Мониторинг$]
   )
   WHERE [Advertiser] = 'METRO GROUP'
   GROUP BY [Year], Month
 ) as T INNER JOIN [C:\test\Month.xlsb].[Test$] AS O
ON T.[Month] = O.[Month]

Одна проблема — если осуществлять такого вида запрос для соединения нескольких Excel-файлов, он будет выполняться достаточно медленно. У меня вышло порядка 2 минут. Но не стоит думать что это бесполезно — если подобные запросы выполнять при подключении к SQL-серверу, то время обработки будет 1-2 секунды (само собой, все зависит от сложности запроса, базы, и прочие прочие факторы).

Бонусы

Формировать более-менее сложный запрос SQL вручную в VBA мягко говоря неудобно.  Поэтому я написал мини-макрос, который берет информацию из буфера обмена, и возвращает туда строчки для вставки в VBE.


'работа с буфером обмена http://excelvba.ru/code/clipboard
Private Function ClipboardText() ' чтение из буфера обмена
    With GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
        .GetFromClipboard
        ClipboardText = .GetText
    End With
End Function
 
Private Sub SetClipboardText(ByVal txt$) ' запись в буфер обмена
    With GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
        .SetText txt$
        .PutInClipboard
    End With
End Sub

Public Sub SQL_String_To_VBA()
  
    Dim sInput As String, sOut As String
    Dim ArrInput, i As Integer
    
    Dim cIdent As Integer: cIdent = 1 'Count of tabs
    Dim sVar As String: sVar = "strSQL" 'Name of variable
      
    sInput = ClipboardText()
    
    ArrInput = Split(sInput, Chr(13))
    
    For i = LBound(ArrInput) To UBound(ArrInput)
        sOut = sOut & sVar & " = " & sVar & " & " & Chr(34)
        sOut = sOut & String(cIdent, Chr(9))
        sOut = sOut & Replace(ArrInput(i), Chr(10), "")
        sOut = sOut & Chr(34) & "& chr(10)" & Chr(10)
    Next i
    
    SetClipboardText (sOut)

End Sub

Public Sub VBA_String_To_SQL()
 
    Dim sInput As String, sOut As String
    Dim ArrInput, i As Integer, sTemp
 
    sInput = ClipboardText()
 
    ArrInput = Split(sInput, Chr(10))
 
    For i = LBound(ArrInput) To UBound(ArrInput)
      sTemp = Replace(ArrInput(i), "& chr(10)", "")
      If Right(sTemp, 1) = " " Then sTemp = Left(sTemp, Len(sTemp) - 1)
      If Right(sTemp, 1) = Chr(34) Then sTemp = Left(sTemp, Len(sTemp) - 1)
 
      If Len(sTemp) > 0 Then
        sTemp = Right(sTemp, Len(sTemp) - InStr(1, sTemp, Chr(34)))
        sOut = sOut & Chr(10) & sTemp
      End If
    Next i
 
    SetClipboardText (sOut)

End Sub

Сами запросы просто и удобно создавать, например, используя Notepad++. Создали многострочный запрос SQL, копируете его в буфер обмена, запускаете макрос и вуаля — в буфере обмена строчки кода, готовые для вставки в ваши макросы. При желании вы можете настроить название переменной и количество табуляций.

И еще один небольшой бонус. Если у вас есть отчет по менеджерам/руководителям, построенный на запросах, то вам наверняка потребуется получать доступ к строке запроса через VBA. Сделать это можно через замечательную команду .CommandText — работает на чтение и запись. Мне для формирования отчета на 25 человек очень пригодился.


Public Sub ReplaceCommandText()
 
Dim con As WorkbookConnection
Dim sTemp As String
 
  For Each con In ActiveWorkbook.Connections
    sTemp = con.ODBCConnection.CommandText
    con.ODBCConnection.CommandText = sTemp
    con.Refresh
  Next con
 
End Sub

PS Ссылка с ответом на вопрос — как вставить данные из Excel в SQL
https://www.simple-talk. com/sql/t-sql-programming/questions-about-using-tsql-to-import-excel-data-you-were-too-shy-to-ask/

 

Приятного использования!

Понравилось это:

Нравится Загрузка…

Выполнение SQL-запросов к таблице Excel в рабочей книге с помощью макроса VBA

Я пытаюсь создать макрос Excel, который даст мне следующую функцию в Excel:

 =SQL("SELECT heading_1 FROM Table1 WHERE heading_2='foo' ")
 

Позволяет мне искать (и, возможно, даже вставлять) данные в таблицы моей книги с помощью SQL-запросов.

Вот что я сделал до сих пор:

 Sub SQL()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Расширенные свойства=""Excel 12.0;HDR=Да;IMEX=1"";"
Установите cn = CreateObject("ADODB.Connection")
Установить rs = CreateObject("ADODB.Recordset")
cn.Open strCon
strSQL = "ВЫБЕРИТЕ * ИЗ [Лист1 $ A1: G3]"
rs.Open strSQL, cn
Debug.Print rs. GetString
Конец сабвуфера
 

Мой скрипт прекрасно работает с жестко закодированными диапазонами, такими как во фрагменте выше. Он также очень хорошо работает со статическими именованными диапазонами.

Однако он не будет работать ни с динамическими именованными диапазонами, ни с ИМЕНАМИ ТАБЛИЦ, что для меня наиболее важно.

Самый близкий ответ, который я нашел, это этот парень, страдающий от того же недуга:
http://www.ozgrid.com/forum/showthread.php?t=72973

Кто-нибудь поможет?

Редактировать

Пока я готовил это, я могу использовать полученное имя в своих SQL-запросах. Ограничение в том, что мне нужно знать, на каком листе находятся таблицы. Можем ли мы что-то с этим сделать?

 Функция getAddress()
    мойАдрес = Заменить(Листы("Лист1").Диапазон("Таблица1").адрес, "$", "")
    мой адрес = "[Лист1$" и мой адрес & "]"
    получитьадрес = мой адрес
Конечная функция
 

Спасибо!

  • sql
  • vba
  • первенствовать

4

Одна вещь, которую вы можете сделать, это получить адрес динамического именованного диапазона и использовать его в качестве входных данных в вашей строке SQL. Что-то вроде:

 Sheets("shtName").range("namedRangeName").Address
 

Который выдаст строку адреса, что-то вроде $A$1:$A$8

Редактировать:

Как я сказал в своем комментарии ниже, вы можете динамически получить полный адрес (включая имя листа) и либо используйте его напрямую, либо проанализируйте имя листа для последующего использования:

 ActiveWorkbook.Names.Item("namedRangeName").RefersToLocal
 

В результате получается строка вида =Sheet1!$C$1:$C$4 . Таким образом, для вашего примера кода выше ваш оператор SQL может быть

 strRangeAddress = Mid(ActiveWorkbook.Names.Item("namedRangeName").RefersToLocal,2)
strSQL = "ВЫБЕРИТЕ * ИЗ [strRangeAddress]"
 

4

 Публичная функция GetRange(ByVal sListName As String) As String
Dim oListObject как ListObject
Dim wb как рабочая книга
Dim ws As рабочий лист
Установите wb = Эта рабочая книга
Для каждого ws в wb. Sheets
    Для каждого oListObject в ws.ListObjects
        Если oListObject.Name = sListName Тогда
            GetRange = "[" & ws.Name & "$" & Replace(oListObject.Range.Address, "$", "") & "]"
        Выход из функции
        Конец, если
    Следующий oListObject
Следующий мс
Конечная функция
 

В вашем SQL используйте это так

 sSQL = "Выбрать * из" & GetRange("NameOfTable") & ""
 

2

Основание на подпрограмме Джоан-Диего Родригеса с подходом Джорди и частью кода Яцека Котовски. Эта функция преобразует любое имя таблицы для активной рабочей книги в пригодный для использования адрес для SQL-запросов.

Примечание для MikeL: добавление «[#Все]» включает заголовки, позволяющие избежать проблем, о которых вы сообщили.

 Функция getAddress(byVal sTableName as String) as String
    С диапазоном (sTableName и "[#All]")
        getAddress= "[" & .Parent.Name & "$" & .Address(False, False) & "]"
    Конец с
Конечная функция
 

1

Я новичок, работаю с чужим кодом, поэтому будьте снисходительны и исправляйте мои ошибки. Я попробовал ваш код и поиграл с помощью VBA. Со мной сработало следующее:

 Функция currAddressTest (dataRangeTest As Range) As String
    currAddressTest = ActiveSheet.Name & "$" & dataRangeTest.Address(False, False)
Конечная функция
 

Когда я выбираю аргумент источника данных для своей функции, он преобразуется в формат Sheet1$A1:G3. Если Excel изменит его на ссылку Table1[#All] в моей формуле, функция все еще будет работать правильно

Затем я использовал ее в вашей функции (пытался воспроизвести и добавить еще один аргумент для внедрения в WHERE…

 Функция SQL( dataRange как диапазон, CritA как строка)
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim currAddress как строка
currAddress = ActiveSheet.Name & "$" & dataRange.Address(False, False)
strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Расширенные свойства=""Excel 12.0;HDR=Да;IMEX=1"";"
Установите cn = CreateObject("ADODB.Connection")
Установить rs = CreateObject("ADODB. Recordset")
cn.Open strCon
strSQL = "SELECT * FROM [" & currAddress & "]" & _
         "ГДЕ [A] = '" & CritA & "' " & _
         "ЗАКАЗАТЬ ПО 1 АСЦ"
rs.Open strSQL, cn
SQL = rs.GetString
Конечная функция
 

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

Просто отвечая на вторую часть вашего вопроса о получении имени листа, на котором находится таблица:

 Dim name as String
имя = Диапазон ("Таблица1"). Рабочий лист. Имя
 

Редактировать:

Чтобы было понятнее: кто-то предложил использовать Range на объекте Sheet. В этом случае вам не нужно; Диапазон, в котором находится таблица, можно получить, используя имя таблицы; это имя доступно на протяжении всей книги. Таким образом, вызов Range в одиночку работает хорошо.

Просто хотел добавить сюда, что вы можете просто сделать свой диапазон именованным диапазоном и использовать его в своем запросе (или весь лист, если у вас есть одна таблица на листе).

Таким образом, вы можете использовать:

SELECT * FROM MyNamedRange

OR

SELECT * FROM [Sheet1$]

Многие из этих ответов, кажется, уходят на усилия при анализе Исторически сложилось так, что я просто устанавливаю все мои таблицы как именованные диапазоны и ссылаюсь на них непосредственно в запросе (это также делает его намного чище).

В одном из моих более сложных запросов ниже все диапазоны, на которые я ссылаюсь, являются именованными диапазонами:

 SELECT Unit_Type AS [Тип единицы], COUNT(*) AS [Количество единиц], SQFT, Депозит AS [Депозит{ $}], Rent AS [Базовая арендная плата{$}], SUM(RENT) AS [Общая базовая арендная плата{$}], SUM(MR) AS [Общая рыночная арендная плата{$}] FROM
(
    ВЫБЕРИТЕ f1.Unit_Code, Unit_Type, SQFT, Rent, Deposit, SWITCH (MR IS NULL, Rent, MR IS NOT NULL, MR) AS MR FROM
    (
        ВЫБЕРИТЕ t2.Unit_Code, t2.Unit_Type, SQFT, Аренда, Депозит ОТ
        (
            ВЫБЕРИТЕ РАЗЛИЧНЫЕ Unit_Code, Unit_Type
            ОТ Коммуникаций
            ГДЕ Unit_Code НЕ КАК "%WAIT%" И Exclude=0
        ) т2
        ЛЕВОЕ СОЕДИНЕНИЕ
        (
            ВЫБЕРИТЕ UnitType_Code, SQFT, Аренда, Депозит
            ИЗ ResUnitTypes
        ) t1 ON (t1. UnitType_Code = t2.Unit_Type)
    ) f1
    ЛЕВОЕ СОЕДИНЕНИЕ
    (
        ВЫБЕРИТЕ Unit_Code, SUM(Current_Charge) AS MR
        ОТ ResUnitAmenities
        ГДЕ Unit_Code НЕ КАК "% WAIT%"
        СГРУППИРОВАТЬ ПО Unit_Code
    ) f2 вкл (f1.Unit_Code = f2.Unit_Code)
)
СГРУППИРОВАТЬ ПО Unit_Type, SQFT, Депозит, Аренда
 

Привет, недавно изучил это и обнаружил проблемы со ссылкой на именованную таблицу (объект списка) в Excel

если вы поместите суффикс ‘$’ в имя таблицы, все будет хорошо в мире

 Sub testSQL()
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    ' Объявить переменные
    strFile = ThisWorkbook.FullName
    ' построить строку подключения
    strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
    & ";Расширенные свойства=""Excel 12.0;HDR=Да;IMEX=1"";"
    ' создать соединение и объекты набора записей
    Установите cn = CreateObject("ADODB.Connection")
    Установить rs = CreateObject("ADODB.Recordset")
    ' открыть соединение
    cn. Open strCon
    ' построить SQL-запрос
    strSQL = "SELECT * FROM [TableName$], где [ColumnHeader] = 'wibble';"
    ' выполнить SQL-запрос
    rs.Open strSQL, cn
    Debug.Print rs.GetString
    ' тесная связь
    rs.Закрыть
    сн.Закрыть
    Установить rs = ничего
    Установите cn = Ничего
Конец сабвуфера
 

3

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью Google

Зарегистрироваться через Facebook

Зарегистрируйтесь, используя адрес электронной почты и пароль

Опубликовать как гость

Электронная почта

Требуется, но не отображается

Опубликовать как гость

Электронная почта

Требуется, но не отображается

sql server — Использование Excel VBA для запуска SQL-запроса

Задавать вопрос

спросил

Изменено
2 года, 9 месяцев назад

Просмотрено
282к раз

Я новичок в 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->Инструменты->Ссылки ] и убедитесь, что у вас отмечена 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.