Run a excel macro with sql quicker? - sql

This code do the work but takes 10 minutes to run. There is maybe a way in the sql part to make it faster. There is not a lot of data so I uspect the sql part.
Dim noCsf As String
Dim cel As Range
Dim rng As Range
Dim noRow As Integer
Set rng = Sheets("CS_A").Range("D5:D68")
Dim targetRng1 As Range
Dim targetRng2 As Range
Dim bd As String
Dim cn As Object
Dim rs1 As Object
Dim rs2 As Object
Dim strSql As String
Dim strConnection As String
Set cn = CreateObject("ADODB.Connection")
Set rs1 = CreateObject("ADODB.Recordset")
Set rs2 = CreateObject("ADODB.Recordset")
bd = "U:\BD\Data_512_P.accdb"
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & bd
For Each cel In rng
If Len(cel.Address) = 4 Then
noRow = Right(cel.Address, 1)
Else
noRow = Right(cel.Address, 2)
End If
noCsf = cel.Value
rs1.Open "SELECT SommeDetotal_euaii FROM Rqt_CS_Anglo WHERE Expr1 LIKE '" & noCsf & "' ", cn, , , adCmdText
Set targetRng1 = Sheets("CS_A").Range("E" & noRow)
targetRng1.CopyFromRecordset rs1
rs1.Close
rs2.Open "SELECT SommeDeeua_apres_exemption FROM Rqt_CS_Anglo WHERE Expr1 LIKE '" & noCsf & "' ", cn, , , adCmdText
Set targetRng2 = Sheets("CS_A").Range("F" & noRow)
targetRng2.CopyFromRecordset rs2
rs2.Close
noRow = noRow + 1
Next
Debug.Print "DONE"
Set rs1 = Nothing
Set rs2 = Nothing
cn.Close
Set cn = Nothing
I expect a quicker running time maybe the sql part could be improve the fact in take data from a access request

Using a single query per line:
Const BD As String = "U:\BD\Data_512_P.accdb"
Dim cel As Range
Dim cn As Object
Dim rs As Object
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & BD
For Each cel In Sheets("CS_A").Range("D5:D68").Cells
rs.Open "SELECT SommeDetotal_euaii, SommeDeeua_apres_exemption FROM " & _
"Rqt_CS_Anglo WHERE Expr1 LIKE '" & cel.Value & "' ", cn, , , adCmdText
If Not rs.EOF Then
With cel.EntireRow
.Cells(5).Value = rs.Fields("SommeDetotal_euaii").Value
.Cells(6).Value = rs.Fields("SommeDeeua_apres_exemption").Value
End With
End If
rs.Close
Next cel
Depending on the size of the source table it may be quicker to build (eg) a lookup table using a scripting dictionary than to make repeated queries to the database.
If the database is on a mapped drive then creating a [temporary] local copy will likely speed things up.
If that still doesn't help then you can add more details about how many rows you're processing, are there any duplicates, and what's the size of your source DB table.

Related

'Application.Transpose(rs.GetRows)' type mismatch error Nº 13 in SQL/VBA code

I'm trying to export data from an Oracle Database through VBA, and I'm getting an error Nº 13 Type Mismatch at line:
mtxData = Application.Transpose(rs.GetRows)
below is my entire code
Sub start()
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim mtxData As Variant
Dim strSQL As String
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open ( _
"user ID =user" & _
";Password=password" & _
";data source=source" & _
";Provider=OraOLEDB.oracle")
rs.CursorType = adOpenForwardOnly
strSQL = ("SELECT * FROM table")
rs.Open strSQL, cn
mtxData = Application.Transpose(rs.GetRows)
ActiveSheet.Range("A1:K22") = mtxData
below is the result I was expecting...
You will get a type mismatch error from Transpose if the data you received via GetRows contains any null values.
There is, however, a better way to dump the data you have in a RecordSet into Excel: Simply use the method Range.CopyFromRecordSet. Advantage is you don't need the transpose, and you need to specify only the start cell.
Const connStr = "(Your connection String)"
Const sql = "(Your SQL)"
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
cn.Open connStr
Set rs = cn.Execute(sql)
With ActiveSheet
.UsedRange.Clear
.Range("A1").CopyFromRecordset rs
End With
If you need also the column names, try this:
With ActiveSheet
.UsedRange.Clear
Dim destRange As Range, colIndex As Long
Set destRange = .Range("A1")
' Write column names
For colIndex = 0 To rs.Fields.Count - 1
destRange.Offset(0, colIndex) = rs(colIndex).Name
Next colIndex
' Dump the data
destRange.Offset(1, 0).CopyFromRecordset rs
End With

