group by with multiple columns

时间:2012-12-12 12:54:08

标签: mysql group-by aggregate-functions

我在一个表(A)中有一个东西,在另外两个表中有一个类别(C1,C2) category_id来自不同的表格(MC)。

我想计算特定类别中有多少东西。

实时数据示例:

表A

main_key (unique)    stuff_id (non unique)
   1                    7
   2                    6 
   3                    3

表C1

category_id main_key (it is FK for A table)
   1             1
   1             2
   3             1

表C2

category_id main_key (it is FK for A table)
   2             3
   2             1

表格MC

category_id category_name
   1             blablbl
   2               asas
   3             asasa
...

之间的关系: C1和A尽可能多 C2和A尽可能多 C1或C2和MC多对一

在当前示例中,我希望将最终结果视为

stuff_qnt        category_id        category_name
2                   1                  blablbl
2                   2                   asas
1                   3                   asasa

如何通过一个查询实现它?

我的查询是:

SELECT count(A.stuff_id) as stuff_qnt, MC.category_id, MC.category_name 
FROM A
LEFT JOIN C1 using(main_key)
LEFT JOIN C2 using(main_key)
LEFT JOIN MC ON (C1.category_id = MC.category_id AND C2.category_id = MC.category_id)
GROUP BY C1.category_id, C2.category_id

但它告诉我错误的结果,我做错了什么?

3 个答案:

答案 0 :(得分:1)

SELECT COUNT(*) AS Stuff_Qnt, C.Category_ID, MC.Category_Name
  FROM MC
  JOIN (SELECT C1.Category_ID
          FROM A
          JOIN C1 ON A.Main_Key = C1.Main_Key
        UNION ALL
        SELECT C2.Category_ID
          FROM A
          JOIN C2 ON A.Main_Key = C2.Main_Key
       ) AS C
    ON C.Category_ID = MC.Category_ID
 GROUP BY C.Category_ID, MC.Category_Name
 ORDER BY C.Category_ID, Stuff_Qnt;

你需要加入A和C1的类别以及加入A和C2的类别,你绝对不需要笛卡尔产品,例如你得到LEFT OUTER JOIN,所以你拿了列表的UNION类别ID,然后聚合并加入MC。

CREATE TABLE A
(
    main_key INTEGER NOT NULL PRIMARY KEY,
    stuff_id INTEGER NOT NULL
);
INSERT INTO A VALUES(1, 7);
INSERT INTO A VALUES(2, 6);
INSERT INTO A VALUES(3, 3);

CREATE TABLE MC
(
    category_id INTEGER NOT NULL PRIMARY KEY,
    category_name VARCHAR(10) NOT NULL
);
INSERT INTO mc VALUES(1, "blablbl");
INSERT INTO mc VALUES(2, "asas");
INSERT INTO mc VALUES(3, "asasa");

CREATE TABLE C1
(
    category_id INTEGER NOT NULL REFERENCES mc,
    main_key INTEGER NOT NULL REFERENCES a
);
INSERT INTO c1 VALUES(1, 1);
INSERT INTO c1 VALUES(1, 2);
INSERT INTO c1 VALUES(3, 1);

CREATE TABLE C2
(
    category_id INTEGER NOT NULL REFERENCES mc,
    main_key INTEGER NOT NULL REFERENCES a
);
INSERT INTO c2 VALUES(2, 3);
INSERT INTO c2 VALUES(2, 1);

SELECT COUNT(*) AS Stuff_Qnt, C.Category_ID, MC.Category_Name
  FROM MC
  JOIN (SELECT C1.Category_ID
          FROM A
          JOIN C1 ON A.Main_Key = C1.Main_Key
        UNION ALL
        SELECT C2.Category_ID
          FROM A
          JOIN C2 ON A.Main_Key = C2.Main_Key
       ) AS C
    ON C.Category_ID = MC.Category_ID
 GROUP BY C.Category_ID, MC.Category_Name
 ORDER BY C.Category_ID, Stuff_Qnt;

输出:

2   1   blablbl
2   2   asas
1   3   asasa

