【问题标题】:MySQL subtract two count columnsMySQL减去两个计数列
【发布时间】:2013-08-20 22:21:41
【问题描述】:

我有一张这样的桌子:

client    msg_type   msg_body  id
------    --------   --------  ---
123       typeA      success   abc
123       typeB      success   abc
456       typeA      success   abc
456       typeB      failure   abc
123       typeA      success   abc
123       typeA      success   abc
789       typeA      success   def
789       typeB      success   def

等等

我想要这样的输出:

client    diff   id
------    ----   ---
 123      2      abc
 456      1      abc
 789      0      def

其中difftypeA:success 消息的计数 - typeB:success 消息。我可以使用以下方法获得 typeA 成功的计数:

select client, count(*) from mytable
where msg_type="typeA" and msg_body="success"

但是,我不知道如何在其中添加另一个计数(对于 typeB)并减去。 我试过类似的东西:

select client, count(*) from mytable
where msg_type="typeA" and msg_body="success" - count(*)
from mytable where msg_type="typeB" and msg_body="success"

但它当然没有用,否则我不会在这里问。 :) 有什么建议吗?

编辑:添加了另一列。我尝试了给出的两个建议,但它似乎只返回其中一个 id 的结果,而不是两者。

编辑 #2:我尝试使用以下命令包装 SELECT 查询:

select id, count(*) from (select ...) as anothertable where count_a_minus_count_b = 0;

我希望输出是这样的:

id    count
---   -----
abc   2
def   1

其中 count 是 typeA:success 和 typeB:success 之差为 0 的客户端数。

【问题讨论】:

  • 回复:“我尝试了给出的两个建议,但它似乎只返回其中一个 id 的结果,而不是两者”:所有答案都显示了如何计算计数之间的差异;我认为他们都非常清楚。与其简单地尝试建议而不阅读它们,我建议您尝试从中学习,如果有不明白的部分,请提出问题。 :-/
  • @ruakh 我以为我理解我正在运行的查询,因此我尝试不同的事情。我想我明白了: select id, count(*) from (SELECT id, client, COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END) - COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_a_minus_count_b FROM mytable WHERE msg_body = 'success' GROUP BY client) as sometable where count_a_minus_count_b

标签: mysql sql


【解决方案1】:

COUNT 计算非空值,因此您可以构造一个在 msg_type = 'typeA' 时为非空的表达式,在 msg_type = 'typeB' 时构造一个非空表达式。例如:

SELECT client,
       COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END) AS count_a,
       COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_b,
       COUNT(CASE WHEN msg_type = 'typeA' THEN 1 END)
       - COUNT(CASE WHEN msg_type = 'typeB' THEN 1 END) AS count_a_minus_count_b
  FROM mytable
 WHERE msg_body = 'success'
 GROUP
    BY client
;

(免责声明:未经测试。)

【讨论】:

  • "(免责声明:未经测试。)" - 对我来说效果很好。我一直在寻找这样的东西,并帮助了我很多。 干杯
  • @Fred-ii-:很高兴听到这个消息! :-)
  • 谢谢 :-) 我不是 MySQL 专家,但我有我的时刻。然而,当我看到它时,我知道好的语法以及我想到的 CASE,但不知道如何使用它来完成我想要完成的事情。我不得不做一些细微的修改,但最终效果很好。 干杯
【解决方案2】:

另一种方式:

SELECT
    d.client, COALESCE(a.cnt, 0) - COALESCE(b.cnt, 0) AS diff, d.id
FROM
    ( SELECT DISTINCT client, id 
      FROM mytable
    ) AS d

  LEFT JOIN
    ( SELECT client, COUNT(*) AS cnt, id
      FROM mytable
      WHERE msg_type = 'typeA' 
        AND msg_body = 'success'
      GROUP BY client, id
    ) AS a
  ON  d.client = a.client
  AND d.id = a.id

  LEFT JOIN
    ( SELECT client, COUNT(*) AS cnt, id 
      FROM mytable
      WHERE msg_type = 'typeB' 
        AND msg_body = 'success'
      GROUP BY client, id
    ) AS b 
  ON  d.client = b.client 
  AND d.id = b.id ;

测试于 SQL-Fiddle

【讨论】:

    【解决方案3】:

    给你:

    select client, 
      (sum(case when msg_type='typeA' and msg_body='success' then 1 else 0 end) - 
      sum(case when msg_type='typeB' and msg_body='success' then 1 else 0 end)) as diff
    from your_table
    group by client
    

    【讨论】:

      【解决方案4】:

      这是获得结果的一种方法:

      SELECT t.client
           , SUM(t.msg_type<=>'typeA' AND t.msg_body<=>'success')
           - SUM(t.msg_type<=>'typeB' AND t.msg_body<=>'success') AS diff
        FROM mytable t
       GROUP BY t.client
      

      (此查询中的表达式是 MySQL 特定的;对于更便携的查询,请使用不太简洁的 CASE 表达式来获得等效结果。)


      作为返回相同结果的更简洁和模糊的替代方案:

      SELECT t.client
           , SUM((t.msg_body<=>'success')*((t.msg_type<=>'typeA')+(t.msg_type<=>'typeB')*-1)) AS diff
        FROM mytable t
       GROUP BY t.client
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 2014-09-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多