MySQL-其他列值之和

时间:2019-12-18 07:13:34

标签: mysql

这是问题所在。我有一个很长但不是很复杂的查询:

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)),或者可以吗?

无论如何,就是这样。我知道我可以重新安排查询(子查询而不是联接,与之不同),但是我想把它留作最后的选择。有没有办法实现我想要的?

1 个答案:

答案 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 有基数问题。