在 MS Access 中,为什么 SQL 字符串用作查询而不用作报表的 RecordSource?

In MS Access, why would a SQL string work as a Query but not as a RecordSource of a Report?

我的问题:为什么 SQL 字符串可以正常用作查询而不是报表的 RecordSource?

对于冗长的背景,我深表歉意,但我认为出现此问题的背景可能会有所帮助。在 Access 2019 中,我有一个基于 多个 其他查询的 MainQuery,其中一些是参数查询。因此,MainQuery 本身不包含任何参数作为其定义的一部分,但由于其“组成查询”包含提示用户输入的参数,运行ning MainQuery 会提示用户输入所述参数值。请注意,我称它们为“组成查询”,因为它们都是我数据库中的独立查询对象,而不是 MainQuery 中的真正子查询。

MainQuery 是MainReport 的RecordSource。当然,在打开 MainReport 时,系统会提示用户输入允许 MainQuery(即其所有组成查询)的参数 运行。当然,用户必须每次重新打开或刷新 MainReport 并提供不同的参数值才能在 MainReport 中看到不同的数据集。

这种安排多年来一直运作良好,并将继续发挥作用,但我最近决定通过允许用户快速连续打印多个 MainReport 报告(针对不同的记录)来增加数据库的功能。

我使用的策略是将 MainQuery 及其所有组成查询合并为一个大型、复杂的 MasterQuery,由其中定义的合法子查询组成。以前每次 MainQuery 运行 时都会提示用户的参数被简单的字符串占位符替换,MasterQuery 的整个主体保存在 SQL_Table 中,这样我的 VBA代码可以访问它。现在,用户可以 select 他或她希望在为此目的设计的表格上打印的记录。然后,单击按钮后,我的 VBA 代码收集用户的选择,从 SQL_Table 中检索模板 SQL 字符串,并为用户想要打印的每条记录替换字符串SQL 字符串中的占位符(以前称为参数)并将 MainReport 的 RecordSource 分配给该 SQL 字符串。

因为我在上周左右的时间里从事这个项目,所以我能够让这个过程非常漂亮和成功地工作。但是,随着我继续开发它,我最终对 MainReport 和 MasterQuery 进行了一些添加和更改以改进数据库的功能。

所以,目前的情况是我成功地将 SQL 字符串传递给报告的 RecordSource 属性,但问题是 Access 告诉我在SQL 字符串,它实际上不会 运行 报告。相反,报表停留在设计模式中,不会进入报表视图。错误消息说,

Syntax error in query. Incomplete query clause

在尝试诊断问题时,我采用了完全相同的 SQL 字符串(我从字面上将其从报告的 RecordSource 属性 复制并粘贴到 SQL 视图中空白查询),令我惊讶的是,查询 运行 非常漂亮。它 returns 我希望看到的结果集。作为奖励,我什至将查询保存为 Query1,并将 MainReport 的 RecordSource 设置为 Query1,甚至这样也有效!

我不明白这种行为。我可能认为它们要么都使用相同的 SQL 字符串,要么都不起作用,但我不明白为什么它们的行为可能不同;这就是我问题的症结所在。

那么,为什么 SQL 字符串可以正常用作查询而不是报表的 RecordSource?

提前感谢任何可能有任何想法的人!

嗯,由于原始形式的查询不会 运行,并且您完全指出您“替换了该查询中的值?

