I construct hundreds of SQL Queries in an excel sheet and each one is placed in a cell of 1 column. What I am looking to do is run each of these SQL statements from excel.
Just wondering if anyone knows a way to convert all my SQL into VBA Strings to that I can loop through all rows to run each query.
I found this which is what I want to do but is there a way I can alter the code so it can read off excel cells rather than a Form?
http://allenbrowne.com/ser-71.html
Thanks
EDIT: Here is a sample SQL that I am trying to convert
SELECT
TT.TEST_TABLE_ID,
TT.TEST_TABLE_NO,
TT.MEMBERSHIP_NUMBER,
TT.TEST_TABLE_TYPE,
from TEST_TABLE TT
I think because each Select is in its own line it causes problems when it converts.
EDIT #2: Here is my code that executes SQL
Sub GetData()
Dim Conn As New ADODB.Connection
Dim RS As New ADODB.Recordset
Dim cmd As New ADODB.Command
Dim sqlText As String
Dim Row As Long
Dim Findex As Long
Dim Data As Worksheet
Dim X As Long
Set Data = Sheets("Results")
Data.Select
Cells.ClearContents
Conn.Open "PROVIDER=ORAOLEDB.ORACLE;DATA SOURCE=ORCL;USER ID=user;PASSWORD=password"
cmd.ActiveConnection = Conn
cmd.CommandType = adCmdText
'sqlText = How to reference Valid SQL cells
cmd.CommandText = sqlText
Set RS = cmd.Execute
For X = 1 To RS.Fields.Count
Data.Cells(1, X) = RS.Fields(X - 1).Name
Next
If RS.RecordCount < Rows.Count Then
Data.Range("A2").CopyFromRecordset RS
Else
Do While Not RS.EOF
Row = Row + 1
For Findex = 0 To RS.Fields.Count - 1
If Row >= Rows.Count - 50 Then
Exit For
End If
Data.Cells(Row + 1, Findex + 1) = RS.Fields(Findex).Value
Next Findex
RS.MoveNext
Loop
End If
Cells.EntireColumn.AutoFit
End Sub
in the SQL text part I want to be able to reference my column of SQL statements that I have. I thought I needed to convert it but you guys are right that if referencing it I can Just use your code Brad.
I tried to incorporate your code brad where my 'sqlText = How to reference Valid SQL cells is but had no success
Here is a start to the code I think you need.
I have placed the SQL in a sheet named "SQL", in Col A.
The issues with this are:
(1) You are placing field names in a row, then the data that is returned into a row. That will require two rows per SQL statement.
(2) I copied the SQL statement from sheet "SQL' and placed in Col A of "Results" (you mentioned you wanted to place results to right of SQL String. (3) You clear the contents of "Results" sheet, so you need to be careful not to erase your SQL if you decide to combine sheets.
Option Explicit
Sub Process_SQL_Strings()
Dim cmd As New ADODB.Command
Dim sqlText As String
Dim Row As Long
Dim Findex As Long
Dim Data As Worksheet
Dim iFldCt As Long
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sConn As String
Dim lLastRow As Long
Dim lRow As Long
Set Data = Sheets("Results")
Data.Select
Cells.ClearContents
conn.Open "PROVIDER=ORAOLEDB.ORACLE;DATA SOURCE=ORCL;USER ID=user;PASSWORD=password"
cmd.ActiveConnection = conn
cmd.CommandType = adCmdText
'' Set conn = New ADODB.Connection
'' sConn = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
'' "Data Source=C:\data\access\tek_tips.accdb;" & _
'' "Jet OLEDB:Engine Type=5;" & _
'' "Persist Security Info=False;"
conn.Open sConn
'sqlText = How to reference Valid SQL cells
lRow = 1
Do
sqlText = Sheets("SQL").Range("A" & lRow)
If sqlText = "" Then
MsgBox "Finished processing " & lRow & " rows of SQL", vbOKOnly, "Finished"
GoTo Wrap_Up
End If
Set rs = New ADODB.Recordset
rs.Open sqlText, conn, adOpenStatic, adLockBatchOptimistic, adCmdText
Data.Cells(lRow, 1) = sqlText
If not rs.EOF then
For iFldCt = 1 To rs.Fields.Count
Data.Cells(lRow, 1 + iFldCt) = rs.Fields(iFldCt - 1).Name
Next
If rs.RecordCount < Rows.Count Then
Data.Range("B" & lRow).CopyFromRecordset rs
Else
Do While Not rs.EOF
Row = Row + 1
For Findex = 0 To rs.Fields.Count - 1
If Row >= Rows.Count - 50 Then
Exit For
End If
Data.Cells(Row + 1, Findex + 1) = rs.Fields(Findex).value
Next Findex
rs.MoveNext
Loop
End If
Cells.EntireColumn.AutoFit
End If
lRow = lRow + 1
Loop
Wrap_Up:
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
End Sub
I am using something this:
Function SQLQueryRun(ByVal query As String, ByVal returnData As Boolean) As Variant
Dim Conn As New ADODB.Connection
Dim ADODBCmd As New ADODB.Command
Dim ret As New ADODB.Recordset
Conn.ConnectionString = "connection_string_here"
Conn.Open
ADODBCmd.ActiveConnection = Conn
ADODBCmd.CommandText = query
Set ret = ADODBCmd.Execute()
If returnData Then
If Not ret.EOF Then SQLQueryRun = ret.GetRows()
Else
SQLQueryRun = True
End If
Conn.Close
Set Conn = Nothing
Set ret = Nothing
End Function
If the second argument is False nothing is returned by function. Are you expecting results from query run?
Also I use a macro to create Query/Pivot table from sql contained in windows clipboard, if you are interested let me know.
You'll need to create a connection to your database and loop through all the cells and execute your code in each cell.
You can use ADO to to make the connection (need to add a reference to Microsoft ActiveX Data Objects 6.1 Library)
You'll need to figure out your connection string, open a connection, then loop through all the cells and execute the SQL in those cells.
Dim cnn As New ADODB.Connection
Dim connectionString As String
Dim cmd As New ADODB.Command
Dim c As Range, ws As Worksheet
Dim rst as ADODB.Recordset
connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data source=C:\Database3.accdb;Persist Security Info=False;"
cnn.Open connectionString
cmd.ActiveConnection = cnn
For Each c In ws.Range()
cmd.CommandText = c.Value
set rst = cmd.Execute
'do what you need to with your new recordset before moving on to the next SELECT
Next c
Related
First of all I'm new to VB so all help is very much appreciated.
I'm trying to populate a ComboBox in Excel with data from an SQL server.
The error is 'Dim cnt As ADODB.Connection' - Complie Error: User-defined type not defined
Sub Populate_ComboBox_From_SQL()
Dim cnt As ADODB.Connection
Dim rst As ADODB.Recordset
Dim stDB As String, stConn As String, stSQL As String
Dim xlCalc As XlCalculation
Dim vaData As Variant
Dim k As Long
Set cnt = New ADODB.Connection
stConn = "DSN=Backup;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=<database>"
cnt.ConnectionString = stConn
stSQL = "SELECT 'project no' FROM 'project register"
With cnt
.CursorLocation = adUseClient
.Open stConn 'Open connection.
Set rst = .Execute(stSQL)
End With
With rst
Set .ActiveConnection = Nothing 'Disconnect the recordset.
k = .Fields.Count
vaData = .GetRows
End With
cnt.Close
With TEMPLATE
With .ComboBox1
.Clear
.BoundColumn = k
.List = Application.Transpose(vaData)
.ListIndex = -1
End With
End With
Set rst = Nothing
Set cnt = Nothing
End Sub
The sheet is called TEMPLATE and the ComboBox is called ComboBox1.
I have omitted the name of the SQL server in the connection string.
Thanks in advance.
I I'm trying to perform a loop over a variable range of cells.
A query is then run with varibles relating to the cell text.
It appears to be looping through the cells but the error lies within sql because the object is already open. I have tried to close all connections before hand but get the same error as it moves to the next cell.
Dim cell as range
dim rng as range
set rng = range("D9:D" & ActiveSheet.Cells(ActiveSheet.Rows.Count, 1).End(xlUp).Row
For each cell in rng.Cells
cell.activate
Dim CELL2 as Variant
CELL2 = Activecell
dim cnn as new adodb.connection
dim rst as new adodb.recordset
dim ConnectionString as string
dim StrQuery1 as string
dim PathID as variant
ConnectionString = ' I have inserted relevant data here'
dim xConnect as object
for each xConnect in ActiveWorkbook.Connections
xConnect.delete
Next xConnect
cnn.Open ConnectionString
cnn.CommanTimeout = 900
StrQuery1 = "Declare #DocID int Select #DocId = DocumentID from Documents where Left(Filename,10) = '" & CELL2 "'Right(Filename,6) = 'SLDDRW' Declare #PrjId int Select #PrjId = ProjectID from DocumentsinProjects where DocumentId = #DocId Select Path from Projects where ProjectID = #PrjId
rst.open StrQuery1, cnn
PathID = rst!Path
Msgbox (CELL2)
Msgbox (PathId)
dim xConnect as object
for each xConnect in ActiveWorkbook.Connections
xConnect.delete
Next xConnect
Next Cell
I would suggest using the Close method for the connection. You might also want to look into opening the connection once at the beginning, sending multiple sql commands, and closing it at the end. A quick examples is included below
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.RecordSet
Dim ConnectionString As String
cnn.Open ConnectionString
For .....
Set rst = cnn.Execute( Insert SQL String here )
do things
Next .....
rst.Close
cnn.Close
Edit: After Dan's comment, here is another way that will open and close the entire connection every time
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.RecordSet
Dim ConnectionString As String
For .....
cnn.Open ConnectionString
Set rst = cnn.Execute( Insert SQL String here )
do things
rst.Close
cnn.Close
Next .....
Hopefully the question I'm asking is clear and to be honest I'm also new to using Microsoft VBA (literally started trying to use it today). I'm trying to "grab" a query/data table from a Microsoft Access Database and I'm having difficulty understanding the syntax and exactly what commands do. At the moment it appears I'm getting into the query, but only returning the very first cell of the data table with the code:
Private Sub Select_From_Access()
Dim cn As Object
Dim rs As Object
Dim strSql As String
Dim strConnection As String
Dim placementRange As Range
'DescriptionErrorByLot is the worksheet I want to put the table in, the range A1:Z44 is what would hypothetically be cleared
'if it needed to be once there is data there and needs to be updated
Worksheets("DescriptionErrorByLot").Range("A1:Z44").ClearContents
Set cn = CreateObject("ADODB.Connection")
'This is where I want the query (table) to be placed?
Set placementRange = Worksheets("DescriptionErrorByLot").Range("A1")
'Connection string containing provider and file path to the database
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\Users\sjevne\Desktop\Database.accdb"
'Selecting the whole table from the query "jc_C2ComplaintCountbyLot10"? This is the queries name in the database
'To better explain what I'm talking about, there's buttons I can click on in the access database inside of the
'Reports section (click 'Reports' button) and then I click another button "Description errors by lot" and then
'A table/query with the name jc_C2ComplaintCountbyLot10 is open
strSql = "SELECT * FROM jc_C2ComplaintCountByLot10;"
cn.Open strConnection
Set rs = cn.Execute(strSql)
placementRange.CopyFromRecordset rs
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Basically all I'm wondering right now is, what's actually allowing me to return the first cell in the data table I'm interested in? and how can I extend the range to grab the whole thing, obviously?
Any help would be much appreciated! Thanks in advance.
EDIT 1 : Code
EDIT 2 : I've been playing around with the code again, when I tried changing the SELECT * FROM to an existing connection that I was previously using to the database query that I want, and it said something about multi-valued cells and not being able to get data from a different database. (This connection to the worksheet was previously used to make an automated table, so as database table values changed, the spreadsheet did. All I'm trying to do now is just 'copy and paste' using a macro since the previous method is no longer available, sadly.
Here is something similar grabbing the whole table, I do not bring in the field names they are already there. Don't forget when you do this the IDs are coming with the table field data.
Private Sub getDataTable_Click()
Dim conn As Object ' connection
Dim rs As Object 'record set
Dim strSql As String
Dim strConnection As String
Dim placementRange As Range
'UPDATE THIS FOR YOUR WORKSHEET AND RANGE IF YOU WANT TO CLEAR BEFORE COPY
Worksheets("mtrInteraction").Range("I2:P25").ClearContents
Set conn = CreateObject("ADODB.Connection")
'update this for the workbook,worksheet, and range where you want it
'UPDATE THIS FOR THE SHEET AND THE RANGE WHERE YOU WANT THE TABLE, UPPER LEFT CORNER
Set placementRange = Worksheets("mtrInteraction").Range("I2")
'UPDATE THIS FOR YOUR PATH AND DB NAME
'Build your connection and path
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\yourpath\yourpath\updatethis.accdb"
'UPDATE THIS FOR YOUR QUERY, TABLE NAME IS ALL YOU HAVE TO CHANGE TO COPY THE WHOLE TABLE, THE DB NAME IS SPECIFIED IN THE CONNECTION ABOVE
'Make your sql query to select all from YOUR table name
strSql = "SELECT * FROM tbl_MTR;"
'open it you might want an error handler here
conn.Open strConnection
'get the recordset
Set rs = conn.Execute(strSql)
'copy your recordset in
placementRange.CopyFromRecordset rs
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
End Sub
Here is the same thing in a stub that has the field name you want and a data value in a cell for specific targeting:
Private Sub CommandButton1_Click()
Dim inputSheet As Worksheet
Dim fieldSTR As String
Dim placementRange As Range
Dim rs As Object 'record set
Dim conn As Object
Dim strQuery As String
Dim myDB As String
Set inputSheet = ThisWorkbook.Worksheets("Sheet1")
Set placementRange = inputSheet.Range("E2")
fieldSTR = CStr(inputSheet.Cells(3, 3).Value) 'C3 cell
myDB = "C:\yourpath\yourpath\updatethis.accdb"
Set conn = CreateObject("ADODB.Connection")
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0" 'For *.ACCDB Databases
.ConnectionString = myDB
.Open
End With
strQuery = "SELECT * FROM " & _
"tbl_test WHERE Color = " & "'" & fieldSTR & "'" & ";"
'The below gives the same result as * but you could limit the fields returned as well
'tbl_test.ID, tbl_test.Color, tbl_test.number
MsgBox (strQuery)
Set rs = conn.Execute(strQuery)
placementRange.CopyFromRecordset rs
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
End Sub
This code works for me, it's stripped bare so it may not compile cleanly:
Sub LoadRecordset(Sheet1 As Worksheet, query As String)
Dim cnpubs As ADODB.Connection
Dim rsPubs As ADODB.Recordset
Set cnpubs = New ADODB.Connection
cnpubs.ConnectionString = "Driver={SQL Server};Server=TESTDS;Database=TEST1;UID=sa;PWD=WERQEWDS"
cnpubs.Open
Set rsPubs = New ADODB.Recordset
With rsPubs
.ActiveConnection = cnpubs
.Open query
fldCount = .Fields.Count
iRow = 1
Sheet1.Rows(iRow & ":" & Rows.Count).Delete
For iCol = 0 To fldCount - 1
Sheet1.Cells(iRow, iCol + 1).Value = .Fields(iCol).Name
Next
iRow = iRow + 1
Sheet1.Range("A" & iRow).CopyFromRecordset rsPubs
.Close
End With
cnpubs.Close
Set rsPubs = Nothing
Set cnpubs = Nothing
Sheet1.Cells.EntireColumn.AutoFit
End Sub
my code below, whoch I've copied from a Yahoo Developers articles and changed accordingly, for Query, I want to copy and paste 2999 rows of insert statements from excel to Teradata. My current way doesn't copy and paste the entire range. If I swap this for: Cells(1, 1) & " " & Cells(2, 1) & " " & Cells(3, 1)....etc. until Cells(2999), it would work. A clever, simpler way of doing this please?
As an aside, would you recommend an alternative method of inserting 2999 rows.
The tables are already populated, so FLOAD won't work. MLOAD or BTEQ? I'm using normal insert statements because 2999 is small enough to get away with. But, I'd always be very grateful for a q quicker solution! Thank you all!
Sub Insert_to_TD()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Dim cmdsqldata As ADODB.Command
Set cmdsqldata = New ADODB.Command
cn.Open "DSN=NNNNNN; Username=XXXXX; Password=YYYYYYY;"
Set cmdsqldata.ActiveConnection = cn 'This line says to which database it has to send the query
Query = Range(Cells(1, 1), Cells(2999, 1))
cmdsqldata.CommandText = Query 'We asign the query as command text
cmdsqldata.CommandType = adCmdText 'We just say what kind of command VBA has to execute
cmdsqldata.CommandTimeout = 0 'With this instruction we don't set any timeout, so the query can take all the necessary time to be executed
Set rs = cmdsqldata.Execute() 'VBA just run the query and send back the result
End Sub
This will cause no error, using VBA Join():
Function GetColumn1(varArray)
Dim i, i0, i1, varArrayRet
i0 = LBound(varArray, 1)
i1 = UBound(varArray, 1)
ReDim varArrayRet(i0 To i1)
For i = i0 To i1
varArrayRet(i) = varArray(i, 1)
Next
GetColumn1 = varArrayRet
End Function
Sub Insert_to_TD()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Dim cmdsqldata As ADODB.Command
Set cmdsqldata = New ADODB.Command
Dim varArray, Query
cn.Open "DSN=NNNNNN; Username=XXXXX; Password=YYYYYYY;"
Set cmdsqldata.ActiveConnection = cn 'This line says to which database it has to send the query
'
'Query = Range(Cells(1, 1), Cells(2999, 1))
'
varArray = Range("A1:A2999").Value
varArray = GetColumn1(varArray)
Query = Join(varArray, " ")
cmdsqldata.CommandText = Query 'We asign the query as command text
cmdsqldata.CommandType = adCmdText 'We just say what kind of command VBA has to execute
cmdsqldata.CommandTimeout = 0 'With this instruction we don't set any timeout, so the query can take all the necessary time to be executed
Set rs = cmdsqldata.Execute() 'VBA just run the query and send back the result
End Sub
Reserve:
Although you'd better use a for loop, insert your data line/line, it will be faster and better done than a bundled insert's.
Now we try run SQL line by line?
Sub Insert_to_TD()
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
Dim cmdsqldata As ADODB.Command
Set cmdsqldata = New ADODB.Command
Dim i, strSQL
cn.Open "DSN=NNNNNN; Username=XXXXX; Password=YYYYYYY;"
Set cmdsqldata.ActiveConnection = cn
cmdsqldata.CommandType = adCmdText
cmdsqldata.CommandTimeout = 0
'
For i = 1 To 2999
strSQL = ActiveSheet.Cells(i, 1).Value
cmdsqldata.CommandText = strSQL
Set rs = cmdsqldata.Execute()
Next
End Sub
I am trying to make an application that has the feature to import data from access into excel. I am starting with a table named ""1301 Array"" before I give user control over which table. The problem is I get the error "Cannot modify table structure. Another user has the table open", assuming because of the excel sheet I am writing in. Is there a work around to use TransferSpreadsheet for this?
Sub Importfromaccess()
Dim accappl As Access.Application
Dim strpathdb As String
Dim strpathxls As String
strpathdb = Application.GetOpenFilename("Access DataBase (*.accdb),*.accdb")
strpathxls = ActiveWorkbook.FullName
Set accappl = New Access.Application
accappl.OpenCurrentDatabase strpathdb
Dim Page As Worksheet
Dim lRow As Long, LCol As Long
Dim fullrange As String
Dim PageName As Variant
accappl.DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, "1301 Array", strpathxls, True
accappl.Quit
End Sub
The solutions I have found online mostly use sql, but I have no idea how to write in that, or how they got sql to work in excel vba. The solution below seems to do something similar to what I need, but I'm not sure how to tweak to import a table into a new sheet and give it the same name.
Sub Workbook_Open()
Dim cn As Object, rs As Object
Dim intColIndex As Integer
Dim DBFullName As String
Dim TargetRange As Range
DBFullName = "D:\Tool_Database\Tool_Database.mdb"
Application.ScreenUpdating = False
Set TargetRange = Sheets("Sheet1").Range("A1") '1301 Array after creating it?
Set cn = CreateObject("ADODB.Connection")
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & DBFullName & ";"
Set rs = CreateObject("ADODB.Recordset")
rs.Open "SELECT * FROM ToolNames WHERE Item = 'Tool'", cn, , , adCmdText
' Write the field names
For intColIndex = 0 To rs.Fields.Count - 1
TargetRange.Offset(1, intColIndex).Value = rs.Fields(intColIndex).Name
Next
' Write recordset
TargetRange.Offset(1, 0).CopyFromRecordset rs
End Sub
Update: Am going to try and use this method
Sub AccessToExcel()
'Declare variables.
Dim dbConnection As ADODB.Connection
Dim dbRecordset As ADODB.Recordset
Dim dbFileName As String
Dim strSQL As String
Dim DestinationSheet As Worksheet
'Set the assignments to the Object variables.
Set dbConnection = New ADODB.Connection
Set dbRecordset = New ADODB.Recordset
Set DestinationSheet = Worksheets("Sheet2")
'Define the Access database path and name.
dbFileName = "C:\YourFilePath\Database1.accdb"
'Define the Provider for post-2007 database files.
dbConnection.Provider = "Microsoft.ACE.OLEDB.12.0;Data Source=" _
& dbFileName & ";Persist Security Info=False;"
'Use SQL's SELECT and FROM statements for importing Table1.
strSQL = "SELECT Table1.* FROM Table1;"
'Clear the destination worksheet.
DestinationSheet.Cells.Clear
With dbConnection
'Open the connection.
.Open
'The purpose of this line is to disconnect the recordset.
.CursorLocation = adUseClient
End With
With dbRecordset
'Create the recordset.
.Open strSQL, dbConnection
'Disconnect the recordset.
Set .ActiveConnection = Nothing
End With
'Copy the Table1 recordset to Sheet2 starting in cell A2.
'Row 1 contains headers that will be populated at the next step.
DestinationSheet.Range("A2").CopyFromRecordset dbRecordset
'Reinstate field headers (assumes a 4-column table).
'Note that the ID field will also transfer into column A,
'so you can optionally delete column A.
DestinationSheet.Range("A1:E1").Value = _
Array("ID", "Header1", "Header2", "Header3", "Header4")
'Close the recordset.
dbRecordset.Close
'Close the connection.
dbConnection.Close
'Release Object variable memory.
Set dbRecordset = Nothing
Set dbConnection = Nothing
Set DestinationSheet = Nothing
End Sub
The first version won't work because you are attempting to write to the Excel file that you currently have open.
Changing to the following line (of the 2nd code) will copy the data to another worksheet:
Set TargetRange = Sheets("WhateverName").Range("A1") 'or
Set TargetRange = Sheets(2).Range("A1")
'..if you know it is the 2nd sheet that
'you want to copy to. Then,
Worksheets(2).Name = "1301 Array"
You could, alternatively, create a new sheet:
Dim wsData As Worksheet
Set wsData = Worksheets.Add
wsData.Name = "1301 Array"
Set TargetRange = wsData.Range("A1")