【问题标题】:If cases broken when using rollup如果在使用汇总时案例被破坏
【发布时间】:2017-02-14 10:03:17
【问题描述】:

我试图让一列在汇总行上有一个特定的值,但是当我添加一个“if”时,所有其他行都会获得该列中的最后一个值。

为什么?而正确的解决方法是什么?

小提琴: http://rextester.com/TTYI19512

例子:

CREATE TABLE ru (ru_id INT KEY, name VARCHAR(20));
INSERT INTO ru VALUES (1, 'A'),(2, 'B');

CREATE TABLE rud (rud_id INT KEY, ru_id INT, value INT);
INSERT INTO rud VALUES (1, 1, 3), (2, 1, 5), (3, 2, 4), (4, 2, 9);

SELECT
   ru_id,
   IF(ru_id IS NULL, 'Total', name) as name,
   COUNT(rud.value),
   SUM(rud.value)
FROM ru
   INNER JOIN rud USING (ru_id)
GROUP BY ru_id WITH ROLLUP;

当前结果:

+-------+-------+------------------+----------------+
| ru_id | name  | COUNT(rud.value) | SUM(rud.value) |
+-------+-------+------------------+----------------+
|     1 | B     |                2 |              8 |
|     2 | B     |                2 |             13 |
|  NULL | Total |                4 |             21 |
+-------+-------+------------------+----------------+

预期结果:

+-------+-------+------------------+----------------+
| ru_id | name  | COUNT(rud.value) | SUM(rud.value) |
+-------+-------+------------------+----------------+
|     1 | A     |                2 |              8 |
|     2 | B     |                2 |             13 |
|  NULL | Total |                4 |             21 |
+-------+-------+------------------+----------------+

【问题讨论】:

  • “为什么?” - 因为您正在尝试选择不属于分组的列 – name。这在“纯”SQL 中是非法的,并且 MySQL 仅在服务器配置为忽略此错误时才允许这样做(在这种情况下,您会从组中的一条记录中获得“随机”值。)
  • @CBroe:组中的随机值会很好,但现在我得到组外的值。
  • @CBroe:那是错误的。根据 SQL 标准,您可以选择所有聚合(即SUM 等)、分组依据中的列,以及在功能上取决于它们的列。 (根据给出的表格,name 不依赖于ru_id - 或者至少 DBMS 不知道这一点,但即使您将KEY 更改为PRIMARY KEY,我们仍然会得到相同的错误结果。 )
  • 似乎是 DBMS 中的一个缺陷。查询对我来说看起来不错。请注意,KEY 在 MySQL 中仅表示 INDEX。将此PRIMARY KEY 设为唯一标识符。
  • @Puggan Se:啊,抱歉,我不知道。 MySQL 似乎在 ROLLUP 方面很糟糕。在 rextester 中,它不显示“总计”。它不知道ru_id 在该行中为空。

标签: mysql rollup


【解决方案1】:

用聚合函数包装你的 if 条件,比如 MAX(没关系,因为它是一个字符串,也可以是 MIN)

SELECT IFNULL(ru_id,'Total'), MAX(IF(ru_id IS NULL, 'Total', name)) as name,
 COUNT(rud.value), SUM(rud.value) 
FROM ru INNER JOIN rud USING (ru_id) 
GROUP BY ru_id WITH ROLLUP;

你可以让总数出现在id而不是名字上,最后一行的名字是随机的。而且你当前的结果也不显示总数。

【讨论】:

  • 我得到的最大值是:A、B、B,而不是预期的“A、B、总计”
  • 找到了解决方法:IF(COUNT(DISTINCT ru_id) > 1, 'Total', name)
  • 在 if 中使用名称周围的最大值,也适用于我。 IF(ru_id IS NULL, 'Total', MAX(name))
【解决方案2】:

在纯 sql 中只允许 group-by 中包含的聚合函数和列,因此通过在 name-column 周围放置一个聚合函数,它使其成为允许的查询,并给出预期的结果。

SELECT
   ru_id,
   IF(ru_id IS NULL, 'Total', MAX(name)) as name,
   COUNT(rud.value),
   SUM(rud.value)
FROM ru
   INNER JOIN rud USING (ru_id)
GROUP BY ru_id WITH ROLLUP;

感谢@ThorstenKettner 和@CBroe 在评论区的贡献。

【讨论】:

  • 以上在 mariadb 中工作,让 mysql-fiddle 工作:IF(COUNT(DISTINCT ru_id) > 1, 'Total', MAX(name)) as name,
猜你喜欢
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-09
  • 2015-12-19
相关资源
最近更新 更多