Send a recordset to another macro

I have a macro for updating an SQL table in an Excel Add-in.
In order to use the same macro from multiple files I want to be able to create the recordset outside of the connection and then send it as a parameter to the update macro. Is this possible?
I have tried looking at the solutions found for in memory recordsets but these seemes to focus more on creating the columns rather than column-value pairs.
Sub test()
Dim ws As Worksheet
Dim serverName As String
Dim dataBase As String
Dim forecastDate As Date
Dim projectNum As Long
Dim SqlStr As String
Dim rst As New ADODB.Recordset
Set ws = ActiveSheet
serverName = "Servername"
dataBase = "database"
forecastDate = ws.Cells(2, "B").Value
projectNum = ws.Cells(3, "B").Value
SqlStr = "SELECT * From forecast WHERE forecastDate='" & forecastDate & "' AND projectNum = '" & projectNum & "';"
Set rst = New ADODB.Recordset
rst!forecastDate = forecastDate
rst!projectNum = projectNum
rst!Data = Cells(4, "B").Value
Application.Run "updateMacro", serverName, dataBase, SqlStr, rst
rst.Close
End Sub
'Part of the updateMacro:
Set conn = New ADODB.Connection
cs = "DRIVER=SQL Server;DATABASE=" & dataBase & ";SERVER=" & serverName & ";Trusted_connection=yes;"
conn.Open cs
'Set rst = New ADODB.Recordset
rst.Open SqlStr, conn, adOpenDynamic, adLockOptimistic 'adLockPessimistic
If rst.EOF Then
rst.AddNew
End If
'get the recordset from caller macro and update
rst.Update
rst.Close
Set rst = Nothing
conn.Close
Set conn = Nothing
I would like to create the recordset outside of the updateMacro and use it in that macro or create some sort of column-value pairs that could be copied to the recordset in the updateMacro.
You can declare the recordset as global or also pass the recordset between functions/subs. Please see code below for an example:
Option Explicit
'Global Recordset to be sued by other functions
Private rsMain As ADODB.Recordset
Public Function ImportData(ByVal fyYear As String) As Long
Dim sConnString As String, sqlYears As String
Dim conn As ADODB.Connection
Dim tCount As Long
sConnString = "Provider=SQLOLEDB;Data Source=server2;" & "Initial Catalog=FPSA;" & "Integrated Security=SSPI;"
sqlYears = "select ltrim(rtrim(FinYearDesc)) as FinYearDesc, Month, AccountType, ltrim(rtrim(AccountName))as AccountName, " & _
"ActualValue, BudgetValue from [GL_AccountMovements] where FinYearDesc >= '" & fyYear & "'"
Set conn = New ADODB.Connection
Set rsMain = New ADODB.Recordset
rsMain.CursorLocation = adUseClient
rsMain.Open sqlYears, conn, _
ADODB.adOpenForwardOnly, _
ADODB.adLockBatchOptimistic
Set rsMain.ActiveConnection = Nothing
conn.Close
If Not rsMain.EOF Then
tCount = rsMain.RecordCount
End If
ImportData = tCount
End Function
'An example of using Global Recordset
Function GetAccountsByYearMonth(ByVal strYTDLastYear as String) As Double
Dim lastYearYTDAct As Double
rsMain.Filter = strYTDLastYear
Do While Not rsMain.EOF
lastYearYTDAct = lastYearYTDAct + rsMain.Fields("ActualValue")
rsMain.MoveNext
Loop
GetAccountsByYearMonth = lastYearYTDAct
End Function
Thanks

Export from Excel to AccessDB, error Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another

