views:

383

answers:

4

Hi all, We need to find a way to programatically *link all the tables* in a SQL Server database to an access db. We will be invoking this access database from a program that uses .net/SQL Server 2008.

While invoking the application we would like to add the linked tables so that the users can just run the reports/modules from access without having to worry about linking the tables. Is there a way we can do this?

Thanks!

A: 

You can achieve the equivalent by using a Linked Server in SQL Server that points to the Access db. This will give you access to all the tables in the Access db so that you can reference them like:

Select ..
From [LinkedServerName]...[AccessTableName]

Btw, a linked server may be overkill for what you want. Look into the OPENROWSET function which effectively let's you pass a connection string.

EDIT: I originally read the question to literally mean "link tables in SQL Server to access" which I translated to mean from SQL to Access. So, given that, my solution would apply. However, if the desire is to go from Access to SQL, then that is different and other solutions presented would be more appropriate.

Thomas
I think you read the question backwards (I did originally, too). The OP says he needs to run the Access app from .NET, not use the SQL Server for access to data that is stored in a Jet/ACE data file. But it is rather confusingly worded, I would agree.
David-W-Fenton
You are correct. Is the proper solution for me to delete my post?
Thomas
I dunno! I'm all for leaving "wrong" answers and annotating them to explain what was wrong about the answer. Somebody with the question *you* answered may end up viewing this discussion, and even though your answer doesn't help the original questioner, it could help somebody else. If I were you, I'd edit my answer to explain why it was wrong, and perhaps say something about when SQL Server linked servers are useful with Jet/ACE (such as cases where you have no drivers to get to your Jet/ACE data directly).
David-W-Fenton
A: 

You would use ADOX to do the actual linking.

As far as enumerating the tables in a database you are connected to, you could do something as simple as running this query against your SQL Server, but there are a lot of ways to skin that cat:

SELECT * FROM INFORMATION_SCHEMA.TABLES
Cade Roux
+1  A: 

Hello,

You'll need an ODBC connection to the SQL database. Once this connection ready, you can use it for all tables that you want to link:

DoCmd.TransferDatabase acLink, _
                       "ODBC Database", _
                       myODBCconnection, _
                       myDatabaseName, _
                       acTable, _
                       myTableName

I guess you can declare your ODBC connector "on the fly", as proposed here for example.

To enumerate your tables, you have the following options:

  • Enumerate them in the code: one transferDatabase line per table
  • Save the table names in a local table, and browse the table
  • Save the table names in a file (text, xml) anywhere on the network and browse the file
  • Access the system table on the server that holds the table list, and browse the table
  • Use the ADOX object to browse all tables in your database server: be carefull not to include system tables. This solution might be also quite confusing because you'll have to first open an ADODB connection to your database, and you'll then use an ODBC connection to open the tables

In all cases, this procedure shall be launched with the autoexec macro, meaning that links will be created\updated each time the user opens the mdb client.

Philippe Grondier
Good answer with the exception of the last paragraph. I would say that it depends on the application involved whether or not you run the code each time the app opens. In many cases, it should need to run only once, i.e., when you want to connect to a different SQL Server database, not every single time the app loads.
David-W-Fenton
TransferDatabase will open a pop-up window, even run from code, if the table to be connected does not have a primary key or a unique index.
Remou
@david: your proposal is right as long as the table list cannot be updated. In case the developer wants to be able to change the linked tables without changing the client (ie tables names are known through ADOX object, xml file, etc), it is mandatory to launch the 'link procedure' each time the app starts.
Philippe Grondier
@Remou: a table without primary key? You are jocking at me! Is it still allowed?
Philippe Grondier
I would not say it's "mandatory" -- I would say that's one way of doing it...
David-W-Fenton
A: 

Here are some notes.

Dim sLocalName As String
Dim tdf As TableDef
Dim rs As dao.Recordset

''This is a basic connection string, you may need to consider password and so forth
cn = "ODBC;DSN=TheDSNName;Trusted_Connection=Yes;APP=Microsoft Office 2010;DATABASE=TheDatabaseName;"

''All fields from tables
strSQL = "SELECT TABLE_CATALOG, " _
& "TABLE_SCHEMA, " _
& "TABLE_NAME, " _
& "TABLE_TYPE " _
& "FROM [" & cn & "].INFORMATION_SCHEMA.tables " _
& "WHERE TABLE_TYPE = 'BASE TABLE'"

Set rs = CurrentDb.OpenRecordset(strSQL)

Do While Not rs.EOF
    sLocalName = rs!TABLE_SCHEMA & "_" & rs!TABLE_NAME 

    With CurrentDb
        If DLookup("Name", "MSysObjects", "Name='" & sLocalName & "'") <> vbNullString Then
            If .TableDefs(sLocalName).Connect <> cn Then
                .TableDefs(sLocalName).Connect = cn
                .TableDefs(sLocalName).RefreshLink
            End If
        Else
            ''If the table does not have a unique index, you will neded to create one
            ''if you wish to update.
            Set tdf = .CreateTableDef(sLocalName)
            tdf.Connect = cn
            tdf.SourceTableName = rs!TABLE_NAME
            .TableDefs.Append tdf
            .TableDefs.Refresh

            ''This will produce a message box if the table does not have a unique index
            ''DoCmd.TransferDatabase acLink, "ODBC Database", cn, acTable, rs!TABLE_NAME, sLocalName
        End If
    End With
    rs.MoveNext
Loop
Remou