【问题标题】:SQL - results from 3 tables, aggregate functionsSQL - 来自 3 个表的结果,聚合函数
【发布时间】:2019-12-03 11:15:09
【问题描述】:

我正在尝试为以下结果创建 SQL 查询:

id, name,   Users in group, Messages in groups, Message type 1 in groups, Message type 2 in groups
1   Group1  4               3                   2                         1
2   Group2  3               2                   1                         1
3   Group1  1               1                   1                         0

我的数据库:

create database user_test;

use user_test;


CREATE TABLE `user` (
  `id`             BIGINT      NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) NOT NULL,
  `group_id`       BIGINT      NOT NULL,
  PRIMARY KEY (`id`)
);


CREATE TABLE `user_group` (
  `id`      BIGINT           NOT NULL AUTO_INCREMENT,
  `name`    VARCHAR(100)
            CHARACTER SET utf8
            COLLATE utf8_bin NOT NULL,
  UNIQUE KEY `unique` (`name`) USING BTREE,
  PRIMARY KEY (`id`)
);


CREATE TABLE `message` (
  `id`               BIGINT   NOT NULL AUTO_INCREMENT,
  `user_id`           BIGINT   NOT NULL,
  `type`             INT      NOT NULL,
  `date`             DATETIME NOT NULL,
  UNIQUE KEY `unique` (`user_id`, `type`, `date`) USING BTREE,
  PRIMARY KEY (`id`)
);


ALTER TABLE user
    ADD CONSTRAINT user_group_c_fk FOREIGN KEY (group_id) REFERENCES user_group(id);


ALTER TABLE message
    ADD CONSTRAINT user_a_fk FOREIGN KEY (user_id) REFERENCES user(id);

和初始值:

INSERT INTO `user_group`
VALUES (1, "Group 1"),
       (2, "Group 2"),
       (3, "Group 3");

INSERT INTO `user`
VALUES (1, "User 1", 1),
       (2, "User 2", 1),
       (3, "User 3", 1),
       (4, "User 4", 1),
       (5, "User 5", 2),
       (6, "User 6", 2),
       (7, "User 7", 2),
       (8, "User 8", 3);

INSERT INTO `message`
VALUES (1, 1, 1, "2019-07-25 00:00:00"),
       (2, 1, 2, "2019-07-25 00:00:01"),
       (3, 1, 2, "2019-07-25 00:00:02"),
       (4, 5, 1, "2019-07-25 00:00:03"),
       (5, 6, 2, "2019-07-25 00:00:04"),
       (6, 8, 1, "2019-07-25 00:00:05");

我想知道这是否可能的结果。我正在尝试这样的事情:

use user_test;

select user_group.id, 
       user_group.name,
       count(user.id) As "Users in group",
       count(message.id) AS "Messages in groups",
       count(message.type = 1) AS "Message type1 in groups",
       count(message.type = 2) AS "Message type2 in groups"
FROM user_group
LEFT JOIN user ON user.group_id = user_group.id
LEFT JOIN message ON message.user_id = user.id
WHERE user_group.id = message.user_id
GROUP BY user_group.id;

但是,当然,这是完全错误的查询。在这种情况下,我认为配置数据库无济于事,但它与整个系统分开很小,我无法修改。我想为后端端点创建一个通用查询 - 最好的解决方案是一个查询所有结果。

【问题讨论】:

  • WHERE 子句看起来很奇怪。您在 ON 子句中已经有了相同的条件,但是 WHERE 将使 LEFT JOIN 返回常规的 INNER JOIN 结果。
  • 哦,真的。我无法删除那个 WHERE 子句……但问题还是一样。
  • 认真考虑处理应用程序代码中的数据显示问题(如果有)。
  • @RaymondNijland,可能有点不清楚,但请注意我说的是 WHERE 子句,而不是 a WHERE 子句。
  • 是的,我在写完我的评论后注意到了它,并在你发表评论之前删除了我的评论@jarlh

标签: mysql sql join group-by


【解决方案1】:

对 Gordon Linoff 的回答进行位编辑。

SELECT a.id, a.name,
       COUNT(DISTINCT b.id) AS "Users in group" ,
       COUNT(c.id) AS "Messages in groups",
       COUNT(DISTINCT CASE WHEN c.type = 1 THEN c.id END) AS "Message type 1 in groups",
       COUNT(DISTINCT CASE WHEN c.type = 2 THEN c.id END) AS "Message type 2 in groups"
FROM user_group a LEFT JOIN
     USER b
     ON b.group_id = a.id LEFT JOIN
     message c
     ON c.user_id = b.id GROUP BY a.id;

这里的聚合结果是从分组表中获取的。

【讨论】:

  • 感谢您的精彩补充。关于查询的信息!
【解决方案2】:

您可以使用count(distinct) 快速完成此操作:

SELECT ug.id, ug.name,
       count(distinct u.id) As "Users in group",
       count(distinct m.id) AS "Messages in groups",
       count(distinct case when m.type = 1 then m.id end) AS "Message type1 in groups",
       count(distinct case when m.type = 2 then m.id end) AS "Message type2 in groups"
FROM user_group ug  LEFT JOIN
     user u
     ON u.group_id = ug.id LEFT JOIN
     message m
     ON m.user_id = u.id
WHERE ug.id = m.user_id
GROUP BY ug.id;

您还可以通过在执行连接之前聚合 来获得准确的计数。另请注意,我添加了表别名,因此查询更易于编写和阅读。

【讨论】:

    【解决方案3】:

    希望这会有所帮助。 我正在做内连接而不是左连接。您可以根据需要进行更改。

    select 
    ug.id, 
    ug.name,
    count(u.id) as users_in_group,
    count(m.id) as messages_in_group,
    count(decode(m.type,'1',count(m.id))) as message_type1_in_group, 
    count(decode(m.type,'2',count(m.id))) as message_type1_in_group
    from user_group ug
    join user u on ug.id=u.group_id
    join message m on m.user_id = u.user_id
    group by ug.id,ug.name ug.id,ug.name;
    

    【讨论】:

      【解决方案4】:

      我真的很接近得到正确的结果!但仍然不是正确的,但也许有帮助......

      use user_test;
      
       select user_group.id, 
             user_group.name,
              count(user.id) As "Users in group",
              count(message.id) AS "Messages in groups",
              count(CASE message.type WHEN 1 THEN 1 ELSE null end) AS "Message type1 in groups",
              count(CASE message.type WHEN 2 THEN 1 ELSE null end) AS "Message type2 in groups" FROM user_group LEFT JOIN user ON
       user.group_id = user_group.id LEFT JOIN message ON message.user_id =
       user.id WHERE user_group.id = user.group_id GROUP BY user_group.id,
       message.type
      

      【讨论】:

        猜你喜欢
        • 2018-07-09
        • 2010-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-29
        • 2014-06-07
        • 1970-01-01
        相关资源
        最近更新 更多