I try to export some data from excel to my access database, but on line 15 rs.open I get the error Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another. I can't seem to figure out what is going wrong here. Any help would be appreciated, thanks!
Public Sub updateAntibiotics(abName As String, Optional startDate As Date, Optional stopDate As Date)
Dim cn As Object, rs As Object
Dim currPath As String, DbPath As String
Dim sProduct As String, sVariety As String, cPrice As Variant
Dim patientID As Integer
' connect to the Access database
currPath = Application.ActiveWorkbook.Path
DbPath = Left$(currPath, InStrRev(currPath, "\")) & "IZ Damiaan.accdb"
Set cn = CreateObject("ADODB.Connection")
cn.Open "Provider=Microsoft.Ace.OLEDB.12.0;Data Source='" & DbPath & "';"
' open a recordset
Set rs = CreateObject("ADODB.Recordset")
rs.Open "Antibiotics", cn, adOpenKeyset, adLockOptimistic, adCmdTable
patientID = Val(Sheets("PatientData").Range("A2"))
rs.Filter = "fkPatientID='" & patientID & "' AND Antibiotic='" & abName & "' AND stopDate IS NULL"
If rs.EOF Then
Debug.Print "No existing record - adding new..."
rs.Filter = ""
rs.AddNew
rs("fkPatientID").Value = patientID
rs("Antibiotic").Value = abName
Else
Debug.Print "Existing record found..."
End If
If Not IsNull(startDate) Then rs("startDate").Value = startDate
If Not IsNull(stopDate) Then rs("stopDate").Value = stopDate
rs.Update
Debug.Print "...record update complete."
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub

Import Selected Columns to Excel from Access Table using VBA

I am trying to import selected data from an access table. This table has 4 columns and I want only want columns 2 and 3. In Excel and want them listed in the order: column 3, column 2 (reverse to how they are in Access). Additionally I want to select rows (From Access table) based on a date referenced in the Excel Spread sheet (which I refer to as RpDate in the code). In Access, "Date" is the first column. I need some help please. Thanks.
Sub ADOImportFromAccessTable()
Dim DBFullName As String
Dim TableName As String
Dim TargetRange As Range
Dim RpDate As Range
DBFullName = "C:\Documents\Database.mdb"
TableName = "DataTable"
TargetRange = Range("C5")
RpDate = Range("B2").Value
Dim cn As ADODB.Connection, rs As ADODB.Recordset, intColIndex As Integer
Set TargetRange = TargetRange.Cells(1, 1)
' open the database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _
"C:\Documents\Database.mdb" & ";"
Set rs = New ADODB.Recordset
With rs
' open the recordset
.Open TableName, cn, adOpenStatic, adLockOptimistic, adCmdTable
' all records
.Open "SELECT * FROM " & TableName & _
" WHERE [Date] = RpDate, cn, , , adCmdText"
' filter rows based on date
rs.Open , TargetRange
End With
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
Try this
Sub ADOImportFromAccessTable()
Dim DBFullName As String
Dim TableName As String
Dim TargetRange As Range
Dim RpDate As Range
DBFullName = "C:\Documents\Database.mdb"
TableName = "DataTable"
Set TargetRange = Range("C5")
RpDate = Range("B2").Value
Dim cn As ADODB.Connection, rs As ADODB.Recordset, intColIndex As Integer
Set TargetRange = TargetRange.Cells(1, 1)
' open the database
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _
"C:\Documents\Database.mdb" & ";"
Set rs = New ADODB.Recordset
With rs
' open the recordset
.Open TableName, cn, adOpenStatic, adLockOptimistic, adCmdTable
' all records
.Open "SELECT Time, Tank FROM " & TableName & " WHERE [Date] = " & RpDate & " ORDER BY Tank, Time", cn, , , adCmdText
' filter rows based on date
End With
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
This isn't prof to SQL injection, but is a start

VBA Syntax error (missing operator) in query expression 'PopID ='

The following code throws an error when trying to run it, I presume I've managed to actually connect to the database and I have a cell selected so not sure what's missing.
ERROR:
Syntax error (missing operator) in query expression 'PopID ='.
Ideally I would like to be able to list four cells that would go into four columns in access appending each time the macro is ran
Const TARGET_DB = "testdb.accdb"
Sub AlterOneRecord() 'not working yet
Dim cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim fld As ADODB.Field
Dim MyConn
Dim lngRow As Long
Dim lngID As String
Dim j As Long
Dim sSQL As String
'determine the ID of the current record and define the SQL statement
lngRow = ActiveCell.Row
lngID = Cells(lngRow, 1).Value
sSQL = "SELECT * FROM tblPopulation WHERE PopID = " & lngID
Set cnn = New ADODB.Connection
MyConn = ThisWorkbook.path & Application.PathSeparator & TARGET_DB
With cnn
.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;"
.Open MyConn
End With
Set rst = New ADODB.Recordset
rst.CursorLocation = adUseServer
rst.Open Source:=sSQL, _
ActiveConnection:=cnn, _
CursorType:=adOpenKeyset, _
LockType:=adLockOptimistic
'Load contents of modified record from Excel to Access.
'do not load the ID again.
For j = 2 To 7
rst(Cells(1, j).Value) = Cells(lngRow, j).Value
Next j
rst.Update
' Close the connection
rst.Close
cnn.Close
Set rst = Nothing
Set cnn = Nothing
End Sub
I find it strange with them both being M$ products that this is not well documented or really really easy to perform. Maybe I'm going about it in the wrong way.
How could I make it contain cells A1 and B2 for example?
You need to quote strings
sSQL = "SELECT * FROM tblPopulation WHERE PopID = '" & lngID & "'"