使用嵌套子查询优化MS ACCESS SQL

时间:2014-03-12 18:21:54

标签: sql performance ms-access optimization subquery

问题

我在MS Access数据库中工作,该数据库将发票中的条目转换为会计总帐代码。数据库有时会“拆分”记录(例如,包含单次收费的发票可能需要在几个不同的业务单位之间分配该费用)。在将“拆分”记录插入到具有INSERT INTO查询的数据库表中之后,我编写了一个SQL查询来删除“父”记录。不幸的是,我通过大多数试验和错误编写了这个,并且它运行得非常慢(我相信嵌套子查询的结果)。

如何优化此查询?

数据库插图

作为示例,如果表格包含以下内容:
[类型] ---- [收费] ---- [说明] ------------------- [发票金额]
5000 ------ NoDept ------ 40个SQL头盔-------------- $ 500

该记录的拆分可能如下:
[类型] ---- [收费] ---- [说明] ------------------- [发票金额]
5000 ------ NoDept ------ 40个SQL头盔-------------- $ 500
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 200
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 75
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 225

在我的SQL语句清理完表后,它应该像这样:
[类型] ---- [收费] ---- [说明] ------------------- [发票金额]
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 200
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 75
5000 ------ NoDept ------ 40 SQL Helmets_%Split ---- $ 225

当前SQL

DELETE * 
FROM [tblManipulateW] 
WHERE EXISTS 
    (SELECT * FROM 
        (SELECT SUM([Dupe].[Invoice Amount]) AS [SumInvoices], 
    [Dupe].[Type], 
        [Dupe].[Charge], 
        LEFT([Dupe].[Description], Len([Dupe].[Description]) - 7) As DescriptionLessSplit 
        FROM [tblManipulateW] AS [Dupe] 
        GROUP BY [Dupe].[Type], 
        [Dupe].[Charge], 
        LEFT([Dupe].[Description], LEN([Dupe].[Description])-7), 
        [Dupe].[Description] LIKE "*_%Split"
        HAVING [Dupe].[Description] LIKE "*_%Split") AS [Dupe2] 
    WHERE [Dupe2].[DescriptionLessSplit] = [tblManipulateW].[Description] 
    AND [Dupe2].[Type] = [tblManipulateW].[Type] 
    AND ROUND([Dupe2].[SumInvoices],2) = ROUND([tblManipulateW].[Invoice Amount],2) 
    AND [Dupe2].[Charge] = [tblManipulateW].[Charge]);

SQL说明

子子查询构建一个名为 Dupe2 的查询,该查询查找已拆分并返回的所有类似费用:
- 发票金额的总和
- 他们的描述少了“_%Split”这句话 - 他们的收费代码
- 他们的类型代码

子查询正在检查主表中的项何时与从子查询a.k.a.Dupe2返回的项匹配。如果某个条目与每个字段匹配,则会将其删除。

非常感谢你看看这个!

1 个答案:

答案 0 :(得分:1)

我建议在tblManipulateW表中再添加两列:自动增量主键(ID)和ParentID列(可以是null })以便拆分可以选择性地识别其父级。这就是原因。

想象一下,你有这样一个主键。并假设你的40头SQL头盔' 500美元的条目最初有ID 25。现在当您执行拆分例程时,您实际上可以将Description的所有子拆分设置为ParentID,而不是将其添加到select t1.* from tblManipulateW as t1 inner join tblManipulateW as t2 on t1.ID = t2.ParentID 。现在你可以很容易地找到所有的父分裂 - 它们是所有有孩子的分裂:

ID

此查询非常容易优化 - 事实上,如果您将Description列设置为自动增量主键,Access将自动为您执行此操作。并且还有一个额外的好处,即数据比以前更加规范化(您将父子关系存储在单独的列中,而不是添加到ParentID列的某些文本)。

附录:您可以执行一项更重要的优化:将ID列设为引用*列的外键。以下应该可以做到这一点:alter table tblManipulateW add column ParentID long constraint ManipulateW_ParentID references tblManipulateW (ID) on delete set null;

ParentID

以上完整描述了on delete set null列。最后一行(ParentID)是可选的;如果父分割被删除,它会自动将分割中的null值设置为ParentID,从而有助于保持参照完整性。

使*成为外键的好处是Access会将其作为数据库中的索引实现,这将自动加速我之前显示的连接。

CurrentProject.Connection.Execute "alter table ..."请注意,此SQL采用ANSI-92语法,Access'前端'不支持该语法。 SQL编辑器。您需要使用一点VBA执行它:{{1}}。