0

I am trying to write a query in MS access to open a connection to a local SQL Server and then to import select tables into MS Access.

My code runs until the Cn.Execute statement. I get

Run-time error '-2471765 (80040e37)' [Microsoft][ODBC SQL Server Driver][SQL Server] Invalid Object Name 'dbo_SQLServertable'.

I need to import additional tables so I need a code that will work when I change table names.

Private Sub Command28_Click()    
        
    Dim Cn As ADODB.Connection
    Dim Server_Name As String
    im Database_Name As String
    Dim User_ID As String
    Dim Password As String
    Dim SQLStr As String
    Dim rs As ADODB.Recordset
    Set rs = New ADODB.Recordset
    
    Server_Name = "" ' Enter your server name here
    Database_Name = "Test" ' Enter your database name here
    User_ID = "" ' enter your user ID here
    Password = "" ' Enter your password here
       
    Set Cn = New ADODB.Connection
    Cn.Open "Driver={SQL Server};Server=" & Server_Name & ";Database=" & Database_Name & ";"
    
    Cn.Execute "INSERT INTO Access Table SELECT dbo_SQLServerTable.* FROM dbo_SQLServerTable;"
    
    Set rs = Nothing
    Cn.Close
    Set Cn = Nothing

I made changes and I get a new error message

Run-time error '-2147216900 (80040e14)' [Microsoft][ODBC SQL Server Driver][SQL Server] Cannot Insert the value NULL into column 'DiagnosisOrdinal', table 'Office.dbo.Test' column does not allow nulls. Insert fails.

It appears that my insert statement is still referencing (or trying to reference) a table in the SQL server. 'Office' is the database name that I am pulling from.

Do I have to close the connection and then paste the data into my local Access table? Will I then have to re-open and close the connection if I want to do this for multiple tables?

I changed my execute statement from

Cn.Execute "INSERT INTO Access Table SELECT dbo_SQLServerTable.* FROM dbo_SQLServerTable;"

to

Cn.Execute "INSERT INTO Test(VisitID, Provider) SELECT VisitID, Provider FROM dbo.SQLServerTable;"
Community
  • 1
  • 1
gbengel
  • 45
  • 7
  • Is the table name really "dbo_SQLServerTable"? probably it should be "dbo.SQLServerTable". This is first error. Probably you will get another error message about "Access Table" . Put the table into the bracket like [Access Table]. – Zeki Gumus Jan 18 '19 at 17:07
  • Also if you don't provide which columns you want to insert in insert statement that is mean [Access Table] and SQLServerTable tables has same table structure. Is this correct? – Zeki Gumus Jan 18 '19 at 17:09
  • do the target table(s) exist in Access, or are you intending for access to create a table out of the sql? – Albert D. Kallal Jan 18 '19 at 18:43
  • I first imported that table manually from SQL server as I did not want to have to list all the fields in my VBA code. I assumed that I could just run "SELECT *" as a result but perhaps that is not the case – gbengel Jan 18 '19 at 19:36
  • Well you can. The basic issue still remains, are you looking to create a new table, or append into a existing table? – Albert D. Kallal Jan 18 '19 at 19:50
  • Append into an existing one – gbengel Jan 18 '19 at 21:19
  • Ah, ok. my post below assumes you are creating tables in Access. Simple change the code - I will update my answer to include data to existing access tables. (simply use a append query in place of make table queries that my example currently has). – Albert D. Kallal Jan 18 '19 at 22:14

4 Answers4

0

You don't want the table prefix in your SELECT from the SQL table. Just do SELECT * FROM dbo_SQLServerTable; Best practice, though, is not to use SELECT * but rather specify the columns in case the table schemas ever change.

squillman
  • 13,363
  • 3
  • 41
  • 60
  • And what @ZekiGumus said about the Access table name as well. – squillman Jan 18 '19 at 17:09
  • I already have the same table structure in my access table? Would seem that I still have to spell out all the fields though? – gbengel Jan 18 '19 at 19:40
  • It's not a requirement, just something to be aware of. Sometimes column names get switched around and using `SELECT *` ends up causing an error or, even worse, dropping things into the wrong columns. – squillman Jan 18 '19 at 19:54
0

There's a few suggestions for this particular issue

  1. Pass thru queries
  2. Linked Tables from SQL Server. Youll prolly have to set up a dsn file which isnt too terribly difficult.
  3. Or handle it directly in SQL Server Insert into Access from SQL Server
  4. ODBC connection via VBA (what youre doing and seemingly the most convoluted)

All of these approaches will work fine. I suggest linked tables so you dont duplicate data but thats a cinsderation fro you since I dont knwo the requirements of the project.

Doug Coats
  • 6,255
  • 9
  • 27
  • 49
0

dbo_SQLServerTable is an Access table name, not SQL server table name. Because you already created the linked table dbo_SQLServerTable, you can use the following VBA code.

Currentproject.connection.execute "INSERT INTO MyAccessTable(fld1, fld2, fld3) SELECT fld1, fld2,fld3 FROM dbo_SQLServerTable"

There is no need to create connection object in VBA code. Currentproject.connection is always available to be referenced.

