MYSQL sum() 用于不同的行

Posted

技术标签:

【中文标题】MYSQL sum() 用于不同的行【英文标题】:MYSQL sum() for distinct rows 【发布时间】:2011-01-27 00:50:56 【问题描述】:

我正在寻找在我的 SQL 查询中使用 sum() 的帮助:

SELECT links.id, 
       count(DISTINCT stats.id) as clicks, 
       count(DISTINCT conversions.id) as conversions, 
       sum(conversions.value) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc;

我使用DISTINCT 是因为我正在执行“分组依据”,这样可以确保同一行不会被多次计算。

问题在于 SUM(conversions.value) 不止一次计算每一行的“值”(由于 group by)

我基本上想为每个 DISTINCT conversions.id 做SUM(conversions.value)

这可能吗?

【问题讨论】:

发布完整的查询会很有帮助。如何使用 GROUP BY 复制值? 你在加入吗?你应该发布你的查询。根据查询,您可以使用几个选项。 我用完整的查询更新了我的问题 显然,你可以这样做SUM(DISTINCT column) 【参考方案1】:
Select sum(x.value) as conversion_value,count(x.clicks),count(x.conversions)
FROM
(SELECT links.id, 
       count(DISTINCT stats.id) as clicks, 
       count(DISTINCT conversions.id) as conversions,
       conversions.value,       
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY conversions.id) x
GROUP BY x.id 
ORDER BY x.created desc;

我相信这会给你你正在寻找的答案。

【讨论】:

【参考方案2】:

如需了解您看到错误数字的原因,请read this

我认为杰罗姆已经掌握了导致您的错误的原因。 Bryson 的查询可以工作,但在 SELECT 中使用该子查询可能效率低下。

【讨论】:

感谢您的回答!我建议到达此页面的每个人都阅读链接的文章。这是对联接和分组的简明、居高临下和滑稽的解释,并为问题提供了适当的解决方案。【参考方案3】:

这可以解决问题,只需将总和除以重复的对话 id 的计数。

SELECT a.id,
       a.clicks,
       SUM(a.conversion_value/a.conversions) AS conversion_value,
       a.conversions
FROM (SELECT links.id, 
       COUNT(DISTINCT stats.id) AS clicks, 
       COUNT(conversions.id) AS conversions, 
       SUM(conversions.value) AS conversion_value 
      FROM links 
      LEFT OUTER JOIN stats ON links.id = stats.parent_id 
      LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
      GROUP BY conversions.id,links.id
      ORDER BY links.created DESC) AS a
GROUP BY a.id

【讨论】:

【参考方案4】:

Jeromes 解决方案实际上是错误的,可能会产生不正确的结果!!

sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value

让我们假设下表

conversions
id value
1 5
1 5
1 5
2 2
3 1

不同 id 的正确值总和为 8。 杰罗姆的公式产生:

sum(conversions.value) = 18
count(distinct conversions.id) = 3
count(*) = 5
18*3/5 = 9.6 != 8

【讨论】:

假设conversions.id 是一个唯一字段,JOIN 不可能产生3 行conversions.id = 1 并且只有1 行conversions.id = 2。假设conversions.id = 1 .id 是唯一的,是隐含的,可能应该是明确的,但除此之外,公式是可靠的。 9.6 还是10.8?。顺便问一下,除了多级子查询或者join(子查询),还有什么解决办法吗? @Jonathan 鉴于 OP 的确切查询,您是对的。如果这种情况是在一个更大的查询中,Clemens 是正确的,因为其他连接导致多行相同的conversions.id。不幸的是,这就是我现在面临的情况。 @Rikaelus 公平点。我想我没有想到的另一个隐含假设是使用的确切 JOIN。在 OP 查询中,GROUP BY 在主键 links.id 上,conversions.value 上有一个连接表/字段,并且没有其他连接来自转换表。最后一个子句非常重要 如果您所处的场景涉及更多直接从links 表连接,您可能 能够执行类似的技巧来稍微向后计算总和。否则,您可能不得不退回到依赖子查询或只是多个 SQL 查询。祝你好运!【参考方案5】:

