这是问题所在。我有一个很长但不是很复杂的查询:
Me.YourSubformContainerName.Form.DataEntry = IIf(Me.OpenArgs = "Button1", True, False)
有n个左联接,我需要保持这种方式,因为新的左联接必须随时可用。我显然将n值复制到SUM中,因为可连接项可以有多个结果,并且出于灵活的WHERE原因,我无法将它们中的任何一个分解为子查询。我只需要每个x.id的一个x.value到SUM中,那也是显而易见的。
-我无法将x.id添加到GROUP BY,因为我需要一行来获得每个y.id的总和。
-我无法使用计算:
SUM(x.value)
FROM valuetable AS x
LEFT JOIN jointable_1 AS y
LEFT JOIN jointable_2 AS z
etc
...
GROUP BY y.id, z.id
由于x.value的总数可以是任意数量,因为不同的x.id具有不同的联接数。
-我不能使用DISTINCT x.value,因为任何x.id可以具有任何x.value,并且它们可以包含相同的值。
-我不知道如何为总和创建子查询,因为我无法在子查询中使用汇总值(例如GROUP_CONCAT(DISTINCT x.id)),或者可以吗?
无论如何,就是这样。我知道我可以重新安排查询(子查询而不是联接,与之不同),但是我想把它留作最后的选择。有没有办法实现我想要的?
答案 0 :(得分:0)
很抱歉,没有子查询(或视图),没有通用的方法来做您想要的事情。
一些术语:“基数”。就我们的目的而言,它是表或结果集中的行数。 (出于我们的目的,结果集是一种虚拟表。)
为使SUM(col)
和COUNT(*)
之类的汇总函数产生良好的结果,我们必须注意所汇总表的基数。这种东西
SELECT DATE(sale_time) sale_date,
store_id,
SUM(sale_amount) total_sales
FROM sale
GROUP BY DATE(sale_time), store_id
汇总了结果表与基础表的基数,因此它会生成有用的结果。
但是,如果我们这样做
SELECT DATE(sale.sale_time) sale_date,
sale.store_id,
SUM(sale.sale_amount) total_sales,
COUNT(promo.promo_id) promos
FROM sale
LEFT JOIN promo ON sale.store_id = promo.store_id
AND DATE(sale.sale_time) = promo.promo_date
GROUP BY DATE(sale.sale_time), sale.store_id
我们破坏了汇总结果集的基数。除非我们确定每个商店每天都有零个或一个促销记录,否则这将永远无效。为什么不? LEFT JOIN操作影响正在汇总的虚拟表的基数。这意味着一些sale_amount值会多次出现在SUM中,因此SUM将不正确或不可信。
如何防止LEFT JOIN操作弄乱您的基数?确保您的LEFT JOIN的ON
子句将右侧的每一行与左侧的零行或一排完全匹配。也就是说,请确保JOIN两侧的(虚拟)表具有适当的基数。
(在实体关系行话中,您的SUM失败,因为在进行求和之前,您以一对多关系加入了两个实体。)
理论上最干净的方法是在连接之前执行两个聚合操作。这样就以LEFT JOIN一对一或一对一的方式联接了两个虚拟表
SELECT sales.sale_date,
sales.store_id,
sales.total_sales,
promos.promo_count
FROM (
SELECT DATE(sale_time) sale_date,
store_id,
SUM(sale_amount) total_sales
FROM sale
GROUP BY DATE(sale_time), sale_store
) sales
LEFT JOIN (
SELECT store_id,
promo_date
COUNT(*) promo_count
FROM promo
GROUP BY store_id, promo_date
) promos ON sales.store_id = promos.store_id
AND sales.sale_date = promo.promo_date
尽管此SQL很复杂,但大多数服务器都能有效地处理这种模式。
故障排除技巧:如果您在同一查询级别看到 SUM()... FROM ... JOIN ... GROUP BY 有基数问题。