做一个计数MySQL查询?

时间:2009-09-26 20:31:33

标签: sql mysql pivot

我有下表:

UID | ID  | Type
1   | 1   | product
1   | 2   | product
1   | 3   | service
1   | 4   | product
1   | 5   | product
2   | 6   | service
1   | 7   | order
2   | 8   | invoice
2   | 9   | product

我想最终:

UID | product | service | invoice | order
1   |  4      |  1      |  0      |  1
2   |  1      |  1      |  1      |  0

SQL查询会是什么样的?或者至少是最充足的一个?

5 个答案:

答案 0 :(得分:7)

如果您真的只需要这四种类型,那么您可以按如下方式对值进行硬编码:

select UID,
    count(case when type='product' then 1 else null end) as product,
    count(case when type='service' then 1 else null end) as service,
    count(case when type='invoice' then 1 else null end) as invoice,
    count(case when type='order' then 1 else null end) as order
from MyTable
group by UID
order by UID    

答案 1 :(得分:7)

您要做的是一个数据透视操作,SQL语法不直接支持它。但是,它并不太复杂,概念上涉及两个步骤:

  1. 将数据“爆破”到多个列中,原始数据集中每行一行。这通常使用CASE WHEN ... ELSE ... END或偶尔使用函数(如oracle中的decode())来完成。我将在下面的示例中使用CASE WHEN,因为它对大多数RDBMS都同样适用
  2. 使用GROUP BY和聚合函数(SUM,MIN,MAX等)将多行折叠到您想要的输出行集中。
  3. 我正在使用此数据集作为示例:

    mysql> select * from foo;
    +------+------+---------+
    | uid  | id   | type    |
    +------+------+---------+
    |    1 |    1 | product | 
    |    1 |    2 | product | 
    |    1 |    3 | service | 
    |    1 |    4 | product | 
    |    1 |    5 | product | 
    |    2 |    6 | service | 
    |    1 |    7 | order   | 
    |    2 |    8 | invoice | 
    |    2 |    9 | product | 
    +------+------+---------+
    

    第1步是“炸毁”数据集:

    select uid
         , case when type = 'product' then 1 else 0 end as is_product
         , case when type = 'service' then 1 else 0 end as is_service
         , case when type = 'invoice' then 1 else 0 end as is_invoice
         , case when type = 'order' then 1 else 0 end as is_order
      from foo;
    

    给出:

    +------+------------+------------+------------+----------+
    | uid  | is_product | is_service | is_invoice | is_order |
    +------+------------+------------+------------+----------+
    |    1 |          1 |          0 |          0 |        0 | 
    |    1 |          1 |          0 |          0 |        0 | 
    |    1 |          0 |          1 |          0 |        0 | 
    |    1 |          1 |          0 |          0 |        0 | 
    |    1 |          1 |          0 |          0 |        0 | 
    |    2 |          0 |          1 |          0 |        0 | 
    |    1 |          0 |          0 |          0 |        1 | 
    |    2 |          0 |          0 |          1 |        0 | 
    |    2 |          1 |          0 |          0 |        0 | 
    +------+------------+------------+------------+----------+
    

    接下来,我们在每个日期的输出中折叠为一行,并将每个is_ *列相加,使用或初始查询作为内联视图(也称为“子查询”):

    select uid
         , sum(is_product) as count_product
         , sum(is_service) as count_service
         , sum(is_invoice) as count_invoice
         , sum(is_order)   as count_order
      from (
             select uid
                  , case when type = 'product' then 1 else 0 end as is_product
                  , case when type = 'service' then 1 else 0 end as is_service
                  , case when type = 'invoice' then 1 else 0 end as is_invoice
                  , case when type = 'order' then 1 else 0 end as is_order
               from foo
           ) x
     group by uid;
    

    (另请注意,您可以将这两个查询合并为一个,但为了清楚起见,我在这里单独显示它们;至少在MySQL中,这似乎导致更简单的执行计划,这通常意味着更快的执行 - 如总是,在真实的数据集上测试你的SQL性能,不要相信我的话!)

    这给了我们:

    +------+---------------+---------------+---------------+-------------+
    | uid  | count_product | count_service | count_invoice | count_order |
    +------+---------------+---------------+---------------+-------------+
    |    1 |             4 |             1 |             0 |           1 | 
    |    2 |             1 |             1 |             1 |           0 | 
    +------+---------------+---------------+---------------+-------------+
    

    这是期望的结果。

答案 2 :(得分:2)

您必须在MySQL中使用CASE statements将行数据转换为列(反之亦然):

  SELECT t.uid,
         SUM(CASE WHEN t.type = 'product' THEN COUNT(*) END) as PRODUCT,
         SUM(CASE WHEN t.type = 'service' THEN COUNT(*) END) as SERVICE,
         SUM(CASE WHEN t.type = 'invoice' THEN COUNT(*) END) as INVOICE,
         SUM(CASE WHEN t.type = 'order' THEN COUNT(*) END) as ORDER
    FROM TABLE t
GROUP BY t.uid, t.type

答案 3 :(得分:1)

你正在寻找一种称为“数据透视表”的东西,这不是MySQL本身可以做的事情。

在这种情况下,您可能最好转换应用程序中的数据,并使用GROUP BY和/或DISTINCT的某种组合来收集您正在寻找的数据。这个查询可能有效,我还没有测试过:

SELECT Type, COUNT(ID), UID
  FROM tablename
 GROUP BY UID, Type

答案 4 :(得分:-3)

从mytable中选择计数(产品,服务,发票,订单)