Seaport
  • 153
  • 2
  • 14
  • Thanks for the response! So all the previous lines of code can be taken out if that is the only instance of SQL server that I have running? – gbengel Jan 18 '19 at 19:37
  • Yes. That is correct. The linked table gives you the access to the SQL server table. You can either use my code, or create an Append query, which is called Action Query in Access. – Seaport Jan 19 '19 at 00:46
  • the point here is if the table is already linked, then you can JUST execute the append query. However your question suggested that the sql table in question was NOT linked. So you can either in code create a linked table to the SQL server table, or you can use the PT query. Once the linked table (or PT query) is setup, then you execute the simple append query. If the sql tables in question that you want to use for appending to local tables already exist, then you can use CurrentProject.Conneciton and not bother with the PT approach. – Albert D. Kallal Jan 22 '19 at 17:50
0

Least amount of code I can think of is to use a pass-through query.

Setup a PT query to the server database in question.

Then your code to create a new table in access would look like:

Sub TestImport()

  Dim strSQL     As String
  
  With CurrentDb.QueryDefs("qryPassR")
     .SQL = "select * from tblHotels"
  End With
  
  Dim strLocalTable  As String
  
  strLocalTable = "zoo"
  
  CurrentDb.Execute "select * into " & strLocalTable & " FROM qryPassR"
  
End Sub

The above of course assumes you setup the connection to sql server (one database) when you created the PT query. The above approach is nice since you don't mess around with connection strings in code.

However, given that you need (want) to specify the database (and likely server), then above becomes this:

Sub TestImport2()

  Dim strSQL           As String
  Dim strServer        As String
  Dim strDatabase      As String
  Dim strUser          As String
  Dim strPass          As String
  
  strServer = ""
  strDatabse = ""
  strUser = ""
  strPass = ""
  
  Dim strLocalTable       As String
  Dim strServerTable      As String
  
  With CurrentDb.QueryDefs("qryPassR")
     .Connect = dbCon(strServer, strDatabase, strUser, strPass)
     .SQL = "select * from " & strServerAble
  End With
  
  CurrentDb.Execute "select * into " & strLocalTable & " FROM qryPassR"
  
End Sub

The above uses a "handy" function to create your connection string.

That function is as follows:

Public Function dbCon(ServerName As String, _
                     DataBaseName As String, _
                     Optional UserID As String = "", _
                     Optional USERpw As String, _
                     Optional APP As String = "Office 2010", _
                     Optional WSID As String = "Import") As String

   ' returns a SQL server conneciton string
   
  dbCon = "ODBC;DRIVER=" & SQLDRIVER & ";" & _
          "SERVER=" & ServerName & ";" & _
          "DATABASE=" & DataBaseName & ";"
          If UserID <> "" Then
             dbCon = dbCon & "UID=" & UserID & ";" & "PWD=" & USERpw & ";"
          End If
          dbCon = dbCon & _
          "APP=" & APP & ";" & _
          "WSID=" & WSID & ";" & _
          "Network=DBMSSOCN"

End Function

Edit

Poster has asked for solution to append data into a EXISTING table.

In that case, simply change this:

  CurrentDb.Execute "select * into " & strLocalTable & " FROM qryPassR"

to

  CurrentDb.Execute "INSERT INTO " & strLocalTable & " SELECT * FROM qryPassR"
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Albert D. Kallal
  • 42,205
  • 3
  • 34
  • 51
  • Hey Albert, I tried to run the code but it says that your "handy" function sytanx was invalid. I am sure that I am trying to use it wrong. For reference, I am attempting to put the VB behind a button in order to allow the end user to 'refresh' the data by clicking, clearing the db, re importing, and then allowing them to work with fresh data. Does that code not work in a private button sub? Additionally, can you provide more reference to a pass through query? I have never worked with those! – gbengel Jan 21 '19 at 21:15
  • sure, but you need that dbCon() function placed in a standard code module (not a forms module). I suppose you could place the 2nd function dbCon() right inside of the forms code module, but that function is likely to be used "all over the place" in your code. – Albert D. Kallal Jan 22 '19 at 00:21
  • To create a PT query, fire up access query builder. Create a new query, and then in the ribbon hit the pass-though icon. At that point you can just save the query, since we are setting the sql right in the query. If you did not have the requirement to "often" change the source database, then you would NOT set the connection of the PT query in your code (as we are doing). The connection for the PT query will be set as the same as what you have for the linked tables. I assume you have some linked tables to sql server - you thus can include the PT queries in your re-link code. – Albert D. Kallal Jan 22 '19 at 00:26
  • To setup the connection for the PT query, hit the proptery sheet button in the ribbon. Then in the sheet, choose ODBC connect str. Hitting the […] will fire up the same ODBC connection manager you use for all linked tables. However, as noted, your case is "rare" in that your source for the PT query is going to often change - that is NOT a normal use case for most applications. – Albert D. Kallal Jan 22 '19 at 00:28
  • Albert, thank you so much for you help. I have marked this answer correct. Ultimately I determined that I will only need to connect to one server so I was able to set the connect in the pass through query. Works like a charm! Final question, I am assuming that the PT query creates a temporary connection, yes? It seems that PT as a name would imply that.... Thank you again so much!! – gbengel Jan 22 '19 at 13:58
  • Well, linked tables, PT quires often use some type of connection caching. And for linked tables or PT quires, if you execute a one time logon from Access, then all linked tables and views and PT queries thus don't need to include the user/password in the connection string. So the complexity of the caching is a rather large and broad topic. The actual PT query, or say linked table(s) when closed do release the connection, but they are pooled anyway to my knowledge. So the word "temporary" is difficult to qualify, since connection information is pooled and re-used by Access. – Albert D. Kallal Jan 22 '19 at 17:37