INSERT data from Excel into SQL DB - vba

I have created an Excel Sheet that does some lookups to format data that needs to be inserted into another table. This Excel Workbook needs to be given to some users that are free to add some new rows, and then need to be able to hit an "Insert Into Database" button and have the records transformed and inserted as new records into a SQL Table. I am using Excel 2010 and SQL Server 2008. I have a connection to the DB as I am using it to pull some data back in order to verify the new rows being added, but I'm not sure how to then insert the data back.

You can do a lot with ADO:
Dim cn As New ADODB.Connection
''You should probably change Activeworkbook.Fullname to the
''name of your workbook
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" _
& ActiveWorkbook.FullName _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
cn.Open strCon
s = "INSERT INTO [ODBC;Description=TEST;DRIVER=SQL Server;" _
& "SERVER=Server;Trusted_Connection=Yes;" _
& "DATABASE=test].SomeTable ( Col1, Col2, Col3, Col4 ) " _
& "SELECT a.Col1, a.Col2, a.Col3, a.Col4 " _
& "FROM [Sheet2$] a " _
& "LEFT JOIN [ODBC;Description=TEST;DRIVER=SQL Server;" _
& "SERVER=Server;Trusted_Connection=Yes;" _
& "DATABASE=test].SomeTable b ON a.Col1 = b.Col1 " _
& "WHERE b.Col1 Is Null"
cn.Execute s
You can also use the ACE connection: http://www.connectionstrings.com/ or OPENROWSET and an SQL Server connection. In all cases, you may have problems with mixed data types in columns, depending on your registry settings (http://forum.lessthandot.com/viewtopic.php?f=17&t=12043&p=59669&hilit=excel#p59669)

I have found out that within a macro, you can create an ADO connection by adding a reference to the "Microsoft ActiveX Data Objects 6.0 Library". Once you have opened a connection within the Macro, you can create your insert statement and execute it via using the connection.Execute(statement) method:
Dim item as String = "Insert Into MyTable(ColA,ColB) VALUES('Foo', 'Bar')"
Dim thisCon As New ADODB.Connection
thiscon.Open("ConnectionString")
thisCon.Execute (item)

After modifying the data in excel, need to generate Update statements, which will be executed by pressing the button "update". As a result, will be executed Update and Insert statements. Then have to send a query to refresh the data in Excel.(imho)

Related

How do you UPDATE SQL Table from Excel Table using VBA JOIN

I've read through postStackoverflow 14814098 and would like to know (2) things.
Can you update MS SQL Tables from Excel by creating a string with an Update statement that refers to an Excel Table. Below is a rough idea in VBA of what I mean.
If you add the SQL Statement to the server, how do you call it from Excel using VBA?
Background: I'm attempting to pull a table from the MS SQL Server, Load results into Excel Sheet as an Excel Table where I can exit the sheet and Update all changes back to the server table.
I set up a class and worksheet module to update the server after individual cells are changed in the worksheet, but now I would like to update all the changes at once.
Is there a better way to go about getting the result?
Sub UpdateSqlWithExcelTableJoin()
Dim cmd As ADODB.Command
Dim strSQL As String
Set cnn = New ADODB.Connection
cnn.ConnectionString = "DRIVER=SQL Server;SERVER=MYSERVERNAME;DATABASE=MYDATABASENAME;Trusted_Connection=Yes"
Set cmd = New ADODB.Command
cnn.Open
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdText
Call setString2
cmd.CommandText = strSQLUpdate
cmd.Execute
cnn.Close
Set cmd = Nothing
Set cnn = Nothing
End Sub
Sub setString2()
strSQLUpdate = _
"Update test.profile " & vbNewLine & _
"Set test.profile.Field = ExcelTable.Field " & vbNewLine & _
" test.profile.Profile_Name = ExcelTable.Profile_Name " & vbNewLine & _
"From test.profile " & vbNewLine & _
"INNER JOIN OPENROWSET('MICROSOFT.JET.OLEDB.4.0', 'Excel 8.0;Database=C:\Users\USERNAME\ONEDRIVE - FOLDER\SQL_VBA_b.xlsm;', 'Select ID, Profile_Name' " & vbNewLine & _
"From '[Sheet3$]') As ExcelTable " & vbNewLine & _
"ON test.profile.ID = ExcelTable.ID " & vbNewLine & _
"WHERE (test.profile.ID = ExcelTable.ID " & vbNewLine & _
" AND test.profile.Profile_Name = ExcelTable.Profile_Name)"
Debug.Print strSQLUpdate
End Sub
I always found this to be easier to run this through an MS-Access connection than to connect directly to SQL Server.
Set up an Acess data base with two ODBC connections. A. Define the Excel data as a table to Access. B. Define the SQL Server table as a table to Access.
In Excel VBA change your ADOdb connection to connect to the Access db.
Now you can run a single update statement in ODBC SQL that looks like this:
Update SQLServerTable
Set SQLServerColumn = ExcelColumn
From SQLServerTable S
Inner Join ExcelTable E
Where sqlServerkey = ExcelKey
This is more flexible than trying to do it directly because if the update relationship grows more complex you can always code the FROM clause as an Access saved query, and that is the only good way to do nested queries in ODBC (queries that use other queries in FROM).
You can't use select at that position it will always take the whole sheet.
Also you are missing a comma after Field
Update test.profile
Set test.profile.Field = ExcelTable.Field,
test.profile.Profile_Name = ExcelTable.Profile_Name
From test.profile
INNER JOIN OPENROWSET('MICROSOFT.JET.OLEDB.4.0', 'Excel 8.0;Database=C:\Users\USERNAME\ONEDRIVE - FOLDER\SQL_VBA_b.xlsm;', [Sheet3$]) As ExcelTable
ON test.profile.ID = ExcelTable.ID
WHERE (test.profile.ID = ExcelTable.ID
AND test.profile.Profile_Name = ExcelTable.Profile_Name)
ado to retrieve records from SQL
save excel file
add excel file and SQL Table in Access
create Update Query using linked tables (sql and excel)
Open workbook / update data / close workbook / run query.

