Jet 数据库和传递查询、参数

Posted

技术标签:

【中文标题】Jet 数据库和传递查询、参数【英文标题】:Jet Database and pass-through queries, parameters 【发布时间】:2010-08-04 07:53:04 【问题描述】:

我正在通过 ODBC 连接到 Jet 4 DB。 Jet DB 使用对 Oracle DB 的传递查询。到目前为止,这有效(无法直接访问 p-t 查询,但在查询上创建视图就可以了)。

我需要一些 p-ts 返回的数据子集。最好有参数,但不支持。

两个问题:

1) Jet 似乎确实能够将一些 where 子句推送给 Oracle。例如,我有一个返回 100k 行的直通查询。带有单个过滤子句(例如“district = '1010'”)的 p-t 视图非常快,因此处理似乎发生在 Oracle 上。添加更多子句会使查询减慢到爬行速度,在 CPU 使用率高的情况下循环数分钟。是否有任何文档说明在 Jet 端传递了什么以及做了什么?

2) 有很多关于如何使用 VBA/Access 创建动态直通查询的教程。是否可以使用通过 ODBC 访问的 Jet 来执行此操作(或任何类似的操作)?

谢谢 马丁

编辑: 抱歉这么不清楚。

我有一个通过 ODBC 访问 Jet db 的报告工具。 Jet db 包含一些数据和几个到 Oracle db 的直通查询。一个典型的用例是使用来自 Jet 和 Oracle 的数据为给定部门和给定日期生成报告。这在原则上非常有效。

问题是直通查询不能包含任何参数。直通查询就像一个视图,所以我可以简单地执行“select * from pt_query where dep = 'a' and date = somedate”。然而,Jet 从 pt 加载所有行并在客户端进行全面扫描。这对于 100k 行视图来说非常慢,我需要找到一种方法来避免这种情况。

对于 一些 简单的选择,Jet 似乎确实让 Oracle 完成了艰苦的工作并且不会加载所有行,因此我的问题是 1。

如果这不起作用,我需要找到一种方法来强制 Jet 仅从 Oracle 为给定请求加载我需要的数据。

我知道我可以通过Access VBA修改pts,但我只能通过ODBC连接,所以我只能将SQL传递给Jet,不能调用vb api(除非可以在SQL语句中内联VB)。

【问题讨论】:

如果查询Oracle,为什么需要Jet?为什么不使用 ODBC 和 ADO connectionstrings.com/oracle ? 一如既往,业务策略...我无法在 Oracle 数据仓库上创建表或上传任意数据。我正在将当前存储在 Access/Jet 中的一些自定义数据与来自 Oracle db 的数据相结合。 Jet 传递给服务器数据库的内容将取决于所涉及的服务器数据库以及 ODBC 驱动程序的编写情况。 Jet 将请求尽可能多的元数据以优化查询并将尽可能多的元数据发送到服务器进行处理。我会查看您的 SQL 跟踪,看看是什么导致了更多标准的减速。我会注意到,当我查看 SQL Server 中的跟踪时,来自 Jet 的带有条件的简单查询是使用通用参数化存储过程执行的。我希望在 Oracle 中有类似的东西。 是否允许在 Oracle DB 中链接 Access? orafaq.com/node/60 如果无法链接,可能值得一试,要么将 Oracle 标签添加到此帖子,要么使用 Oracle 标签重新发布。直通查询需要使用 Oracle 语法,因此最好使用 Oracle 观点,而不是 Jet 观点。 【参考方案1】:

构造查询导致表扫描并非不可能,这就是问题所在。

您似乎正在使用 VBA。可以在 VBA 中将许多有趣的查询构造为 SQL 字符串并将它们保存到新查询、更新现有查询、将它们用作表单的记录源或打开记录集。您可以使用 DAO 或 ADO,具体取决于您想要做什么。我有 Oracle,所以我能做的就是使用 SQL Server 提出想法,方括号中的连接可以通过查看链接表的连接 (CurrentDb.TableDefs("NameOfTable").Connect) 获得:

Dim cn As New ADODB.Connection

''You can use Microsoft.ACE.OLEDB.12.0 or Microsoft.Jet.OLEDB.4.0
scn = "Provider=Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=" _
    & CurrentProject.FullName
cn.Open scn

''An insert query, but you can see that is would be easy enough to 
''select from two different databases
s = "INSERT into [ODBC;Description=TEST;DRIVER=SQL Server;" _
& "SERVER=ServerName\SQLEXPRESS;Trusted_Connection=Yes;" _
& "DATABASE=test].Table2 (id, atext) select id, atext from table1"

cn.Execute s

或者

''http://www.carlprothman.net/Default.aspx?tabid=87
strConnect = _
    "Provider=sqloledb;" & _
    "Data Source=myServerName;" & _
    "Initial Catalog=Test;" & _
    "Integrated Security=SSPI"
With cmd
    .ActiveConnection = strConnect
    .CommandType = adCmdText
    .CommandText = "SELECT ID, aText FROM table2 " _
                 & "WHERE ID=?"
    .Parameters.Append .CreateParameter _
        ("ID", adInteger, adParamInput, , 1)
    .CommandTimeout = 0
    Set rs = .Execute
End With

【讨论】:

我不确定我是否理解您在这里所做的事情。这是否意味着您可以通过包含连接字符串在 Jet SQL 查询中打开与其他内联数据库的任意连接?如果是这样,我也可以内联传递查询吗? 是的,你可以。答案有点飘忽不定,因为我不确定您想做什么,例如,我绝对不确定您希望通过传递查询发生什么,或者为什么需要它。 如果您在直通中内联传递连接字符串,它将由远程服务器处理。这可能有效,也可能无效。 内联连接字符串可与 Jet、AFAIK 一起正常工作。我相信 OP 希望从 Jet 运行,而不是将内联字符串传递给其他数据库。 (为了更清楚,我更新了问题。)谢谢,这看起来很有希望。直通查询做了一些中等复杂的事情,我只需要根据两个条件过滤结果。那么,是否可以将要传递给指定连接的 sql 语句内联,例如(伪代码)“select * from ([connectionString].['select bla from table2 where ...']) as pt”? 【参考方案2】:

您可以在自己的数据库中复制 PT 查询,而不是在另一个数据库中链接到它吗?

PT 查询中的所有 sql 都应该在链接服务器上执行,而不需要 Jet 尝试解析或执行它。从 Jet 的角度来看,这是一门外语。

我将在 PT 中使用这样的代码:

SELECT * FROM DHSVIEWS.ClaimHeaderV    WHERE
DHSViews.claimheaderV.ClaimType = 'p'    AND
DHSViews.claimheaderV.FinalVersionInd = 'y'    AND
DHSViews.claimheaderV.ReimbursementAmount > 0    AND
DHSViews.claimheaderV.majorProgram = 'HH'    AND
DHSViews.claimheaderV.ServiceDateFrom >= [qStart]    AND
DHSViews.claimheaderV.ServiceDateFrom <=  [qEnd];

这在 VBA 中:

Set qdef = db.QueryDefs(qryPT)
sqlOld = qdef.sql
iPosStart = InStr(sqlOld, "[")
sqlNew = sqlOld
Do While iPosStart > 0
    iPosEnd = InStr(iPosStart, sqlNew, "]")
    param = Mid(sqlNew, iPosStart + 1, iPosEnd - iPosStart - 1)
    Select Case param
        Case "qStart"
            paramVal = "'" & rsQuarter("quarterStart") & "'"
        Case "qEnd"
            paramVal = "'" & rsQuarter("quarterEnd") & "'"
    End Select
    sqlNew = Mid(sqlNew, 1, iPosStart - 1) & paramVal & Mid(sqlNew, iPosEnd + 1)
    iPosStart = InStr(iPosEnd, sqlNew, "[")
Loop
If sqlNew <> sqlOld Then
    qdef.sql = sqlNew
End If
db.QueryDefs(rsPTAppend("append")).Execute
If sqlNew <> sqlOld Then
    qdef.sql = sqlOld
End If

【讨论】:

以上是关于Jet 数据库和传递查询、参数的主要内容,如果未能解决你的问题,请参考以下文章

传递查询如何在Access中使用SQL Server数据库引擎进行查询

传递查询如何在Access中使用SQL Server数据库引擎进行查询

VB6:错误 3078“... Jet 数据库引擎找不到输入表或查询...”的可能原因是啥

在选择中带有参数的参数化查询返回无效数据

MS Access/JET“不支持加入表达式”有啥方法可以修复这个查询吗?

Microsoft Jet 数据库引擎找不到输入表或查询或者找不到文件