我有一个实现SQL的Access项目,我一直在努力优化协调过程。此过程使用凭证系统将所有表链接在一起。 每个表中的每个记录都有一个特定的凭证ID,其中包含金额。 优惠券本身是独一无二的,可以包含多个优惠券号码,如下所示。
Table: Rec_Vouchers
v_id v_num voucher
1 12341234 12341234
2 10101010 10101010;22222222
2 22222222 10101010;22222222
...
我有8个其他表格,这些表格通过这些凭证ID链接。我正在尝试将所有表连接在一起,以显示distict凭证ID和凭证以及具有该特定凭证ID的每个表的所有相应金额总和。以下是查询和结果示例。我已经在这方面工作了一段时间,它开始让我头疼。此查询有效,但需要长时间执行。
此外,在某些时候,我需要将所有这些值匹配在一起,以确定凭证是“匹配”,“不匹配”还是“匹配差异”。到目前为止,我只尝试在下面的代码中创建一个函数,该函数将返回字符串值“M”,“NM”或“MwD”以显示在每个凭证的列中。同样,这可行,但需要很长时间。我也试过让VBA使用查询的返回记录集进行脏工作,这也需要花费大量时间,但不能在我的sql查询中创建函数。这是下一步,所以如果你可以帮助解决所有这些问题,那么我真的只需要优化我给出的查询。
我知道要解决这个问题很多,所以如果您需要更多信息,请告诉我。任何帮助,将不胜感激。谢谢!
select a.v_id, a.voucher,
(Select sum(b.amount) from rec_month_4349_test b where b.voucher = a.v_id) as GL,
(Select sum(c.payments) from rec_daily_balancing_test c where c.voucher = a.v_id) as DB,
(Select count(x.v_num) from rec_vouchers x where a.v_id = x.v_id and x.v_num not like 'ONL%') as GLcount,
(select count(c.batch_num) from rec_daily_balancing_test c where a.v_id = c.voucher) as DBcount,
(select sum(d.amount) from rec_ed_test d where a.v_id = d.voucher) as ED,
(select sum(e.batchtotal) from rec_eft_batches_new_test e where a.v_id = e.voucher) as EFT,
(select sum(f.batchtotal) from rec_check_batch_test f where a.v_id = f.voucher) as CHK,
(select sum(g.idxtotal) from rec_lockbox_test g where a.v_id = g.voucher) as LBX,
(select sum(h.amount) from rec_lcdl_test h where a.v_id = h.voucher) as LCDL,
((select sum(i.payment_amount) from rec_electronic_files_test i where a.v_id = i.voucher) + (select sum(j.amount) from rec_electronic_edits_test j where a.v_id = j.voucher)) as Elec
from rec_vouchers a
group by a.v_id, a.voucher
Sample Results:
v_id GL DB GLcount DBcount ED EFT CHK LBX LCDL Elec
6131 19204.00 19204.00 1 1 NULL NULL NULL NULL NULL NULL
6132 125330.00 14932.00 6 6 NULL NULL NULL NULL NULL 14932.00
6133 18245.00 NULL 2 0 NULL NULL NULL NULL NULL NULL
6175 98.93 98.93 1 1 NULL 98.93 NULL NULL NULL NULL
答案 0 :(得分:0)
很容易说,编写此查询的“传统”方法是使用from
谓词将表移动到join
子句。但是,这可能会引入不必要的笛卡尔积。你的方法确实没问题;替代方案是对聚合子查询进行left join
。
表现上的杀手可能是因为在桌子上骑自行车以找到比赛。通过在每个查询的where
子句中使用字段索引,可以显着提高性能。例如,对于前两个表,您应该在rec_month_4349_test(voucher)
和rec_daily_balancing_test(voucher)
上建立索引。
在SQL Server中,您还可以通过在索引中包含用于求和的变量来进一步优化此查询。以下索引会更好:rec_month_4349_test(voucher, amount)
和rec_daily_balancing_test(voucher, payments)
(或者您可以将它们包含在索引中而不会被搜索,这有点高级)。
此优化适用于大多数数据库(索引扫描而不是索引查找)。我不知道它是否适用于MS Access(我尽可能避免使用的软件产品)。
请记住,您需要为所有表格执行此操作。
答案 1 :(得分:0)
不确定这是否是最佳解决方案,但我为每个表创建了单独的视图,以选择凭证和每个特定凭证的金额总和。每个视图看起来类似于以下内容:
<强> rec_sum4349 强>
SELECT voucher, sum(amount) AS GL
FROM rec_month_4349_test
GROUP BY voucher
然后我有一个视图,它使用如下所示的完整连接将所有单独的视图组合在一起:
<强> rec_vouch_test 强>
SELECT a.voucher, a.GL, b.DB
FROM rec_sum4349 a
FULL JOIN rec_sumDB b
ON a.voucher = b.voucher
WHERE a.voucher IS NOT NULL AND a.voucher <> ''
ORDER BY a.voucher
在我看到这个效果非常好之后,我为剩下的表创建了我需要总计金额的视图,并将它们添加到上面的视图中。结果正是我所寻找的,运行时间从近2分钟减少到几秒钟!谢谢你的帮助。现在开始匹配所有内容!
答案 2 :(得分:0)
相关的子查询是我更喜欢的最后选择。
我建议编写子查询并连接每个表,以便每个表都可以利用它们上的索引。
在每个表上创建以下索引,并查看以下查询。
<强> rec_vouchers 强>
聚集索引(v_id,凭证)
过滤的非群集索引(v_num)WHERE v_num不喜欢'ONL%'
<强> rec_month_4349_test 强>
非聚集索引(凭证)包含(金额)
<强> rec_daily_balancing_test 强>
非聚集索引(凭证)包含(付款)
<强> rec_ed_test 强>
非聚集索引(凭证)包含(金额)
<强> rec_eft_batches_new_test 强>
非聚集索引(凭证)包括(batchtotal)
<强> rec_check_batch_test 强>
非聚集索引(凭证)包括(batchtotal)
<强> rec_lockbox_test 强>
非聚集索引(凭证)包含(idxtotal)
<强> rec_lcdl_test 强>
非聚集索引(凭证)包含(金额)
<强> rec_electronic_files_test 强>
非聚集索引(凭证)包含(payment_amount)
<强> rec_electronic_edits_test 强>
非聚集索引(凭证)包含(金额)
SELECT a.v_id,a.voucher
,t1.GL ,t2.DB ,t3.GLcount
,t4.DBcount ,t5.ED ,t6.EFT
,t7.CHK ,t8.LBX ,t9.LCDL
,(t10.Elec1+t11.Elec2) AS Elec
FROM
( SELECT t0.v_id ,t0.voucher
FROM rec_vouchers t0
GROUP BY t0.v_id ,t0.voucher
)a
JOIN
( SELECT SUM(b.amount) AS GL,b.voucher
FROM rec_month_4349_test b
Group By b.voucher
) t1
ON a.v_id=t1.voucher
JOIN
( SELECT SUM(c.payments) AS DB,c.voucher
FROM rec_daily_balancing_test c
Group By c.voucher
) t2
ON a.v_id=t2.voucher
JOIN
( SELECT COUNT(x.v_num) AS GLcount,x.v_id
FROM rec_vouchers x
WHERE x.v_num NOT LIKE 'ONL%'
Group BY x.v_id
) t3
ON a.v_id=t3.v_id
JOIN
( SELECT COUNT(c.batch_num) AS DBcount,c.voucher
FROM rec_daily_balancing_test c
Group By c.voucher
) t4
ON a.v_id=t4.voucher
JOIN
( SELECT SUM(d.amount) AS ED,d.voucher
FROM rec_ed_test d
Group By d.voucher
) t5
ON a.v_id=t5.voucher
JOIN
( SELECT SUM(e.batchtotal) AS EFT,e.voucher
FROM rec_eft_batches_new_test e
Group By e.voucher
) t6
ON a.v_id=t6.voucher
JOIN
( SELECT SUM(f.batchtotal) AS CHK,f.voucher
FROM rec_check_batch_test f
Group By f.voucher
) t7
ON a.v_id=t7.voucher
JOIN
( SELECT SUM(g.idxtotal) AS LBX,g.voucher
FROM rec_lockbox_test g
Group By g.voucher
) t8
ON a.v_id=t8.voucher
JOIN
( SELECT SUM(h.amount) AS LCDL,h.voucher
FROM rec_lcdl_test h
Group By h.voucher
) t9
ON a.v_id=t9.voucher
JOIN
( SELECT SUM(i.payment_amount) AS Elec1,i.voucher
FROM rec_electronic_files_test i
GROUP BY i.voucher
) t10
ON a.v_id=t10.voucher
JOIN
( SELECT SUM(j.amount) AS Elec2,j.voucher
FROM rec_electronic_edits_test j
GROUP BY j.voucher
) t11
ON a.v_id=t11.voucher