简体   繁体   English

MySQL COUNT和GROUP BY子查询

[英]MySQL COUNT and GROUP BY subquery

I'm trying to find the count of posts grouped by branch and category. 我正在尝试查找按分支和类别分组的帖子数。 I'm not getting the categories with count 0. 我没有得到计数为0的类别。

CREATE TABLE branches
    (`id` serial primary key, `name` varchar(7) unique)
;

INSERT INTO branches
    (`id`, `name`)
VALUES
    (1, 'branch1'),
    (2, 'branch2'),
    (3, 'branch3')
;


CREATE TABLE categories
    (`id` serial primary key, `category` varchar(4) unique)
;

INSERT INTO categories
    (`id`, `category`)
VALUES
    (1, 'cat1'),
    (2, 'cat2')
;


CREATE TABLE posts
    (`id` serial primary key, `branch_id` int, `category_id` int, `title` varchar(6), `created_at` varchar(10))
;

INSERT INTO posts
    (`id`, `branch_id`, `category_id`, `title`, `created_at`)
VALUES
    (1, 1, 1, 'Title1', '2017-12-14'),
    (2, 1, 2, 'Title2', '2018-01-05'),
    (3, 2, 1, 'Title3', '2018-01-10')
;

Expected Output: 预期产量:

+---------+----------+----+----+
| branch  | category | c1 | c2 |
+---------+----------+----+----+
| branch1 | cat1     |  1 |  0 |
| branch1 | cat2     |  0 |  1 |
| branch2 | cat1     |  0 |  1 |
| branch2 | cat2     |  0 |  0 |
+---------+----------+----+----+

Query tried: 查询尝试:

SELECT b.name, x.c1, y.c2 FROM branches b
LEFT JOIN (
     SELECT COUNT(id) c1 FROM posts WHERE created_at < '2018-01-01'
     GROUP BY posts.branch_id, posts.category_id
) x x.branch_id = b.id
LEFT JOIN (
     SELECT COUNT(id) c2 FROM posts WHERE created_at BETWEEN '2018-01-01' AND '2018-01-31'
     GROUP BY posts.branch_id, posts.category_id
) y y.branch_id = b.id
GROUP BY b.id

It looks like this might do what you want. 看来这可能会做您想要的。

Explanation: Get each possible combination of branch/category for branches which exists in posts. 说明:获取帖子中存在的分支的分支/类别的每种可能组合。 Do a conditional sum to get the counts by date range and branch/category. 进行条件求和,以按日期范围和分支/类别获取计数。 Then join back to branch. 然后加入分支。

SELECT b.b_id branch,
       b.category,
       COALESCE(Range_Sum.C1,0) C1,
       COALESCE(Range_Sum.C2,0) C2
  FROM ( SELECT b.id b_id,
                c.id c_id,
                c.category
           FROM branches b,
                categories c
          WHERE EXISTS
                  ( SELECT 1
                      FROM posts
                     WHERE b.id = posts.branch_id
                  )
       ) b
  LEFT  
  JOIN (SELECT p.branch_id,
               c.id c_id,
               c.category,
               SUM
                 ( CASE WHEN p.created_at < '2018-01-01' THEN 1 
                        ELSE 0
                    END
                 ) C1,
               SUM
                 ( CASE WHEN p.created_at BETWEEN '2018-01-01' AND '2018-01-31' THEN 1
                        ELSE 0
                    END
                 ) C2
          FROM posts p
         INNER
          JOIN categories c
            ON p.category_id = c.id
         GROUP
            BY p.branch_id,
               c.category,
               c.id
       ) Range_Sum
    ON b.b_id = Range_Sum.branch_id
   AND b.c_id = Range_Sum.c_id;

Also, just a thing for writing easily readable queries - NEVER use x and y as aliases. 而且,这只是编写易于阅读的查询的内容-切勿使用x和y作为别名。 Choose anything else that could possibly be more informative. 选择其他可能更有用的信息。

You need to CROSS JOIN branches and categories first; 您需要首先CROSS JOIN branchescategories then LEFT JOIN to posts and do conditional counts based on your WHERE criteria. 然后LEFT JOIN posts并根据您的WHERE标准进行条件计数。

Generic format: 通用格式:

SELECT x.data, y.data
, COUNT(CASE WHEN conditionN THEN 1 ELSE NULL END) AS cN
FROM x CROSS JOIN y
LEFT JOIN z ON x.id = z.x_id AND y.id = z.y_id
GROUP BY x.data, y.data
;

Note: COUNT (and pretty much all aggregate functions) ignore NULL values. 注意:COUNT(几乎所有聚合函数)都会忽略NULL值。

Maybe a little contrived... 也许有点人为...

SELECT DISTINCT x.branch_id
              , y.category_id
              , COALESCE(z.created_at < '2018-01-01',0) c1
              , COALESCE(z.created_at BETWEEN '2018-01-01' AND '2018-01-31',0) c2
           FROM posts x
           JOIN posts y
           LEFT
           JOIN posts z
             ON z.branch_id = x.branch_id
            AND z.category_id  = y.category_id;

http://sqlfiddle.com/#!9/8aabf2/31 http://sqlfiddle.com/#!9/8aabf2/31

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM