I am creating an automate file to update the currency rates in the CurrencyTable (dB) on a button click. I have refer to the example as in this post.
My Excel data is as below:
CsName Rate
AUD 1.23
BHD 2.23
BND 3.23
EUR 4.23
IDR 5.23
INR 6.23
MYR 7.23
OMR 8.23
SGD 9.23
THB 10.23
USD 11.23
The code seems to work fine, however it does not updating as per the Excel data, instead, it only took the 4th row value for everything.
Here are the updated result.
Below are my codes:
Sub UpdateCR()
Dim con As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim i As Long
Dim vDB As Variant
Dim Ws As Worksheet
con.ConnectionString = "Provider=SQLOLEDB.1;Password=1234;Persist Security Info=False;User ID=Guest;Initial Catalog=ABC;Data Source=XYZ"
con.Open
Set cmd.ActiveConnection = con
Set Ws = ActiveSheet
vDB = Ws.Range("a1").CurrentRegion
For i = 2 To UBound(vDB, 1)
cmd.CommandText = "UPDATE CurrencyTable SET Rate='" & vDB(i, 2) & "' WHERE CsName ='" & vDB(i, 1) & "' "
cmd.Execute
Next i
con.Close
MsgBox "Exchange rates successfully updated"
Set con = Nothing
End Sub
Does anyone know why is this happening? Is it related to the UBound function?
Any helps on this would be much appreciated!
Are all the CSNames correct in the table you're updating? Are they all set to EUR from something else, maybe coding this. May sound obvs, but just in case :)
First of all this is not the answer, I am posting here to explain the
troubleshooting as comments won't help.
What I am saying is print the string of what is being executed in another column.
For example:
Once you try this, can you please show the image from the 3rd column?
Sub UpdateCR()
Dim con As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim i As Long
Dim vDB As Variant
Dim Ws As Worksheet
con.ConnectionString = "Provider=SQLOLEDB.1;Password=1234;Persist Security Info=False;User ID=Guest;Initial Catalog=ABC;Data Source=XYZ"
con.Open
Set cmd.ActiveConnection = con
Set Ws = ActiveSheet
vDB = Ws.Range("a1").CurrentRegion
For i = 2 To UBound(vDB, 1)
cmd.CommandText = "UPDATE CurrencyTable SET Rate='" & vDB(i, 2) & "' WHERE CsName ='" & vDB(i, 1) & "' "
cmd.Execute
Cells(i, 3) = "UPDATE CurrencyTable SET Rate='" & vDB(i, 2) & "' WHERE CsName ='" & vDB(i, 1) & "' "
Next i
con.Close
MsgBox "Exchange rates successfully updated"
Set con = Nothing
End Sub
For me the result looks like below, is it same for you?
Related
I am trying to update some records in SQL from excel sheet using VBA. I have a lot of records in the excel sheet so this is why I want to automate this. Below is a sample of the field I want to update "rmn_dr". "t_id" is unique in both tables. I want to update "rmn_dr" in the SQL "Job" table with values from "Excel Sheet"
Excel Sheet
t_id rmn_dr
310449 16
310450 120
310451 256
310452 165.2
JOB (SQL Table)
t_id rmn_dr
310449 2
310450 5
310451 7
310452 0
Can someone help me with the VBA code please? Thanks
If each field is text, try the following.
The assumption is that the data on the Excel sheet is listed from a1 Cell, including fields.
Sub setDAtaToServer()
Dim con As New ADODB.Connection
Dim cmd As New ADODB.Command
Dim rst As New ADODB.Recordset
Dim i As Long
Dim vDB As Variant
Dim Ws As Worksheet
con.ConnectionString = "Provider=SQLOLEDB.1;" _
& "Server=(local);" _
& "Database=JOB;" _
& "Integrated Security=SSPI;" _
& "DataTypeCompatibility=80;"
con.Open
Set cmd.ActiveConnection = con
Set Ws = ActiveSheet
vDB = Ws.Range("a1").CurrentRegion
For i = 2 To UBound(vDB, 1)
cmd.CommandText = "UPDATE JOB SET rmn_dr='" & vDB(i, 2) & "' WHERE t_id='" & vDB(i, 1) & "' "
cmd.Execute
Next i
con.Close
Set con = Nothing
End Sub
I am new to VBA and Excel Scripting, however, I am trying to use it to connect to an SQL Server I have created. I have built a generalized query from a userform, and created a successful SELECT statements that fill my sheet.
However, when I try to update this information in the database I am unsuccessful. The code throws no errors, but I cannot find my changes in the database. Here is my attempt:
Private Sub dbUpdate(Query)
Dim conn As ADODB.Connection
Dim recset As ADODB.Recordset
Dim cmd As ADODB.Command
Dim strConn As String
'Create the connection string
strConn = "Provider=SQLNCLI11;Server=IP-Address;Database=Info;Trusted_Connection=yes;DataTypeCompatibility=80;"
'Create the connection and recordset objects
Set conn = New ADODB.Connection
Set recset = New ADODB.Recordset
'Open the connection
conn.Open strConn
'Open the recordset with the query
'Previous attempt, no errors
'recset.Open Query, conn
'Execute the recordset
Set cmd = New ADODB.Command
'The below execution of a query throws errors I believe
cmd.CommandText = Query
Set recset = cmd.Execute
'Close things up
Set recset = Nothing
'recset.Close
conn.Close
Set conn = Nothing
End Sub
I am pretty sure the query is correct, but I will update tomorrow if I still can't figure it out.
Here is one example that could work for you.
Sub ImportDataFromExcel()
Dim rng As Range
Dim r As Long
Dim conn As ADODB.Connection
Dim strConn As String
Dim strSQL As String
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
"C:\Users\Ryan\Desktop\Coding\Integrating Access and Excel and SQL Server\Access & Excel & SQL Server\" & _
"EXCEL AND ACCESS AND SQL SERVER\Excel & Access\Select, Insert, Update & Delete\Northwind.mdb"
Set conn = New ADODB.Connection
conn.Open strConn
With Worksheets("Sheet1")
lastrow = .Range("A2").End(xlDown).Row
lastcolumn = .Range("A2").End(xlToRight).Column
Set rng = .Range(.Cells(lastrow, 1), .Cells(lastrow, lastcolumn))
End With
'therow = 1
For i = 2 To lastrow
'r = rng.Row
'If r > 1 Then
strSQL = "UPDATE PersonInformation SET " & _
"FName='" & Worksheets("Sheet1").Range("B" & i).Value & "', " & _
"LName='" & Worksheets("Sheet1").Range("C" & i).Value & "', " & _
"Address='" & Worksheets("Sheet1").Range("D" & i).Value & "', " & _
"Age=" & Worksheets("Sheet1").Range("E" & i).Value & " WHERE " & _
"ID=" & Worksheets("Sheet1").Range("A" & i).Value
conn.Execute strSQL
'End If
'r = r + 1
Next i
conn.Close
Set conn = Nothing
End Sub
There are so, so, so many different versions of this. Hopefully you can adapt this example to fit your specific needs.
I have two workbooks, call them Book1 and Book2. Book1 is open, and I am trying to get data from Book2, which is closed, into Book1. Book1 contains a column listing a corresponding element in Book2. For example, Book1 has a column of numbers that correspond to another list of numbers in Book2. I am trying to use VBA to get data from a row in Book2 with the matching number to the one in Book1.
Right now, I have the following MWE that generates an Error 91 (Object Not Set) when I try to execute the code:
Dim path As String, book As String, sheet As String
Dim targetRng As Range, sourceRng As Range
path = Left(Cells(2, 1).Value, InStrRev(Cells(2, 1).Value, "\"))
book = Dir(Cells(2, 1).Value)
sheet = Cells(2, 2).Value
Set targetRng = Range("A1").CurrentRegion
Set targetRng = targetRng.Offset(1, 0).Resize(targetRng.Rows.Count - 1) 'Ignore header row
For i = 1 To targetRng.Rows.Count
Set sourceRng = "'" & path & "[" & book & "]" & sheet & "'!" & Range("A:A").Find(targetRng.Cells(i, 1).Value) 'Error is here
targetRng.Cells(i, 2).Value = ExecuteExcel4Macro("'" & path & "[" & book & "]" & sheet & "'!" & Cells(sourceRng.Row, 2).Address)
'
'Do some other stuff
'
Next i
I was reluctant to provide an answer using the ADO because it is a broad topic. But I will provide you two examples of how you con query a Excel files using the ADO.
On the left we have the source file that we will be querying [Employees.xlsx]. On the right we workbook that we are updating [Sample.xlsm]. In my examples we are using [Sheet1] of booth workbooks. Note that the ADO will use column headers as field names (id,first_name,last_name...etc.).
In Example1 we query [Employees.xlsx] loading all the records from [Employees.xlsx]![Sheet1] into the recordset EmployeeData. Next we iterate over the id column of [Sample.xlsm]![Sheet1] and setting the filter of the recordset EmployeeData.Filter = "id=" & Cells(x, 1). Then copy the values of the records fields to the appropriate cell .Cells(x, 2) = EmployeeData.Fields("first_name")
Sub Example1()
Dim lastRow As Long, x As Long
Const adOpenKeyset = 1
Const adLockOptimistic = 3
Dim conn
Dim EmployeeData
Set conn = CreateObject("ADODB.Connection")
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=I:\stackoverflow\Employees.xlsx;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
conn.Open
On Error GoTo CloseConnection
Set EmployeeData = CreateObject("ADODB.Recordset")
With EmployeeData
.ActiveConnection = conn
.CursorType = adOpenKeyset
.LockType = adLockOptimistic
.Source = "Select * FROM [Sheet1$]"
.Open
On Error GoTo CloseRecordset
End With
With Worksheets("Sheet1")
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
For x = 2 To lastRow
EmployeeData.Filter = "id=" & Cells(x, 1)
If Not (EmployeeData.BOF And EmployeeData.EOF) Then
.Cells(x, 2) = EmployeeData.Fields("first_name")
.Cells(x, 3) = EmployeeData.Fields("last_name")
.Cells(x, 4) = EmployeeData.Fields("email")
.Cells(x, 5) = EmployeeData.Fields("gender")
.Cells(x, 6) = EmployeeData.Fields("ip_address")
End If
Next
End With
CloseRecordset:
EmployeeData.Close
Set EmployeeData = Nothing
CloseConnection:
conn.Close
Set conn = Nothing
End Sub
In Example2 we Left Join [Sample.xlsm]![Sheet1] with [Employees.xlsx]![Sheet1]. In this way, we use CopyFromRecordset to update the data for us.
Sheet1.Range("A2").CopyFromRecordset EmployeeData.
Sub Example2()
Dim lastRow As Long, x As Long
Const adOpenKeyset = 1
Const adLockOptimistic = 3
Dim conn
Dim EmployeeData
Set conn = CreateObject("ADODB.Connection")
conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
conn.Open
On Error GoTo CloseConnection
Set EmployeeData = CreateObject("ADODB.Recordset")
With EmployeeData
.ActiveConnection = conn
.CursorType = adOpenKeyset
.LockType = adLockOptimistic
.Source = "SELECT table1.id, table2.[first_name], table2.[last_name], table2.[email], table2.[gender], table2.[ip_address] FROM ( [Sheet1$] table1 LEFT JOIN `I:\stackoverflow\Employees.xlsx`.`Sheet1$` table2 ON table2.[id]=table1.[id] )"
.Open
On Error GoTo CloseRecordset
End With
Sheet1.Range("A2").CopyFromRecordset EmployeeData
CloseRecordset:
EmployeeData.Close
Set EmployeeData = Nothing
CloseConnection:
conn.Close
Set conn = Nothing
End Sub
Note: CopyFromRecordset will replace all the data in the effected columns. For this reason recommend using Example 1 until you become comfortable writing queries.
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 & "'"
OK so I have a spreadsheet that produces a reasonably large amount of records (~3500)
I have the following script that inserts them into my access db:
Sub putinDB()
Dim Cn As ADODB.Connection, Rs As ADODB.Recordset
Dim MyConn, sSQL As String
Dim Rw As Long, c As Long
Dim MyField, Result
Dim x As Integer
Dim accName As String, AccNum As String, sector As String, holding As String, holdingvalue As Double, holdingdate As Date
theend = lastRow("Holdings", 1) - 1
'Set source
MyConn = "S:\Docs\Harry\Engine Client\Engine3.accdb"
'Create query
Set r = Sheets("Holdings").Range("a2")
x = 0
Do
Application.StatusBar = "Inserting record " & x + 1 & " of " & theend
accName = r.Offset(x, 0)
AccNum = r.Offset(x, 4)
sector = r.Offset(x, 2)
holding = r.Offset(x, 1)
holdingvalue = r.Offset(x, 3)
holdingdate = r.Offset(x, 5)
sSQL = "INSERT INTO Holdings (AccName, AccNum, Sector, Holding, HoldingValue, HoldingDate)"
sSQL = sSQL & " VALUES ('" & Replace(accName, "'", "''") & "', '" & AccNum & "', '" & sector & "', '" & Replace(holding, "'", "''") & "', '" & holdingvalue & "', #" & holdingdate & "#)"
Debug.Print (sSQL)
'Create RecordSet
Set Cn = New ADODB.Connection
With Cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.CursorLocation = adUseClient
.Open MyConn
Set Rs = .Execute(sSQL)
End With
x = x + 1
Loop While r.Offset(x, 0) <> "" Or x < 15
Application.StatusBar = False
End Sub
The trouble is, is that it loops through each record one-by-one, rebuilds and executes the query each time which results in very slow execution (about 2-3 records per second on my PC)
Is there a way to have vba insert the whole range into the DB in one go without having to loop through?
Thanks
The answer you have provided should improve things slightly as you only need open the connection once, but the code is still inefficient. You really only want to write to your recordset once with all the data rather than like this. I always prefer working from the Access side to pull info from Excel as oppose to pushing into Access from Excel but I believe we can use either for this scenario.
In this case your better to use DAO over ADO and work with a Transacation, essentially you still loop over the recordset but the actual act of writing the data does not happen until you Commit at the end so it's much faster.
This is a very basic example from the Access side for you to try:
Private Sub TestTrans()
Dim wksp As DAO.Workspace
Dim rs As DAO.Recordset
Set wksp = DBEngine.Workspaces(0) 'The current database
wksp.BeginTrans 'Start the transaction buffer
Set rs = CurrentDb.OpenRecordset("Table1", dbOpenDynaset)
Do 'Begin your loop here
With rs
.AddNew
!Field = "Sample Data"
.Update
End With
Loop 'End it here
wksp.CommitTrans 'Commit the transaction to dataset
End Sub
OK, silly me. After a bit of tinkering it turns out that putting the
Set Cn = New ADODB.Connection
With Cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.CursorLocation = adUseClient
.Open MyConn
End With
bit outside the loop makes it far quicker.