mysql sum时去重

mysql sum时去重

前言

在做项目的过程中,总是会遇到一些求和的情况,表A和表B关联之后,导致表A数据重复,但是求和字段中又有表A的某个字段。当然了,最直接的想法就是先根据表A分组之后再进行求和,但是在实际应用中,可能本身原来就是一个比较复杂和耗时的查询,再进行一个分组之后再包装一层,会大大降低效率,也可能会影响其他字段的值。也在网上看了一些博友贴出的sum DISTINCT case whensum DISTINCT 求和字段 这两种写法,只要遇到求和字段有重复值,就给排除掉了,也参考了其他一些想法,最终写出一个可以解决我问题的一种写法。

最终写法

SELECT SUM(sc.score) AS enSum,
SUM(DISTINCT CONVERT(st.id*POWER(10,10),DECIMAL(30,0))+st.credits)
-SUM(DISTINCT CONVERT(st.id*POWER(10,10),DECIMAL(30,0))) AS creSum
 FROM student st
JOIN stu_score sc ON sc.stu_id  = st.id
WHERE sc.course = '英语';

过程演示

创建表

CREATE TABLE `student`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `sname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '学生姓名',
  `credits` int NOT NULL DEFAULT 0 COMMENT '学分',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '学生表' ROW_FORMAT = Dynamic;

CREATE TABLE `stu_score`  (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `stu_id` int NOT NULL COMMENT '学生ID',
  `grade` int NOT NULL COMMENT '学年',
  `course` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '课程',
  `score` int NOT NULL DEFAULT 0 COMMENT '分数',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '学生成绩表' ROW_FORMAT = Dynamic;

插入测试数据

INSERT INTO `student` (`sname`, `credits`) VALUES ('张一', 30);
INSERT INTO `student` (`sname`, `credits`) VALUES ('张二', 30);
INSERT INTO `student` (`sname`, `credits`) VALUES ('张三', 32);
INSERT INTO `student` (`sname`, `credits`) VALUES ('张四', 25);

INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2021, '英语', 88);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2021, '高数', 65);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2021, '英语', 80);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2021, '高数', 78);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2021, '英语', 66);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2021, '高数', 65);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2021, '英语', 80);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2021, '高数', 90);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2022, '英语', 80);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2022, '高数', 65);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2022, '英语', 81);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2022, '高数', 74);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2022, '英语', 66);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2022, '高数', 69);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2022, '英语', 80);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2022, '高数', 91);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2023, '英语', 82);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (1, 2023, '高数', 69);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2023, '英语', 80);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (2, 2023, '高数', 79);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2023, '英语', 66);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (3, 2023, '高数', 66);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2023, '英语', 88);
INSERT INTO `stu_score` (`stu_id`, `grade`, `course`, `score`) VALUES (4, 2023, '高数', 90);

需求阐述

需要查询所有学生的学分合计和所有学生三年的英语成绩合计,不能使用子查询

错误查询1

直接对求和字段DISTINCT,两个30的值只能统计进来一个

SELECT SUM(sc.score) AS enSum,
SUM(DISTINCT st.credits) AS creSum
 FROM student st
JOIN stu_score sc ON sc.stu_id  = st.id
WHERE sc.course = '英语';

在这里插入图片描述

错误查询2

sum DISTINCT case whensum DISTINCT if 方式,查询出来结果和第一种方式一致

SELECT SUM(DISTINCT IF(st.id,st.credits,0)) 
FROM student st
JOIN stu_score sc ON sc.stu_id  = st.id
WHERE sc.course = '英语';

在这里插入图片描述

改进版本1

SELECT SUM(sc.score) AS enSum,
SUM(DISTINCT st.id+st.credits)-SUM(DISTINCT st.id) AS creSum
FROM student st
JOIN stu_score sc ON sc.stu_id  = st.id
WHERE sc.course = '英语';

在这里插入图片描述
乍一看,好像是对的了,别急,我们调整下数据。

UPDATE `student` SET `credits` = 29 WHERE `id` = 2

再次进行查询
在这里插入图片描述
我去,不应该是116吗,怎么变成85了,相信很多人已经看出了
在这里插入图片描述

改进版本2

求和字段表的主键去乘上一个足够大的数(理论上要大于求和字段的最大值)
在这里插入图片描述
乍一看,好像可以了,但是如果st.id比较大的话,也会出现问题

UPDATE `student` SET `id` = 10000000 WHERE `id` = 1;
UPDATE stu_score SET stu_id = 10000000 WHERE stu_id = 1;

在这里插入图片描述
这里是因为st.id*POWER(10,10)数值太大,被自动转换成科学计数了,最终获取到的也是错误到的结果

最终版本

将计算结果转换为decimal,可以避免被转换成科学计数
在这里插入图片描述

结语

最终的方案完美解决了我的问题,但是不排除其他一些特殊情况也会导致结果不正确,如果大家使用时遇到任何困难,都可以留言联系我,如果我没有及时回复可以邮箱联系我(1334881756@qq.com)

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KevinPan_1992

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值