我管理一个SQL Server 2005数据库,我想对一组20-30个网络用户提供对必要表的只读访问权限,这些用户能够使用MS Access 2007中的GUI编写或修改自己的GUI在一些帮助下查询数据库。
我想使用单个表单分发Access数据库,该表单将创建指向必要表的链接。所有这些用户都包含在对SQL Server数据库具有只读权限的组中。我可以为连接分发dsn文件,但我还没有找到一种方法以编程方式创建指向他们可能需要的50个左右表的链接,并使用其他空的Access数据库中的网络凭据。
我发现了一行VB代码来回答类似问题onstackoverflow(下面),但是我想知道是否有更简单的方法,而不是为50个左右的表中的每一个运行修改后的命令一次。
DoCmd.TransferDatabase acLink,“ODBC数据库”,“ODBC; DRIVER = Microsoft ODBC for Oracle; SERVER = myserver; UID = myuser; PWD = mypassword”,acTable,“SCHEMA.TABLE”,“TABLE”,False,真
答案 0 :(得分:4)
我上周刚刚写了一篇article,详细介绍了一种快速将SQL数据库中的所有表链接到Access的方法。以下是一些有用的Access方法。阅读文章以获取有关使用它的更多说明。
您需要引用Microsoft ActiveX数据对象库。
Sub LinkAllTables(Server As String, database As String, OverwriteIfExists As Boolean)
'Usage Example (link all tables in database "SQLDB" on SQL Server Instance SQO01, overwriting any existing linked tables.
'linkalltables "SQL01","SQLDB", true
'This will also update the link if the underlying table definition has been modified.
Dim rsTableList As New ADODB.Recordset
Dim sqlTableList As String
sqlTableList = "SELECT [name] as tablename FROM sysObjects WHERE (type = 'U')"
rsTableList.Open sqlTableList, BuildSQLConnectionString(Server, database)
While Not rsTableList.EOF
If LinkTable(rsTableList("tableName"), Server, database, rsTableList("tableName"), OverwriteIfExists) Then
Debug.Print "Linked: " & rsTableList("tableName")
End If
rsTableList.MoveNext
Wend
rsTableList.Close
Debug.Print "Done."
End Sub
Function LinkTable(LinkedTableAlias As String, Server As String, database As String, SourceTableName As String, OverwriteIfExists As Boolean)
'This method will also update the link if the underlying table definition has been modified.
'The overwrite parameter will cause it to re-map/refresh the link for LinktedTable Alias, but only if it was already a linked table.
' it will not overwrite an existing query or local table with the name specified in LinkedTableAlias.
'Links to a SQL Server table without the need to set up a DSN in the ODBC Console.
Dim dbsCurrent As database
Dim tdfLinked As TableDef
' Open a database to which a linked table can be appended.
Set dbsCurrent = CurrentDb()
'Check for and deal with the scenario ofthe table alias already existing
If TableNameInUse(LinkedTableAlias) Then
If (Not OverwriteIfExists) Then
Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite existing table."
Exit Function
End If
'delete existing table, but only if it is a linked table
If IsLinkedTable(LinkedTableAlias) Then
dbsCurrent.TableDefs.Delete LinkedTableAlias
dbsCurrent.TableDefs.Refresh
Else
Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite an existing query or local table."
Exit Function
End If
End If
'Create a linked table
Set tdfLinked = dbsCurrent.CreateTableDef(LinkedTableAlias)
tdfLinked.SourceTableName = SourceTableName
tdfLinked.Connect = "ODBC;DRIVER={SQL Server};SERVER=" & Server & ";DATABASE=" & database & ";TRUSTED_CONNECTION=yes;"
On Error Resume Next
dbsCurrent.TableDefs.Append tdfLinked
If (Err.Number = 3626) Then 'too many indexes on source table for Access
Err.Clear
On Error GoTo 0
If LinkTable(LinkedTableAlias, Server, database, "vw" & SourceTableName, OverwriteIfExists) Then
Debug.Print "Can't link directly to table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Linked to view '" & "vw" & SourceTableName & "' instead."
LinkTable = True
Else
Debug.Print "Can't link table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Create a view named '" & "vw" & SourceTableName & "' that selects all rows/columns from '" & SourceTableName & "' and try again to circumvent this."
LinkTable = False
End If
Exit Function
End If
On Error GoTo 0
tdfLinked.RefreshLink
LinkTable = True
End Function
Function BuildSQLConnectionString(Server As String, DBName As String) As String
BuildSQLConnectionString = "Driver={SQL Server};Server=" & Server & ";Database=" & DBName & ";TRUSTED_CONNECTION=yes;"
End Function
Function TableNameInUse(TableName As String) As Boolean
'check for local tables, linked tables and queries (they all share the same namespace)
TableNameInUse = DCount("*", "MSYSObjects", "(Type = 4 or type=1 or type=5) AND [Name]='" & TableName & "'") > 0
End Function
Function IsLinkedTable(TableName As String) As Boolean
IsLinkedTable = DCount("*", "MSYSObjects", "(Type = 4) AND [Name]='" & TableName & "'") > 0
End Function
答案 1 :(得分:2)
除了David提出的建议之外,您还可以在本地(客户端)表中列出通过SQL连接可用的表列表。然后,您可以编写一段VBA代码来浏览此表以建立所有相应的连接:
Dim rsTable as DAO.recordset
set rsTable = currentDb.openRecordset("Tbl_Tables")
if rsTable.EOF and rsTable.BOF then
else
rsTable.moveFirst
Do while not rsTable.EOF
DoCmd.openDatabase .... 'enumerate here all needed paarmeters with rsTable.fields("tableName") in the string'
rsTable.moveNext
Loop
Endif
rsTable.close
set rsTable = Nothing
这段代码是动态编写的,所以我不能保证它会“按原样”工作。例如,此代码可以在启动时启动(通过autoexec宏),以便用户在打开应用程序时准备好自己的链接。
通过将相应的用户(或者,如果您有一个域,相应的用户组)列为SQL服务器上的“数据读取器”,可以轻松管理“仅查看”事物。
答案 2 :(得分:1)
如果您的SQL Server使用Windows安全性而不是SQL Server安全性,那么您不必在连接字符串中提供用户名/密码。
以下是执行此操作的标准方法:
,为您的SQL Server数据库创建一个DSN。
使用FILE |获取外部数据| LINK TABLES通过ODBC链接到表。
获取Doug Steele's code to convert to DSN-less connect strings。
然后将前端按原样分发给您的用户。
此方案的关键是使用Windows安全性而不是SQL Server安全性 - Access在通过ODBC请求连接时以无提示方式传递凭据。这是我永远不会使用SQL Server安全性的一个原因 - 太麻烦了!
答案 3 :(得分:1)
您是否有特殊原因要每次都重新创建链接? 使用链接表创建一次mdb会更简单,并将该mdb分发给您的用户 您可能还希望将SQL Server视图(而不是表)链接到Access表,以确保它是只读的,可能预先连接某些表,并消除它们不需要的某些字段。
答案 4 :(得分:1)
为什么不在Access中使用Active Data Project?
链接表实际上只在您需要本地(未链接)表时才有用。如果您可以保留SQL Server上的所有表和视图并将表单保留在Access中,则ADP将正常工作,并且不需要手动或通过脚本“链接”任何表。
为了回应下面的Patrick,如果您不希望他们在真正的SQL Server存储中创建查询,请创建第二个SQL Server数据库,他们有权创建和更新查询,并创建如下的VIEW :
CREATE VIEW mytable AS SELECT * FROM [real database].dbo.mytable
因此,当您更改主数据表时,您只需要更改其共享SQL Server数据库中的VIEW,而不是更改每个Access数据库。
方面优势#1:用户可以看到彼此的查询,从而提供轻松分享好查询的社交方面。
方面优势#2:因为它们都在一个地方,所以如果对其中一个只读表进行更改,可以使用SQL Server来检测哪些用户查询会中断(通过搜索Access创建的视图定义) )。