VBA Excel SQL INSERT query adds apostrophe to all data inserted

I'm trying to use an INSERT statement to insert data from a userform to an excel spreadsheet, but it adds apostrophes to every inserted value, even dates and numbers.
How can I do an insert statement that will not insert any apostrophe for any value?
Code I'm using currently:
Sub Insert_data()
Dim con As Object
Dim vSQL1 As String
Dim dbpath As String
dbpath = myworkbookpath
Set con = CreateObject("ADODB.Connection")
con.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dbpath & ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=0"";"
con.Open
'CancelledFeeEntryForm.LogDate.Value = Date
'CancelledFeeEntryForm.RecordAppNum.Value = 123456789
vSQL1 = "INSERT INTO [Sheet1$] ([Employee],[Date Of Call],[Application Number]) " & _
"VALUES('" & CancelledFeeEntryForm.Employee.Value & "'," & _
"#" & CancelledFeeEntryForm.LogDate.Value & "#," & _
CancelledFeeEntryForm.RecordAppNum.Value & ");"
con.Execute (vSQL1)
con.Close
End Sub
You should've debugged and looked at what exactly vSQL1 is containing.
From looking at it, this is what your SQL statement is going to look like:
... VALUES ('SomeStringValue',#SomeDateValue,123')
... aka, there's an apostrophe at the end of the numerical value... but not at the beginning.
To be honest, I'm glad Excel VBA is handling it like this. Because the alternative would be having an open security hole for SQL Injection Attack (I was about 5 seconds away from going on a rant about how you should never do SQL statements like this, until I noticed that VBA protected you from a serious security mistake.)
Figured out a work around, although it's annoying, it'll have to do for now.
As is with excel in many cases, I had to enter dummy data on line 2 of the workbook i'm inserting data in the format I want. Then, when using the SQL insert code, it will match the existing data.
If anyone knows how to do it through code, feel free to pitch in. thanks

How to import a microsoft access query with input parameters into excel

I have to import a microsoft access query into Excel.
The issue that I have with the import is that the Microsoft Access query requires two input parameters, i.e current month and previous month.
Based on the input, the Access query will select certain values from a table that fit the criteria and then make certain calculations only for these values.
If I use the import function in Excel I receive an error which states that two inputs were expected but not given.
Any help would be appreciated greatly.
Thank you!
MS Access sql code is similar to this:
Select
table1.value,
table2.value,
table1.value * table2.value as product,
From(
select *
(from table 1 where date = current month)
inner join
select *
(from table 2 where date = previous month))
(current and previous month are popup input variables)
The Access query object cannot have dynamic parameters. Excel will have to provide the criteria. Following is an example of Excel pulling data from Access.
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset
cn.Open ""Provider=Microsoft.ACE.OLEDB.12.0; Data Source='C:\Users\June\LabData.accdb'"
strStateNum = InputBox("Enter State Number", "State Number")
rs.Open "SELECT * FROM GeoDataAll WHERE StateNum='" & strStateNum & "';", cn, adOpenStatic, adLockReadOnly
Instead of InputBox, can reference cell to provide parameter.
Your query in Excel like:
rs.Open "SELECT Q1.*, field1 * field2 AS Product FROM (" & _
"(SELECT * FROM table1 WHERE [date] = " & cell for current month & ") AS T1 " & _
"INNER JOIN " & _
"(SELECT * FROM table2 WHERE [date] = " & cell for previous month & ") AS T2 " & _
"ON T1.ID=T2.ID) " & _
"AS Q1;", cn, adOpenStatic, adLockReadOnly
Then use CopyFromRecordset method to write the data to a range on worksheet.

Getting user ID from a Spreadsheet and Access database

Why is this code not working? Sorry for the generic question....
I am tasked with generating reports with reference information that needs to be drawn from an access database and an excel spreadsheet.
Basically in my role I'm responsible for providing service to people who live in a community; the record of all the people I provide service for is contained in an access database. There's reference information; address, name, situation, and other information needed for regular reports to funders or the board of directors.
I also provide service to local businesses; this information is contained within a spreadsheet, and not a database. The information could be put into a relational database, with the two related together; but there is resistance at the organization for significant changes to the system, nor is there really the knowledge of how to do this.
So I'm trying to move forward with a spreadsheet - if I provide service to person A or organization B, that this spreadsheet will check both the access database, and the excel spreadsheet to see whether that person or organization is entered; if it is, it should populate a table with that information, and assign it a unique code.
The unique code is determined on the basis of the database; whether or not the person or organization has been entered into the database before.
The spreadsheet I am working at the base with is this:
The bottom table I am looking to be a 'lookup' table. Its name is Lookup. The code I want to run with it looks like this (but obv not is this):
Sub getUserID()
Dim myTable As ListObject
Set myTable = Sheets("Client Codes").ListObjects("Lookup")
If myTable.ListRows.Count >= 1 Then
myTable.DataBodyRange.Delete
End If
With Sheets("Client Codes").ListObjects("Lookup").Add(SourceType:=0, Source:=Array(Array("ODBC;DSN=MS Access Database;DBQ=C:\database\here\test.accdb;DefaultDir=F:\Housing;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeo"), Array("ut=5;")), Destination:=myTable.Range(Cells(1, 1)))
.CommandText = Array("SELECT Clients.ID, Clients.LastName, Clients.FirstName " & Chr(13) & "" & Chr(10) & "FROM `C:\database\here\test.accdb`.Clients Clients" & Chr(13) & "" & Chr(10) & "WHERE (Clients.LastName='" & Range("b1").End(xlDown) & "') AND (Clients.FirstName='" & Range("c1").End(xlDown) & "')")
End With
With Sheets("Client Codes").ListObjects("Lookup").Add(SourceType:=0, Source:=Array(Array("ODBC;DSN=Excel Files;DBQ=C:\spreadsheet\here\text.xlsx;DefaultDir=c:\spreadsheet;DriverId=1046;MaxBufferSize=2"), Array("048;PageTimeout=5;")), Destination:=myTable.Range(Cells(1, 1)))
.CommandText = Array("SELECT `Businesses$`.Operation" & Chr(13) & "" & Chr(10) & "FROM `C:\spreadsheet\here\test.xlsx`.`Businesses$` `Businesses$`" & Chr(13) & "" & Chr(10) & "WHERE (`Businesses$`.Operation='" & Range("b1").End(xlDown) & "')")
End With
End Sub
The hope is to be able to query the database on the basis of either a persons first and last name, or to query the spreadsheet on the basis of organization name; and if there is a value that is found, to add some information to the table 'Lookup'. If nothing is found, then I will know its a new entry, and enter in the information as such.
For reference, the database has 3 fields (ID, LastName, FirstName); and the spreadsheet has 1 column (Operation).
Really the confusion is focused here:
How to 'add' the information based on a query to the listobject to a pre-existing table
How to do this both with an access database and an Excel spreadsheet
Any suggestions on other ways how this can be done would be appreciated; pull information from multiple data sources into one table so that it can be validated in that table.
EDIT: If I did this through Access or another database program, I would do an INNERJOIN on two tables; one of people, the other of businesses. I'm looking to keep excel though - I find it to be more user friendly.
EDIT: Code based on Ian's response....generates the following error message:
'run time error -2147467259, could not find installable ISAM'
Research on the internet seems to indicate the following:
1) People have gotten this error before
2) There might not be a proper DLL installed - not certain this is the case, because I'm trying to access access from excel, and it doesn't seem like there is a DLL for access here: https://support.microsoft.com/en-us/kb/209805
3) There might be issue of how the connection string is framed. The data source might need to be in quotes, the JET OLEDB needs to be used not ACE, the connection string needs to be extended to include 'extended properties' here: Error: "Could Not Find Installable ISAM"
The last one is obviously the biggest target (and has the most error about it).
Option Explicit
Sub getUserID()
Dim cmd As New ADODB.Command
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strConn As String
Dim strSQL As String
Dim firstName As String
Dim lastName As String
firstName = "John"
lastName = "Smith"
strConn = "Provider = Microsoft.ACE.OLEDB.12.0;'DataSource=F:\Housing\bpTest.accdb'"
conn.Open strConn
strSQL = "SELECT * FROM Table Where FirstName = '" & firstName & "' AND LastName = '" & lastName & "';"
'& ... ' or You could put your InnerJoin SQL here
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
If rs.EOF Then 'If the returned RecordSet is empty
MsgBox ("No record found")
Else
MsgBox (rs.Index)
End If
end sub
You will most like want to use ActiveX Data Objects to accomplish this. This will let you to pull data from the access database and also update the records in the access database from Excel.
Here is the Microsoft reference material: https://msdn.microsoft.com/en-us/library/ms677497(v=vs.85).aspx
And some sample code:
Dim cmd As New adodb.Command
Dim conn As New adodb.Connection
Dim rs As New adodb.Recordset
Dim strConn As String
strConn = "Provider = Microsoft.ACE.OLEDB.12.0;" _
& "Data Source=C:\AccessDatabse.accdb"
conn.Open strConn
strSQL = "SELECT * FROM Table Where FristName =" & strName & ... ' or You could put your InnerJoin SQL here
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
If rs.EOF then 'If the returned RecordSet is empty
'...there is no match in database
Else
'the rs object will hold the ID you are looking for
End If
you can add a new records to the Access Database with:
myFieldList = Array("ID", "FirstName", "LastName")
myValues = Array(IDValue, FirstNameValue, LastNameValue)
rs.AddNew myFieldList, myValues

