【问题标题】:Grouping MySQL entries only if a field is not NULL, else another field with CASE仅当一个字段不为 NULL 时才对 MySQL 条目进行分组,否则另一个字段为 CASE
【发布时间】:2014-12-05 11:16:26
【问题描述】:

我有一个存储书籍版本的books 表。通常,同一本书会多次插入我的数据库中,因为它以不同的形式存在(精装本、平装本、电子书等)。每本书都有以下字段(除其他外):

  • id(唯一的主键)
  • 标题
  • item(它是一个int,同一本书的两种不同形式将具有相同的项目,即 仅以一种形式存在将为 NULL)

现在如果有另一个 sales 表来存储销售额并且看起来像这样:

  • id(唯一主键)
  • book_id(与 book.id 有关)
  • 日期(销售发生的日期)

我需要获取畅销书的列表,将不同版本的书分组,就好像有同一本书一样,所以我的 sql 查询看起来像:

    SELECT `books`.`title`, COUNT(`sales`.`id`) 
    FROM `sales` 
    JOIN `books` ON `books`.`id` = `sales`.`book_id` 
    GROUP BY (CASE WHEN `item` IS NOT NULL THEN `item` ELSE `books`.`id` END)

问题在于 ID 为 27057 且项目为 NULL 的书 «Margherita Dolcevita» 与 ID 为 49522 和项目 27057 的书 «Master of the Storm» 分组。

我需要在我的 sql 查询(最好)或我的数据库方案中进行哪些更改才能仅通过一个查询获得我想要的内容?

【问题讨论】:

  • 为什么不按书名分组?
  • 因为有几本书有相同的标题但没有共同点,很遗憾。
  • 我会尝试按 2 个字段分组,包括 item 和 books.id - GROUP BY item, IF(item IS NULL, books.id, NULL) 。这应该按项目对它们进行分组,对于那些具有 NULL 项目的项目,它也将按 id 分组
  • 按 Book.id 分组 * 10000 + case 当 item 为 null 然后 -1 else item end
  • @Kickstart 提出的解决方案应该也可以。

标签: mysql sql group-by case


【解决方案1】:

问题出在GROUP BY 子句中的CASE 上。您将“item”与“id”混合在一起。

理想情况下,您应该为books 表中的任何书籍保留一个条目,并为具有这些字段的书籍格式设置一个不同的表:

  • id(PK,自动增量);
  • book_id (FK, books.id);
  • 格式(整数、字符串,任何适合您的设计);

使用您当前的设计,尝试使您在 CASE 表达式中使用的两个 ID 的范围不重叠(例如,为 books.id 添加前缀):

GROUP BY (CASE WHEN `item` IS NOT NULL THEN `item` ELSE CONCAT('book-', `books`.`id`) END)

同一表达式的更简单的形式(并且更易于阅读和理解)是:

GROUP BY IFNULL(`item`, CONCAT('book-', `books`.`id`))

【讨论】:

  • 确实更好的解决方案是创建第三个表,遗憾的是我不能这样做,因为项目代码实际上有时是从另一个公共数据库导入的。无论如何,感谢您的解释,您的解决方案工作正常,虽然我想我会去@Kickstart 的可读性。
  • 如果itembooks.id的类型是INT我觉得@Kickstart提出的解决方案比较快。加油!
猜你喜欢
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-19
  • 2021-09-14
  • 1970-01-01
相关资源
最近更新 更多