具有 SQL 服务器后端查询存储最佳实践的 MS Access 前端

MS Access frontend with SQL Server backend query storing best practices

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

使用 SQL 服务器的一些流行功能,我发现了我无法自行解决的问题。

蒂亚 烟.

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

但是,CTE 在哪些方面最有用?特别是在访问上下文中? 好吧,Access SQL 的一个非常非常好的功能是在 sql 的表达式中别名列可以是 re-used。使用 T-SQL 语法,你不能!。结果非常丑陋 T-SQL.

在 Access 中进行这个典型的查询 (Access SQL) 不错(简单 + 容易)的查询:

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 服务器),我们不能使用别名列。 所以,你现在明白了:

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 不允许 re-use 列在表达式中(就像 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

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

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

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

但是,总而言之,CTE 可以用作视图,主要原因是 T-SQL 缺少 Access SQL 的可爱功能,它允许 re-use 的别名列,其中 as T-SQL 没有。因此,在尝试将 Access SQL 转换为 T-SQL 时,CTE 的问题尤为重要 - 它可以让您恢复 Access 在 sql 中具有的这种奇妙功能,以及您会非常想念的功能在 T-SQL 语法中。

Writing complicated queries in MS Access as the VBA code is pain

好吧,我不能说 .net 或大多数其他语言的代码中的 in-line 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 中丑陋的 in-line sql 当然可以通过保存此类查询而不是将其写入代码来“驯服”。我不能说如果你使用 in-line sql .net 会更好(并且因为你必须处理连接对象,命令对象,并且在大多数情况下是数据适配器?好吧,那就是.net 代码变得更加冗长,需要更多的代码然后 VBA 中的一行代码来做同样的事情。

好的,这样就可以解决您的 CTE 问题和 in-line 的问题,并在 VBA 代码中使用 SQL。

关于在Access中组织FE?那么,以最少的工作量获得最佳性能?毫无疑问,观点是必经之路。原因是 Access 玩起来非常好。

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

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

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

你这样做:

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

好吧,现在 Access 只会从网络管道中提取一条记录。不是整个table.

现在,假设我们将 BE table 迁移到 SQL 服务器? 现在,假设我们仍然将发票表格链接到链接的 table 100 万行。 当然,数据现在位于 sql 服务器中。 如何在网络管道中只拉出一排? 你可以使用这个:

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

(相同的代码)。作为clie访问t 仍然只会拉一排。尽管表单直接基于链接 table,但还是如此。所以,一般来说,access不会拉全table。它没有访问后端 (BE),如果您有链接 table 和直接绑定到 100 万行的链接 table 的表单,它也不会。

关于使用 Access 作为 sql 服务器的 FE,这里并没有太多考虑,而且你在“未来”说要使用 .net 或现在这些天一些基于 Web发展方针。

唯一真正的提示和问题是您实际上不需要或可以大量采用从 Access 到 sql 的参数的使用。但是有了 Access where 子句,那么你很少需要(所以,是的,在 Access 中使用 open form/report 的“where”子句来获得窃取性能,并限制拉到访问客户端的网络数据。所以虽然大多数开发平台都围绕基于 sql 的参数生存和死亡?Access 根本不是这些情况之一。你生存和死亡(使用很多)A​​ccess 中 where 子句的概念,因为它与 [=119 配合得很好=] 服务器并通过使用 open form/report.

的 where 子句实现仅将数据拉下您告诉访问 grab/get 的网络管道的目标

哪里可以得到“最”re-use?嗯,是的,对于复杂的 Access(客户端)查询?是的,将它们移到视图中。对于一些变得相当复杂的查询,您可以使用 Access 中的存储过程。 (这意味着 pass-though 查询)。

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

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

又是4行代码。因此,一个非常好的提示是,您是在 VBA 还是 .net 或其他任何格式中编写代码?没有 in-line 连接字符串代码。正如您在上面看到的那样,在 VBA 中,我们在代码中没有任何连接字符串 - 即使在上面使用 T-SQL 存储过程时也不需要它。

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

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

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