SQL/DBF Updating records from one table to another table located in different folder (*.dbf)

Updating records from one table to another table located in different folder.
Dim connection As New ADODB.Connection
Dim strConnection As String
Dim pathPrincipal As String
Dim pathUpdate As String 'External data base to update with TablePrincipal
Dim strSQL As String
pathPrincipal = "D:\DBFs"
strConnection = "Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=" & PathPrincipal
connection.Open strConnection
If connection.State <> adStateOpen Then Exit Sub
'Correct :)
strSQL="UPDATE TablePrincipal#DBF" & " A INNER JOIN " & "TableUpdate#DBF" & " B ON A.ID = B.ID SET A.X=B.X, A.Y=B.Y"
'Execute
connection.Execute strSQL, n, adCmdText
PREVIOUS CODE WORKS TO PERFECTION.....
BUT MY PROBLEM IS WHEN BOTH DBF NOT IN THE SAME FOLDER BUT I AM TRYING THIS IS NOT WHAT ELSE DO
'No working for external DBF :'( :(
strSQL = "UPDATE TablePrincipal#DBF A INNER JOIN" & _
" OPENROWSET('MSDASQL','Driver={Microsoft dBase Driver (*.dbf)}; DBQ=" & _
pathUpdate & "; SourceType = DBF ','SELECT * FROM TableUpdate#DBF') B" & _
" ON A.ID=B.ID SET A.X=B.X, A.Y=B.Y"
ANYONE CAN HELP ME.....PLEASEEEE!!!! HELP
APOLOGIES FOR MY ENGLISH :)
If the data resides on different volumes such as C:, D:, X:, Y: (or whatever mapping) you are pretty much out of luck without some adjustments...
I don't know about your path settings, but I know I've done the following working with VFP (Visual FoxPro) and using the latest OleDB Provider...
When making the connection for the data files, you SHOULD be able to reference a relative path from the connection point. However, this would only work if the data paths you are referring to are BOTH on the same logical volume...
such as
C:\SomePath\YourApplication\FirstDataFolder
C:\SomePath\YourApplication\SecondDataFolder
or even
C:\SomeOtherPath\AnotherDataLocation
if the above is SIMILAR to what your environment is, you could create a connection to
C:\SomePath\YourApplication
Then, your query should be able to do something like
update FirstDataFolder\YourTable A
JOIN SecondDataFolder\YourOtherTable B
on a.field = b.field
set ... etc
where
If the path is based on the third path sample, you would have to make your connection to C:\ by itself, then fully qualify the now "relative" paths to your data, such as:
update SomePath\YourApplication\FirstDataFolder\YourTable A
JOIN SomeOtherPath\AnotherDataLocation\YourOtherTable B
on a.field = b.field
set ... etc
where
Just use full file names (including path) in your UPDATE and SELECT queries.