MS Access 前端与 SQL Server 后端查询存储最佳实践 [关闭]

Posted

技术标签:

【中文标题】MS Access 前端与 SQL Server 后端查询存储最佳实践 [关闭]【英文标题】:MS Access frontend with SQL Server backend query storing best practices [closed] 【发布时间】:2020-09-04 09:03:34 【问题描述】:

我正在尝试更好地优化我的项目组织。使用 MS Access 作为前端,使用 SQL Server 作为后端,我的目标是尽可能地分离,遵循最佳实践并带来使用不同/多个前端(web、c#、python)的能力。为了实现我的目标,我决定遵循一些设计决策:

使用视图在后端存储尽可能多的复杂查询 尽可能使用存储过程在后端进行处理 停止使用链接表,转而使用简短的查询在 VBA 代码中生成记录集。

在使用 SQL Server 的一些流行功能时,我发现了我无法自行解决的问题。

CTE 可以参数化。视图不能。存储在视图中的 CTE 怎么样?如果答案是否定的,那么有没有其他方便的方法来存储 CTE 服务器端并从 VBA 调用它来构建记录集?其他参数化查询呢? 在 MS Access 中将复杂的查询作为 VBA 代码编写是痛苦的……手指和眼睛。或许还有其他方法可以在 Access 中像老板一样存储查询? 您如何组织您的前端 - 后端应用程序,特别是如果前端是 MS Access 并且打算移动到任何其他平台时?

TYA 抽烟。

【问题讨论】:

【参考方案1】:

CTE 的零零与是否有参数有关。 CTE 与在查询上编写查询(或现在视图上的视图)的想法相同。代替必须编写(并保存)两个视图?您可以使用 CTE。

但是,CTE 在哪里最有用?特别是在访问上下文中? 嗯,Access SQL 真正非常好的特性之一是别名列可以在该 sql 的表达式中重复使用。使用 T-SQL 语法,您不能!结果是可怕的丑陋的 T-SQL。

在 Access 中使用这个典型的查询 (Access SQL) nice (simple + easy) 查询:

SELECT 
    ID, Company, State,
    (SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) as Purchased,
    (SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id) as Payments,
    (SELECT TaxRate from TaxRates where State = Customers.State) as TaxRate,
    (Purchased - Payments) as Balance,
    (Balance * TaxRate) as BalanceWithTax 

如你所见?在上面,我们使用子查询来获取购买、付款和税率。然后我们在表达式中使用这 3 个。 但是,对于 T-SQL (sql server),我们不能使用别名列。 所以,你现在明白了:

SELECT ID, Company, State,
(SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) as Purchased,
(SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id) as Payments,
(SELECT TaxRate from TaxRates where State = Customers.State) as TaxRate,
((SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) - 
(SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id)) as Balance,
( (SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) - 
(SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id)) * 
(SELECT TaxRate from TaxRates where State = Customers.State) as BAlanceWithTax
FROM Customers

以上是一个简单的例子。所以在上面,t-sql 不允许在表达式中重复使用列(就像 Access SQL 一样)。所以,以上,或者说将 Access SQL 转换为 T-SQL 是一种痛苦——简直是痛苦的。

因此,我们可以在 t-sql 中使用 CTE 来“驯服”上述内容。我们可以走了:

WITH MyCTE
AS
(SELECT ID, Company, State,
(SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) as Purchased,
(SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id) as Payments,
(SELECT TaxRate from TaxRates where State = Customers.State) as TaxRate
FROM Customers)

SELECT ID, Company, State, Purchases, Payments, TaxRate,
       (Purchases - Payments) as Balance,
       ( (Purchases - Payments) * TaxRate) as BalanceWithTax
         from mycte

现在,请注意我们仍然必须重复 balance 表达式,但至少我们现在可以在 FURTHER 表达式中使用计算的列,而不必重复它们。 因此,CTE 是一个很棒的功能,可以帮助您在 Access SQL 中转换所有那些“非常好”具有在 T-SQL 中重复(重用)任何 Alised 表达式的能力的惊人查询。

至于 CTE 和参数?他们彼此之间有零零连接。并且 CTE 与 t-sql 中的其他任何东西相比,不支持或不具有任何参数。 (所以我可以在这里看到 CTE 和参数之间没有联系)。

但是,问题的答案?您可以在视图中使用 CTE 吗?是的,你可以,而且几乎没有理由不这样做。在 CTE 之前,您可以使用一些技巧,或者(喘气)简单地创建一个视图,保存它,然后在其上创建另一个视图。因此,CTE 实际上只是一种对查询进行查询的简单方法,而无需创建单独的视图来查询。

但是,总而言之,CTE 可以用作视图,主要原因是因为 T-SQL 缺少 Access SQL 的可爱功能,它允许重用别名列,而 T-SQL 确实如此不是。因此,在尝试将 Access SQL 转换为 T-SQL 时,CTE 的问题尤为重要 - 它让您恢复了 Access 在 sql 中的出色功能,以及您将在 T-SQL 语法中非常怀念的功能。

在 MS Access 中编写复杂的查询作为 VBA 代码很痛苦

好吧,我不能说 .net 或大多数其他语言的代码中的内联 sql 也很干净。您倾向于使用字符串连接,这总是一个挑战,但我不能说在.net 开发中这样做比在 VBA 中要好得多。 但是,在大多数情况下?

将 sql 文本作为保存的查询放入 Access 中,从而在您的代码中使用它。 那么,运行我们上面的例子呢?

您可以在代码中使用它:

dim strSQL    as string
strSQL = "SELECT ID, Company, State," & _
"(SELECT SUM(Price) FROM Purchases where Customer_ID = Customers.ID) as Purchased," & 
"(SELECT SUM(Payment) FROM Payments where Customer_ID = Customers.id) as Payments," & _
"(SELECT TaxRate from TaxRates where State = Customers.State) as TaxRate," & _
"(Purchased - Payments) as Balance," & _
"(Balance * TaxRate) as BalanceWithTax " & _

dim rst     as DAO.RecordSet
set rst = CurrentDB.OpenRecordSet(strSQL)

真的不能说上面写的比用大多数其他语言写的更糟。 但是,当然可以(并且在 Access VBA 中通常会)保存该查询,因此上面的代码变成了一行代码。

例如:

set rst = CurrentDB.OpenRecordSet("qryGetBalance")

因此,VBA 中丑陋的内联 sql 当然可以通过保存此类查询而不是在代码中写出来来“驯服”。如果您使用内联 sql,我不能说 .net 会更好(因为您必须处理连接对象、命令对象,并且在大多数情况下还需要处理数据适配器?那么,.net 代码变得更加冗长并在 VBA 中使用 MORE 代码然后一行代码来做同样的事情。

好的,这样就可以解决您的 CTE 问题以及在 VBA 代码中内联和使用 SQL 的问题。

关于在 Access 中组织 FE?那么,为了获得最佳性能而做最少的工作?毫无疑问,观点是要走的路。原因是Access玩的很好。

如果您在 Access 中有一个表单。说直接绑定到链接表。在 sql server 之前,该表单将绑定到 accDB 后端。

假设有 100 万行。 假设访问后端是文件夹中的共享 accDB。 假设表单基于此链接表。

那么,在过去,您将如何启动 + 加载和显示一条记录,并且只从网络管道中拉出一条记录? 好吧,除非您将 where 子句传递给它,否则您不会启动表单。

你这样做:

dim strInvoice   as string
strInvoice = InputBox("Enter invoice number")
docmd.OpenForm "frmInvoices",,,"InvoiceNum = " & strInvoice

好吧,现在 Access 只会从网络管道中拉出一条记录。不是整张桌子。

现在,假设我们将 BE 表迁移到 SQL Server? 现在,假设我们仍然将发票表单链接到 100 万行的链接表。 当然,数据现在在 sql server 中。 如何仅从网络管道中拉出一行? 你可以使用这个:

dim strInvoice   as string
strInvoice = InputBox("Enter invoice number")
docmd.OpenForm "frmInvoices",,,"InvoiceNum = " & strInvoice

(相同的代码)。作为客户端访问仍然只会拉一行。尽管表单直接基于链接表。因此,作为一般规则,访问不会拉动整个表。它没有访问后端 (BE),如果您有一个链接表和一个直接绑定到该链接表的 100 万行的表单,则不会。

这里没有太多考虑将 Access 作为 FE 到 sql 服务器,并且您在“未来”说使用 .net 或现在一些基于 Web 的开发方法。

唯一真正的提示和问题是,您实际上不需要或可以采用从 Access 到 sql 的参数的使用。但是使用 Access where 子句,那么无论如何您都很少需要(所以,是的,使用 Access 中打开表单/报告的“where”子句来获得窃取性能,并限制拉到访问客户端的网络数据。所以虽然大多数开发平台围绕基于参数的 sql 生死存亡?Access 根本不是这些情况之一。你生死(使用很多)A​​ccess 中 where 子句的概念,因为它与 SQL server 配合得很好,达到了只拉动的目标使用打开表单/报告的 where 子句告诉 Access 抓取/获取的网络管道中的数据。

在哪里可以获得“最多”的重复使用?嗯,是的,对于复杂的 Access(客户端)查询?是的,移动它们以查看。对于一些变得相当复杂的查询,您可以在 Access 中使用存储过程。 (这意味着传递查询)。

那么,在访问中,假设我们有一个复杂的发票检索,其中涉及复杂的连接和大量查询?然后你可以创建一个存储过程,然后从访问中使用它来获取数据:

with CurrentDB.queryDefs("ptGetIvnoice")
   .SQL = "Exec GetInoice " & strInvoice
   rst = .OpenRecordSet
end with

再一次,4 行代码。所以,一个非常好的提示是你用 VBA 或 .net 或其他什么方式编写代码?没有内联连接字符串代码。正如您在上面看到的,在那个 VBA 中,我们在代码中没有任何连接字符串 - 即使在上面使用 T-SQL 存储过程时也不需要它。

所以,是的,使用视图意味着您的 asp.net 或您最终采用的任何系统都允许您使用保存在 SQL Server 端的相同视图,从而访问,或者 Web 或任何其他软件可以使用相同的视图.

另一个问题是访问将与视图很好地配合,您很少需要在 T-SQL 中采用存储过程来进行基于参数的查询。原因当然是 Access 有我上面提到的“where”子句。没有 T-SQL 参数,并且在 access(where 子句)中向链接视图添加条件将与存储过程一样执行,但没有 Access 一开始就不能很好支持的 missay 参数。

因此,视图在 Access 开发中接近顶峰,因为 Access 与它们配合得非常好,这也意味着当您采用 asp.net 或其他任何目标时,这些视图可以被重用更换访问。但是,当您的后端是 sql server 时,Access 确实是一个很棒的 RAD 工具。因此,当您这样做时,您可以获得良好的可扩展性、更好的安全性,当然还有 asp.net 甚至其他桌面开发平台使用这些数据。通常在将 Access 数据移动到 sql server 之后,公司会发现几乎不需要放弃访问,因为所有这些表单、报告和代码都可以继续使用,同时采用基于 Web 的技术。

【讨论】:

哇。这真太了不起了。你在这个答案上付出了很多努力,我非常感谢。你指出了一些我什至没有意识到也没有理解的非常重要的话题。 CTE 是我的主要观点,因为在我的几个查询中使用了递归。我只是想使用参数来控制递归开始的级别。这个答案肯定让我对这个主题更加清晰。再次感谢您的耐心和清晰的解释。

以上是关于MS Access 前端与 SQL Server 后端查询存储最佳实践 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

多个 MS Access 前端连接到单个远程 SQL Server 后端

SQL Server 2008r2 <--> 前端 MS Access 的最佳版本

ODBC:用于 MS Access 的 SQL Server 2008 驱动程序

MS Access 直通选择查询导致 SQL Server 中的页面锁定

如何通过 MS ACCESS 表执行 SQL Server 表的批量更新

SQL Server 后端和 Access 前端 - 与 SQL Server 本机客户端的 ODBC 连接失败