【问题标题】:SQL Aggregation with SUM, GROUP BY and JOIN (many-to-many)使用 SUM、GROUP BY 和 JOIN 进行 SQL 聚合(多对多)
【发布时间】:2014-11-14 18:15:26
【问题描述】:

这是一个表格布局示例:

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:真,假
  • 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

【问题讨论】:

  • 为什么需要这种格式的结果?
  • 我并不需要这种格式,也可以有一个键值列表作为结果:key | value,然后是行aTrue | 3aFalse | 2...。最重要的是我的应用程序可以读取它并且可以识别不同的键。
  • 您的申请?告诉我们更多。
  • 你需要知道什么?它基于 Java (Spring Framework / JPA 2.1)。这意味着:我基本上可以处理每一个结果。我将在上面的问题中附加一个示例 SQL Result 结构。这种新结构处理起来真的很酷,但我不知道如何到达那里......
  • 啊,新的首选结构对MySQL来说更容易

标签: mysql sql count sum aggregation


【解决方案1】:

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

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

现在,由于您的表计数不相互依赖,它们可以将 SUM() 分离到它们自己的子别名查询引用中(pqA 和 pqB 分别用于 pre-queryA 和 pre-queryB)。由于没有分组依据,它们将各自产生一行。没有连接将创建笛卡尔,但由于 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

【讨论】:

  • 谢谢。输出#2 的解决方案看起来基本上像我的第一次尝试(此处未显示),我只是对每一列进行了单独的查询。 #2 是不是比 #1 慢很多,因为在 #1 中他只通过表一次,而对于 #2,它通过每个 UNION 的表? ... 最后一个问题,MAX(...) 函数在那里做什么?我知道你选择了列名,但你为什么使用MAX
  • @BenjaminM,由于 GROUP BY 子句要求您按所有非聚合列分组,并且标题没有改变,因此某些引擎不允许您按计算的列名排序。因此,一个简单的方法是 MAX(description),因为它无论如何都不会改变,并且会满足 GROUP BY 的唠叨。此外,更正 #1 更快,因为它通过每个表一次并获得所需的所有列。
【解决方案2】:

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

【讨论】:

  • 谢谢。我明白你的意思了。这解决了TABLE_A.c 的问题,但是 TABLE_A 和 TABLE_B 之间的多对多关系呢?我尝试使用LEFT JOIN TABLE_A_B ON ...,但随后 SUM 值出错,因为 JOIN 的结果可以包含单行 TABLE_A 的多行。
  • 如果您能分享您的修复方法,将会很有帮助。
  • @HappyCoder 请给我看你的代码,这样我可以帮助你。我认为你应该使用子查询
猜你喜欢
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-12
  • 2022-01-18
  • 2021-01-30
相关资源
最近更新 更多