使用SUM,GROUP BY和JOIN进行SQL聚合(多对多)

时间:2014-09-20 06:32:53

标签: mysql sql count sum aggregation

以下是表格布局示例:

TABLE_A:                    TABLE_B:     TABLE_A_B:
id | a     | b    | c       id | name    a_id | b_id
---------------------       ---------    -----------
1  | true  | X    | A       1  | A       1    | 1
2  | true  | Z    | null    2  | B       1    | 2
3  | false | X    | null    3  | C       2    | 2
4  | true  | Y    | Q                    4    | 1
5  | false | null | null                 4    | 2
                                         5    | 1

可能的值:

  • TABLE_A.a:true,false
  • TABLE_A.b:X,Y,Z
  • TABLE_A.c:A,B,C,...基本上是任意的
  • TABLE_B.name:A,B,C,......基本上是任意的

我想要实现的目标:

SELECT all rows from TABLE_A
  SUM(where a = true),
  SUM(where a = false),
  SUM(where b = 'X'),
  SUM(where b = 'Y'),
  SUM(where b = 'Z'),
  SUM(where b IS NULL),
and also get the SUMs for all distinct TABLE_A.c values.
and also get the SUMs for all those TABLE_A_B relations.

上面示例表的结果应如下所示:

aTrue | aFalse | bX | bY | bZ | bNull | cA | cQ | cNull | nameA | nameB | nameC
-------------------------------------------------------------------------------
3     | 2      | 2  | 1  | 1  | 1     | 1  | 1  | 3     | 3     | 3     | 0

到目前为止我做了什么:

SELECT
  SUM(CASE WHEN a = true THEN 1 ELSE 0 END) AS aTrue,
  SUM(CASE WHEN b = false THEN 1 ELSE 0 END) AS aFalse,
  SUM(CASE WHEN b = 'X' THEN 1 ELSE 0 END) AS bX,
  ...
FROM TABLE_A

我的问题是什么?

选择列TABLE_A.aTABLE_A.b非常简单,因为可能存在固定数量的值。

但我无法弄清楚如何计算TABLE_A.c的不同值。基本上相同的问题是JOINed TABLE_B因为 TABLE_B中的值数量未知且可能会随时间发生变化。

感谢您的帮助! :)

EDIT1:新的(首选)SQL结果结构:

column         | value | sum
----------------------------
TABLE_A.a      | true  | 3
TABLE_A.a      | false | 2
TABLE_A.b      | X     | 2
TABLE_A.b      | Y     | 1
TABLE_A.b      | Z     | 1
TABLE_A.b      | null  | 1
TABLE_A.c      | A     | 1
TABLE_A.c      | Q     | 1
TABLE_A.c      | null  | 3
TABLE_B.name   | A     | 3
TABLE_B.name   | B     | 3
TABLE_B.name   | C     | 0

2 个答案:

答案 0 :(得分:1)

从您原来的行请求作为模拟枢轴。通过执行SUM(逻辑条件),如果为true,则基本上返回1,如果为false则返回0。因此,由于列“a”是真或假,简单的“a”或NOT“a”之和(对于错误计数 - NOT FALSE = TRUE)。同样,你的“b”列,所以b ='X'= true计为1,否则为0。

在其他sql引擎中,您可能会将其视为SUM(case / when)。

现在,由于您的表计数不相互依赖,因此它们可以单独使用SUM()到它们自己的子别名查询引用(分别用于pre-queryA和pre-queryB的pqA和pqB)。由于没有分组,它们每个都会产生一行。没有连接会创建一个笛卡尔,但由于1:1的比例,只返回你想要的所有列的单个记录。

SELECT 
      pqA.*, pqB.*
   from
      ( SELECT
              SUM( ta.a ) aTrue,
              SUM( NOT ta.a ) aFalse,
              SUM( ta.b = 'X' ) bX,
              SUM( ta.b = 'Y' ) bY,
              SUM( ta.b = 'Z' ) bZ,
              SUM( ta.b is null ) bNULL,
              SUM( ta.c = 'A' ) cA,
              SUM( ta.c = 'Q' ) cQ,
              SUM( ta.c is null ) cNULL,
              COUNT( distinct ta.c ) DistC
           from
              table_a ta ) pqA,
      ( SELECT
              SUM( b.Name = 'A' ) nameA,
              SUM( b.Name = 'B' ) nameB,
              SUM( b.Name = 'C' ) nameC
           from
              table_a_b t_ab 
                 join table_b b
                    ON t_ab.b_id = b.id ) pqB

此选项提供您的第二个(首选)输出

SELECT
      MAX( 'TABLE_A.a   ' ) as Basis,
      CASE when a then 'true' else 'false' end Value,
      COUNT(*) finalCnt
   from
      TABLE_A
   group by
      a
UNION ALL
SELECT
      MAX( 'TABLE_A.b   ' ) as Basis,
      b Value,
      COUNT(*) finalCnt
   from
      TABLE_A
   group by
      b
UNION ALL
SELECT
      MAX( 'TABLE_A.c   ' ) as Basis,
      c Value,
      COUNT(*) finalCnt
   from
      TABLE_A
   group by
      c
UNION ALL
SELECT
      MAX( 'TABLE_B.name   ' ) as Basis,
      b.Name Value,
      COUNT(*) finalCnt
   from
      table_a_b t_ab 
         join table_b b
            ON t_ab.b_id = b.id 
   group by
      b.Name

答案 1 :(得分:0)

我认为您需要构建动态查询,因为您不知道表A中列C的可能值。因此您可以编写存储过程,您可以在一个变量中获取列C的不同值列表并使用“Do WHILE”可以构建动态查询。 如果您需要更多详细帮助,请与我们联系 Dynamic SQL