这是进一步的测试,在A中有两个额外的行,在C1和C2中有相应的行。测试了两个查询,我和query dkkumargoyal

CREATE TABLE A(main_key INTEGER NOT NULL PRIMARY KEY, stuff_id INTEGER NOT NULL);
INSERT INTO A VALUES(1, 7);
INSERT INTO A VALUES(2, 6);
INSERT INTO A VALUES(3, 3);
INSERT INTO A VALUES(4, 3);
INSERT INTO A VALUES(5, 3);

CREATE TABLE MC(category_id INTEGER NOT NULL PRIMARY KEY, category_name VARCHAR(10) NOT NULL);
INSERT INTO mc VALUES(1, "blablbl");
INSERT INTO mc VALUES(2, "asas");
INSERT INTO mc VALUES(3, "asasa");

CREATE TABLE C1(category_id INTEGER NOT NULL REFERENCES mc, main_key INTEGER NOT NULL REFERENCES a);
INSERT INTO c1 VALUES(1, 1);
INSERT INTO c1 VALUES(1, 2);
INSERT INTO c1 VALUES(3, 1);
INSERT INTO c1 VALUES(3, 4);
INSERT INTO c1 VALUES(1, 4);
INSERT INTO c1 VALUES(1, 5);

CREATE TABLE C2(category_id INTEGER NOT NULL REFERENCES mc, main_key INTEGER NOT NULL REFERENCES a);

INSERT INTO c2 VALUES(2, 3);
INSERT INTO c2 VALUES(2, 1);
INSERT INTO c2 VALUES(2, 5);

SELECT COUNT(*) AS Stuff_Qnt, C.Category_ID, MC.Category_Name
  FROM MC
  JOIN (SELECT C1.Category_ID
          FROM A
          JOIN C1 ON A.Main_Key = C1.Main_Key
        UNION ALL
        SELECT C2.Category_ID
          FROM A
          JOIN C2 ON A.Main_Key = C2.Main_Key
       ) AS C
    ON C.Category_ID = MC.Category_ID
 GROUP BY C.Category_ID, MC.Category_Name
 ORDER BY C.Category_ID, Stuff_Qnt;

-- Query by dkkumargoyal
SELECT COUNT(DISTINCT A.stuff_id) AS stuff_qnt, MC.category_id, MC.category_name 
FROM A
LEFT JOIN C1 on a.main_key = c1.main_key  -- USING(main_key)
LEFT JOIN C2 on a.main_key = c2.main_key  -- USING(main_key)
LEFT JOIN MC ON (C1.category_id = MC.category_id OR C2.category_id = MC.category_id)
GROUP BY MC.category_id, mc.category_name
ORDER BY MC.Category_id, stuff_qnt;       -- stuff_qnt added for standard compatibility

所做的更改对于代码在测试DBMS(Informix 11.70.FC6)上工作是必要的。

结果1:

4   1   blablbl
3   2   asas
2   3   asasa

结果2:

3   1   blablbl
2   2   asas
2   3   asasa

我认为我的结果是正确的,而另一个则没有,主要是因为当问题规定它不是唯一的时候(和{1}}唯一取决于A.Stuff_ID是唯一的(并且额外的数据行使它不唯一)。

答案 1 :(得分:1)

请看一下这个参考:

查询:

select m.category_id, m.category_name, count(a.stuff_id) as cntstuff from
(select * from c1 
 union all
 select * from c2) as c
join a 
on a.main_key = c.main_key
join mc m
on m.category_id = c.category_id
group by m.category_id
order by m.category_id
;

结果:

CATEGORY_ID     CATEGORY_NAME   CNTSTUFF
1               blablbl         2
2               asas            2
3               asasa           1

答案 2 :(得分:0)

试试这个SQL。

SELECT COUNT(DISTINCT A.stuff_id) AS stuff_qnt, MC.category_id, MC.category_name 
FROM A
LEFT JOIN C1 USING(main_key)
LEFT JOIN C2 USING(main_key)
LEFT JOIN MC ON (C1.category_id = MC.category_id OR C2.category_id = MC.category_id)
GROUP BY MC.category_id