并且由于您还指出您正在替换报告查询源(并且您可能想展示并解释您是如何做到的?

所以,假设您每次都将修改原始查询?然后,如果您修改它一次,那么就很明显,那么该报告(标准)中的值将被更改。所以,它也不清楚你是如何处理这个问题的?

在大多数情况下,由于原始格式的查询具有您要替换的“值”,因此理论上这些值需要“已知”以便您可以重新替换它们。

因此,作为上述的一般方法?

我将原始查询保存在查询生成器中,然后复制该查询,进行条件替换,然后将该查询保存到第二个查询 - 报告所基于的查询。

假设我们有一个简单的查询和报告。

 qryHotelsS     (I put a "s" on such querys - means "source"
 qryHotels      (the final fixed up and changed query).

所以,假设我有这个:

SELECT * FROM tblHotels WHERE City = '@City' ORDER BY HotelName.

所以,我现在可能有一些非常好的提示表单,或者允许用户输入城市标准,然后点击查看报告按钮的表单。

代码将如下所示:

 Dim strSQL         As String
 Dim strCity        As String   ' for test - the value would no doubt come
                                ' from a very nice form wiht a text box, and
                                ' button to launch the report.
                                
 
 strSQL = CurrentDb.QueryDefs("qryHotelsS").SQL
 
 strCity = "Calgary"        ' as noted, this would be some text box value on
                             ' a nice report form
                             
 strSQL = Replace(strSQL, "@City", strCity)
 
 CurrentDb.QueryDefs("qryHotels").SQL = strSQL
 
 
 DoCmd.OpenReport "rptHotels", acViewPreview

因此,我们获取“源”查询,替换我们想要的值,然后将查询保存到报告所基于的查询,然后简单地启动该报告。

我的意思是,这真的取决于您现在如何替换和设置查询?上面的真正好的功能?您可以 运行 代码(注释掉上面的打开报告命令)。一旦你 运行 上面的代码,你就可以很自由地打开报表并进一步设计和调整报表,因为它有一个有效的查询源,你就可以自由地设计、更改和设置以任何您想要的方式报告。 (因为它有一个有效的 sql 查询源)。

因此,采用对报告进行两次查询的想法。 “源”查询 - 使用您在 VBA 代码中替换的一些值。我突然使用了“@City”,所以我使用了@符号,您可以随心所欲地使用自己的符号。您甚至可以保留 [] 并让 VBA 替换 [],但我喜欢为此使用 @ 符号。它甚至适用于日期。

例如:

 WHERE InvoiceDate = #@InvoiceDate#

因此,在代码中,您可以将@InvoiceDate 替换为日期字符串,但不需要添加分隔符(#)。

编辑:为什么某些查询无法在代码中运行?

好吧,如果您可以获取该字符串,将其推送(保存)到查询中,然后 运行 关于该查询的报告,那么这就可以了。

但是,使用 DAO 对象模型和将 sql 推入 reocrdset 与基于表单或基于同一源的查询之间存在显着差异。

记住,DAO 记录集对象不允许也不知道表单!表达式等,不能用

如果你在 sql 中引入任何 VBA 功能?再一次,您不能使用 DAO querydef 对象。

纯数据引擎 (DAO) 可以从 vb6、vb.net、c# 等使用。因此数据引擎不允许使用示例表单!表达式,它还不允许在 sql.

中使用自定义 VBA 函数

所以,基于已保存的查询定义进行重现?没问题,两种形式!表达式,甚至 VBA 函数都可以包含在 sql 查询中。

但是,如果您尝试使用 SAME 查询并将其推送到 DAO 记录集中?然后是所谓的“表达”服务。 (解析表单!表达式和解析 VBA 函数调用的系统)无法使用。

这是因为数据库引擎 (JET/ACE) 不知道 VBA,不知道 abut forms!,它是一个独立的数据引擎,并且数据引擎不限于与 Access 一起使用,但如前所述,可以从 FoxPro、vb.net、c#、vb6 等中使用。因此,纯 DAO 数据引擎调用没有也不允许形式!表达式,如前所述,甚至不允许您使用 VBA 表达式。它必须是 100% 有效的 JET ONLY sql 语法。因此,虽然 JET sql 中存在一些函数,但很多 VBA 函数是不允许的。

JET 数据库引擎因此甚至不知道也不假设表单!对象存在,可以打开或关闭,VBA 中使用的函数也是如此 sql - 事实上它们不能使用。

那么,如果您将此类表达式放入查询中并使用 from MS-ACCESS?然后查询可以从UI运行,可以作为报表的数据源,但是在纯VBA代码中,设置相同的查询到一个DAO记录集对象会失败.

所以,最好是:

Figure out if you have any VBA functions used in the sql
Figure out if you have any forms! expressions used in the sql

然后把上面的去掉。

但是,你可能会在处理那些混乱的问题时遇到一些困难 sql,所以你可以直接解决这个问题将字符串放入 querydef ojbect(将其保存到 .SQL 属性 中,就像我上面所做的那样),然后简单地将报告基于已保存的查询,而不是尝试在代码中创建 DAO 记录集对象,并将其用于表单 reocrdsource,正如我在上面指出的那样不能使用表单!或 VBA 函数 - 并且必须是没有此类表达式的纯有效 JET/ACE 语法。