这样的事情怎么样:

select l.id, count(s.id) clicks, count(c.id) clicks, sum(c.value) conversion_value
from    (SELECT l.id id, l.created created,
               s.id clicks,  
               c.id conversions,  
               max(c.value) conversion_value                    
        FROM links l LEFT
        JOIN stats s ON l.id = s.parent_id LEFT
        JOIN conversions c ON l.id = c.link_id  
        GROUP BY l.id, l.created, s.id, c.id) t
order by t.created  

【讨论】:

【参考方案6】:

使用以下查询:

SELECT links.id
  , (
    SELECT COUNT(*)
    FROM stats
    WHERE links.id = stats.parent_id
  ) AS clicks
  , conversions.conversions
  , conversions.conversion_value
FROM links
LEFT JOIN (
  SELECT link_id
    , COUNT(id) AS conversions
    , SUM(conversions.value) AS conversion_value
  FROM conversions
  GROUP BY link_id
) AS conversions ON links.id = conversions.link_id
ORDER BY links.created DESC

【讨论】:

【参考方案7】:

我可能错了,但据我了解

conversions.idconversions 表的主键 stats.id 是您的表 stats主键

因此,对于每个 Conversions.id,您最多有一个 links.id 受到影响。

你的要求有点像做 2 组的笛卡尔积:

[clicks]
SELECT *
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 

[conversions]
SELECT *
FROM links 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 

对于每个链接,您会得到 sizeof([clicks]) x sizeof([conversions]) 行数

正如您所指出的,您的请求中的唯一转化次数可以通过

count(distinct conversions.id) = sizeof([conversions])

这个 distinct 设法删除笛卡尔积中的所有 [clicks] 行

但很明显

sum(conversions.value) = sum([conversions].value) * sizeof([clicks])

在你的情况下,因为

count(*) = sizeof([clicks]) x sizeof([conversions])
count(*) = sizeof([clicks]) x count(distinct conversions.id)

你有

sizeof([clicks]) = count(*)/count(distinct conversions.id)

所以我会用

测试您的请求
SELECT links.id, 
   count(DISTINCT stats.id) as clicks, 
   count(DISTINCT conversions.id) as conversions, 
   sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc;

让我知道! 杰罗姆

【讨论】:

太好了,当您不想处理大型数据集无法接受的依赖子查询解决方案时,此解决方案非常完美且非常通用。 Jeromes 解决方案实际上是错误的,可能会产生不正确的结果!!请参阅下面的答案。 @ClemensValiente,Jerome 的解决方案是正确的,鉴于 conversions.id 是转换表上的唯一列。这可能是一个重要的区别,应该在答案中注明。编辑——实际上,它被声明(conversions.id 是你的表转换的主键) 还有什么方法更好,子查询还是杰罗姆斯解决方案 这不是一个充分的答案,因为它除以连接中的总行数,如果父表在连接表中有多个关系,这将产生不需要的结果。【参考方案8】:

我使用子查询来执行此操作。它消除了分组的问题。 所以查询会是这样的:

SELECT COUNT(DISTINCT conversions.id)
...
     (SELECT SUM(conversions.value) FROM ....) AS Vals

【讨论】:

用我的完整查询更新了问题。我不确定如何将子查询集成到我拥有的内容中以及它会如何影响性能。 子查询通常会对性能产生负面影响。为了尽量减少影响,请确保所有子查询都作用于索引。

以上是关于MYSQL sum() 用于不同的行的主要内容,如果未能解决你的问题,请参考以下文章

mysql 分组聚集

mysql 分组聚集

MySQL - 将两列分成两个不同的行

MySQL:每天计算不同的行

Mysql根据不同的行更新表中的行值

PHP MySQL 相同的查询返回不同的行数