您好!欢迎访问家园网-www.jy.wang!

家园网

SQL使用SUM进行多列求和时如果要先去掉重复值,应如何来写代码?请举例讲解

网络 作者:本站 点击:

SQL 多列求和先去重详解

这是一个非常实用的问题!当需要对多列求和,但某些列存在重复值时,需要先去除重复再进行求和。让我详细讲解几种常见场景和写法。


一、核心概念:什么时候需要先去重再求和?

场景说明示例
订单明细同一订单有多条商品记录,但只想计算一次运费订单A有3件商品,运费只应计算1次
用户统计同一用户有多条登录记录,但只想计算一次VIP积分用户一天登录10次,VIP积分只算1次
部门汇总同一部门有多名员工,但部门预算只应算一次部门预算不应按员工人数重复累加

二、常用解决方法

方法1:使用 DISTINCT + 子查询(最常用)

sql

SELECT 
    SUM(DISTINCT 列名) AS 去重后求和FROM 表名;

注意SUM(DISTINCT ...) 只能对单列去重求和。

sql

-- 示例:计算不重复的运费总额SELECT 
    SUM(DISTINCT freight) AS 去重运费总额FROM order_details;


方法2:使用子查询先去重,再求和

适用于多列组合去重后求和。

sql

-- 示例:按订单ID去重后,计算运费总额SELECT 
    SUM(freight) AS 去重运费总额FROM (
    SELECT DISTINCT order_id, freight    FROM order_details) t;


方法3:使用 ROW_NUMBER() 去重后求和(最精确)

适用于有复杂去重逻辑(如按某列分组,取最新记录)。

sql

-- 示例:每个订单只取最新一条记录的运费进行求和SELECT 
    SUM(freight) AS 最新运费总额FROM (
    SELECT 
        order_id,
        freight,
        ROW_NUMBER() OVER(PARTITION BY order_id ORDER BY create_time DESC) rn    FROM order_details) tWHERE rn = 1;


三、完整示例讲解

示例表结构

sql

-- 假设有一张订单明细表CREATE TABLE order_details (
    id INT,
    order_id VARCHAR(20),    -- 订单号
    product_name VARCHAR(50), -- 商品名称
    quantity INT,             -- 数量
    price DECIMAL(10,2),      -- 单价
    freight DECIMAL(10,2)     -- 运费(同一订单多次出现,运费重复));

示例数据

id

order_id

product_name

quantity

price

freight

1

ORD001

手机

1

2999

10

2

ORD001

手机壳

2

50

10

3

ORD002

电脑

1

5999

20

4

ORD002

鼠标

1

89

20

5

ORD003

耳机

3

199

15

场景1:计算商品总金额(不去重)

sql

SELECT 
    SUM(quantity * price) AS 商品总金额FROM order_details;

结果1*2999 + 2*50 + 1*5999 + 1*89 + 3*199 = 2999 + 100 + 5999 + 89 + 597 = 9784


场景2:计算运费总额(不去重)

sql

SELECT 
    SUM(freight) AS 运费总额FROM order_details;

结果10 + 10 + 20 + 20 + 15 = 75(错误!ORD001的运费被算了2次,ORD002的运费被算了2次)


场景3:计算运费总额(先去重,正确写法)

sql

-- 方法A:使用 DISTINCT 子查询SELECT 
    SUM(freight) AS 正确运费总额FROM (
    SELECT DISTINCT order_id, freight    FROM order_details) t;

结果:ORD001(10) + ORD002(20) + ORD003(15) = 45(正确)


sql

-- 方法B:使用 GROUP BY 子查询SELECT 
    SUM(freight) AS 正确运费总额FROM (
    SELECT order_id, freight    FROM order_details    GROUP BY order_id, freight) t;


场景4:多列组合去重后求和

假设需要计算:每个订单的运费 × 订单的某种系数,且同一订单的运费和系数都相同。

sql

-- 错误写法:直接求和会重复累加SELECT 
    SUM(freight * coefficient) FROM order_details;-- 正确写法:先去重,再计算SELECT 
    SUM(freight * coefficient) AS 去重后总额FROM (
    SELECT DISTINCT order_id, freight, coefficient    FROM order_details) t;


四、各数据库写法对比

数据库去重求和写法说明
MySQLSUM(DISTINCT freight)仅限单列
SQL ServerSUM(DISTINCT freight)仅限单列
PostgreSQLSUM(DISTINCT freight)仅限单列
OracleSUM(DISTINCT freight)仅限单列
所有数据库SELECT SUM(freight) FROM (SELECT DISTINCT order_id, freight FROM t) sub多列组合去重

五、性能优化建议

场景推荐写法原因
单列去重SUM(DISTINCT 列)简洁高效
多列组合去重子查询 + DISTINCT逻辑清晰
大数据量子查询 + GROUP BY比 DISTINCT 有时更优
复杂去重逻辑ROW_NUMBER() 窗口函数最灵活精确

六、总结

问题答案
单列去重求和怎么写?SUM(DISTINCT 列名)
多列组合去重求和怎么写?SELECT SUM(列) FROM (SELECT DISTINCT 列1, 列2 FROM 表) t
为什么要先去重?避免重复值被多次累加,导致结果错误
典型应用场景?运费计算、预算汇总、积分统计等

一句话总结:SQL 中进行多列求和时,如果需要先去掉重复值,单列可用 SUM(DISTINCT 列),多列组合则需要先用子查询(DISTINCT 或 GROUP BY)去重,再在外层求和,以避免重复数据被多次累加导致结果错误


标签: