How to copy data from non-linked to linked table in Access 2010 using VBA - sql

So what I'm trying to do is to either copy data from an Access local table to a linked table on a SQL Server. I'd like this to work via a macro so it can be triggered upon opening a report. Or I could just bypass the linked table and insert directly to the remote server.
What I'm having a difficult time finding is the proper syntax to accomplish this. It should be very easy but apparently it's not.
Public Sub CopyPT()
Dim strSQL As String
Dim strConnect As String
Dim strDatabase As String
Dim strTableName As String
ODBC_String = "ODBC;DRIVER={SQL Server};SERVER=aaa;DATABASE=bbb;UID=ccc;PWD=ddd;" _
& "LANGUAGE=us_english;TRUSTED_CONNECTION=No"
' Id also like to truncate the Destination table here too
strSQL = "SELECT * INTO dbo_DESTINATION_TABLE IN [" & ODBC_String & "]" _
& " FROM [ACCESS_LOCAL_TABLE];"
DoCmd.RunSQL strSQL
MsgBox "Success!"
End Sub
Either I need to get the proper format for the IN statement, which doesn't appear to have ODBC option, or I need another method to copy to the linked table. Such a simple copy and paste line by line macro - which I also can't find anywhere since most sane people would just write a query.
Thanks!

Related

Insert Query/Select Query works in access, but not in vba

I have created a query that works great with no errors in Access, and while trying to translate this to my vba setup I can't figure out why I am not getting any values, even though the query clearly works in access, and causes no errors on the VBA side.
Pulling my hair out here, I have created a side table to see if I could "pseudo-insert" the calculated value, but I get the same issue as above - insert works with no errors in access, goes through in vba with no issues, but doesn't actually insert any data.
I have copied the string queries while pausing code to make sure EVERYTHING matches up between the Access query that works and the VBA query, and haven't found any differences.
I read somewhere since I am trying to pull a "first line" data piece that there may be some HDR setting that I could change, but when I tried to apply any fixes I found they opened another instance of excel and opened a dialogue box.
Please let me know what I am doing wrong here.
Public Function PullNextLineItemNumB(QuoteNum) As Integer
Dim strQuery As String
Dim ConnDB As New ADODB.Connection
Dim myRecordset As ADODB.Recordset
Dim QuoteModifiedNum As String
ConnDB.Open ConnectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data
source=" & ThisWorkbook.Path & "\OEE Info.accdb"
'Query to try and make Access dump the value "18" into the table so I can
grab it after the query is finished, sidestepping excel not working
strQuery = "INSERT INTO TempTableColm (TempColm) SELECT
MAX(MID([Quote_Number_Line],InStr(1,[Quote_Number_Line]," & Chr(34) & "-"
& Chr(34) & ")+1)) AS MaxNum from UnifiedQuoteLog where Quote_Number_Line
like '" & QuoteNum & "*'"
ConnDB.Execute strQuery
'Original query, returns "18" as expected in Access, and null or empty in
the recordset
strQuery = "SELECT MAX(MID([Quote_Number_Line],InStr(1,
[Quote_Number_Line]," & Chr(34) & "-" & Chr(34) & ")+1)) from
UnifiedQuoteLog where Quote_Number_Line like '" & QuoteNum & "*'"
Set myRecordset = ConnDB.Execute(strQuery)
Do Until myRecordset.EOF
For Each fld In myRecordset.Fields
Debug.Print fld.Name & "=" & fld.Value
Next fld
myRecordset.MoveNext
Loop
myRecordset.Close
Set myRecordset = Nothing
ConnDB.Close
Set ConnDB = Nothing
End Function
Actual output from access is "18" which is expected, output from excel's vba recordset is always null or empty string.
It appears I solved the problem, while looking into this apparently the excel operator using ADODB with access is % for LIKE and NOT * (because reasons). As soon as I made that change everything started working.
Can someone explain why that is a thing? I really want to understand why this was a design choice.

Connecting to Access 2016 from Excel 2016 with VBA

I'm very new to VBA, and I've been trying to write some code in Excel 2016 that will, when a button is pressed, take a range of cells and write them to a table that I've set up in an Access 2016 database. I'm working out of an .xlsm workbook right now.
I've been basing my code off of the bulk-insert method (building an SQL "INSERT INTO" statement) that the submitter posted as an edit to this previous StackOverflow question Using Excel VBA to export data to MS Access table .
So far, here is the VBA I have written (or at least the part of it dealing with the importing into Access). When I run it, I get the error "Run-time error '-2147467259 (80004005)': Could not find installable ISAM.". I think the issue is in my connection string, which I've been having trouble with since I can't find any examples of properly-formatted connection strings on the Internet that use Access 2016 and Excel 2016 (mostly older versions).
' Set up the transfer into Access
Dim dbPath As String, dbWb As String, dbWs As String, scn As String, dsh As String, ssql As String
Set cn = CreateObject("ADODB.Connection")
dbPath = Application.ActiveWorkbook.Path & "\MyDatabase.accdb"
dbWb = Application.ActiveWorkbook.FullName
dbWs = Application.ActiveSheet.Name
scn = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath
dsh = "[" & Application.ActiveSheet.Name & "$]" & "Data2" 'Data2 is the named range of data to be written to Access
' Open the connection with Access
cn.Open scn
' Create an SQL "Insert" statement using the name dsh developed earlier
ssql = "INSERT INTO DataPortfolio ([Field1], [Field2], [Field3]) "
ssql = ssql & "SELECT * FROM [Excel 16.0;HDR=YES;DATABASE=" & dbWb & "]." & dsh
' Execute the SQL statement
cn.Execute ssql
Can anyone see where I may be going wrong? I assume it's in the connection string (scn), but I'm not sure.
Any help is appreciated! Many thanks.

Inserting data to other xls workbook via ADO & SQL – Data type error

I am building a quite complex UserForm that uses ADO connection to connect to another Excel workbook that serves as a database and retrieve & insert data via SQL queries. Please note I am not allowed to use Access in this case.
I have already figured out how to use SELECT, but there is one particular error with INSERT I can't resolve. That bothers me a lot, I've put a lot of work to it.
First the connection (I use JET for retrieving data and ACE for saving data as I was not able to get JET to work for that):
Public Sub InsertDataToSheet(SQLCmd As String)
Dim cnx As Object
Set cnx = CreateObject("ADODB.Connection")
cnx.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source='" & ThisWorkbook.Path & "\Database.xls'; Extended Properties=Excel 12.0;"
cnx.Execute SQLCmd
cnx.Close
End Sub
Then there is a subroutine linked to a Submit button that actually generates the Query as I need to save only filled out Textboxes and Combos to avoid Nulls:
Private Sub SaveRecord()
Dim SQL As String
SQL = "INSERT INTO [Report$A2:AM50000] ("
Dim i As Control
For Each i In Me.controls
If TypeName(i) = "TextBox" Or TypeName(i) = "ComboBox" Then
If i <> e Then SQL = SQL & i.Name & ","
End If
Next i
SQL = Mid(SQL, 1, Len(SQL) - 1) & ") VALUES(" ' Remove last space & comma
Dim j As Control
For Each j In Me.controls
If TypeName(j) = "TextBox" Or TypeName(j) = "ComboBox" Then
If j <> e Then
If j = "Unknown" Then MsgBox "Fire"
Select Case IsNumeric(j)
Case False
SQL = SQL & "'" & j & "'" ' Add single quotes around strings
Case True
SQL = SQL & j
End Select
SQL = SQL & ","
End If
End If
Next j
SQL = Mid(SQL, 1, Len(SQL) - 1) & ")" ' Remove last comma
' Connect
InsertDataToSheet (SQL)
End Sub
There are two particular textboxes in the form that work exactly the same. Normally, users enter numbers to them and everything saves fine (don't mind the '+' buttons):
Sometimes, however, users do not know the values but can't leave those empty. That's when they are supposed to tick the checkboxes to set the value(s) to 'Unknown':
Now there comes the funny part – for the Batch field, it saves fine. But when I set the Shipment ID to 'Unknown' (or any other string), it throws an error:
Note the fields are not Disabled, just Locked with some appearance changes. I was also unable to find any specific details about the error, but it seems there is some problem with the query:
(It says something like 'Incompatible data types in the expression'). The generated query is this:
Any ideas what goes wrong? I'd very much like to keep the functionality as it is know and solve the error rather than redesign it as it already took some effort and the fields can't stay empty.
Never used sql in xls workbooks, but I had this problem with SQL server already. There's nothing "wrong" with your query, the problem is that data type that's accepted on the field of the table you want to insert. Try to turn that field to use text values instead of numbers and it should work.

Excel VBA Late Bind to Access and SQL Insert

I am having a frustrating issue with late binding to MS Access from Excel VBA to execute a DML statement like Insert or Update. All of the data I use in vba comes from user defined Classes. I can query just fine but writing to the DB gets different errors each time I try a different way to do the same thing. Below are some links to the same/similar issues, however each is slightly out of context and therefore I could not get passed my problem.
Microsoft.ACE.OLEDB.12.0 Current Recordset does not support updating error received when trying to update access
Operation must use an Updateable Query / SQL - VBA
Update an excel sheet using VBA/ADO
Operation must use an updatable query. (Error 3073) Microsoft Access
https://msdn.microsoft.com/en-us/library/bb220954%28v=office.12%29.aspx?f=255&MSPPError=-2147217396
http://www.access-programmers.co.uk/forums/showthread.php?t=225063
My end goal is to simply execute a DML string statement and it has to use late binding. Mainly I get the 3251 error saying my connection is 'Read Only' or a missing ISAM when I add ReadOnly=0 to the connection string. Fyi, getProjectFile just returns a path to a file starting from the parent folder of my project. I am pretty sure I can just use the connDB.Execute so I only need SQL Insert, I don't want to query first because the queries will get fat quick. I also think something might be wrong with the enum params because the ExecuteOptions want bitmasks instead of just a Long and I don't really know how to do that. From most of my research, I kept getting referred to the LockType and/or cursor not being right. For my environment; Windows 8.1 64bit, MS Office 2010 32bit(required). Does anyone see what is wrong here?
Sub ADO_Tester()
Dim strSQL, strFile, strConnection As String
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = Application.ActiveWorkbook.Path & "\" & "PortfolioDB.accdb"
strConnection = "Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
connDB.Open strConnection
'insert statement for a test record
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'execute the
connDB.Execute strSQL, , 2, 1 + 128
'clear the object
connDB.Close
Set connDB = Nothing
End Sub
Edit:
Early binding:
connDB.Execute strSQL, , adCmdText + adExecuteNoRecords
Late Binding: How to enter the value for adExecuteNoRecords? On msdn it is 0x80 and another post says &H0001,either way it gives a syntax error. It says enter a bitmask for this enum value.
connDB.Execute strSQL, , 1 + 0x80
Edit: Now the correct way -
adExecuteNoRecords (the ADO enum value) = 0x80 (a binary value) = 128 (a decimal value)
connDB.Execute strSQL, , 1 + 128
Edit: Now the issue gets even deeper. When I execute the code in a test spreadsheet into a test database, it works. When I copy and paste into the actual project spreadsheet and point to actual project db, I get the error: operation must use an updateable query . . . again. Same db name, same dml, same table name. The only difference is the actual DB is a product of a split to separate it from the forms and code in Access. Could this have changed some setting to make it read only?
Edit: It just gets deeper and deeper. The issue causing it not to work in the project db is because I have some Excel Tables querying the db. I made these through the Excel UI, Ribbon -> External Data -> Access -> etc. . . It has now become obvious these are causing me to be unable to insert DML because they are probably set to read only. How can I change the tables connections permissions? Is there another way I could be making these tables so that I can provide the connection? How to get Tables to be friendly with DML in VBA?
This worked for me:
Option Explicit
Private Const acCmdText As Integer = 1
Sub ADO_Tester()
On Error GoTo ErrorHandler
Dim strSQL As String
Dim strFile As String
'Dim adoRecSet As Object
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = getProjectFile("core", "PortfolioDB.accdb")
connDB.Open connectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
'If State = 1, db connection is okay.
MsgBox "ADO Connection State is " & connDB.State & "."
'SQL to get the whole [underlying_symbol] table
'strSQL = "underlying_symbol" 'if options 2
'strSQL = "SELECT * FROM underlying_symbol" 'if options 1
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'late bind to adodb and get recordset object
'Set adoRecSet = CreateObject("ADODB.Recordset")
'&H0001 = bitmask for aCmdText
connDB.Execute strSQL, , acCmdText
'With adoRecSet
' .Open Source:=strSQL, _
' ActiveConnection:=connDB, _
' CursorType:=1, _
' LockType:=3, _
' Options:=&H1
'.AddNew
'.fields("symbol") = "XYZ"
'.Update
'End With
'------------------
'close the objects
'adoRecSet.Close
connDB.Close
'destroy the variables
'Set adoRecSet = Nothing
Set connDB = Nothing
ExitMe:
Exit Sub
ErrorHandler:
MsgBox Err.Number & ": " & Err.Description
GoTo ExitMe
End Sub
Added some error handling, a constant that defines acCmdText (Why just not add a reference to ADO library? Up to you, though.), and a message box to check the connection state to the database, as I can't test your getProjectFile function. Late binding doesn't seem to be the issue here, I think the key line is:
connDB.Execute strSQL, , 2, &H1
Can really say what's going on here as I've never done it like this (code doesn't even compile), but changing it to
connDB.Execute strSQL, , acCmdText
worked for me.

Schema changes not updated in MS Access front end linked to the database

I created a new table in SQL server using SQL Server Management Studio but the MS Access front end linked to the database was not updated.
I tried reopening Access but still the new tables cannot be found. Yet when I check the SQL Server database they are there.
My tables in Access are linked to the database so I assumed any table or changes made in the SQL server database would be reflected in the Access front end. When I run a query in Access looking for the tables nothing is found. Another bit of information is when I right click and press view dependencies it says unable to view dependencies because
"unable to cast object of type 'System.DBNull' to type
'System.string'"
Something is maybe wrong with the way i save the query but I am not sure.
Your assumption:
I assumed any table or changes made in the SQL server database would
be reflected in the Access front end
...is not correct. Access does not automatically re-link when the SQL Server's schema changes, and it really can't. You're expecting Access assumes the data models between SQL Server and Access are the same. Even if your table and column names are exactly the same there are still differences to deal with since the data types have some differences. So, even in the best-case scenario Access does not have enough info to automatically re-link.
When you modify the SQL Server db you have to re-link from Access. Here's an article with some code that will allow you to do that quickly but note that you still have to launch it manually. And beware, as mentioned above, linking isn't that straightforward. If you use an automated method for linking the process will have to make some decisions, some of which make take you by surprise.
I have found the management of linked tables in access to be administratively tedious. In order to make my life simpler I have used the functions below that can be called to update the linked tables in access. This will take care of updating the structure of any changed table in SQL. Adding values to the SetTableNames function will bring in new tables
Private mstrTableNames(100) As String
Private const gcSQLDB as string = "MySQLServer"
Private const gcUserID as string = "SQLUserName"
Private const gcUserPassword as string = "SQLPassword"
Private const gcLiveDSN as string = "DSN"
Private const gcEmpty as string = ""
Public Function LinkLiveTables() As Boolean
Dim tdfLinked As TableDef
Dim strConnect As String
Dim intLoop As Integer
'Remove all non system tables from the application:
' !!!NB Add other exclusions so as to not delete tables that are not linked!!!
For Each tdfLinked In CurrentDb.TableDefs
If Left(tdfLinked.Name, 2) <> "MS" Then
If Left(tdfLinked.Name, 7) <> "tblTemp" Then
CurrentDb.TableDefs.Delete tdfLinked.Name
End If
End If
Next
'Create a linked table that points to SQL Server
strConnect = "ODBC;DATABASE=" & gcSQLDB & ";UID=" & gcUserID & _
";PWD=" & gcUserPassword & ";DSN=" & gcLiveDSN
SetTablesNames
For intLoop = 1 To 100
If mstrTableNames(intLoop) = gcEmpty Then GoTo ProcExit
Set tdfLinked = CurrentDb.CreateTableDef(mstrTableNames(intLoop))
With tdfLinked
.Connect = strConnect
.SourceTableName = "dbo." & mstrTableNames(intLoop)
End With
CurrentDb.TableDefs.Append tdfLinked
Next
ProcExit:
MsgBox "Connection to the LIVE tables was successful.", vbInformation
Exit Function
ProcError:
MsgBox "Link to LIVE tables Failed." & vbCrLf & vbCrLf & _
"Error Number : " & Err.number & vbCrLf & _
"Error Description : " & Err.Description, vbCritical
End Function
Private Sub SetTablesNames()
mstrTableNames(1) = "tblMoistureHist"
mstrTableNames(2) = "tblRawMaterials"
' ... add the additional table that you need as mstrTableNames(n) = "tablename"
End Sub