LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

6个SQL去重关键字或操作符的对比

admin
2025年8月30日 12:51 本文热度 30

数据重复是数据库常见问题,易导致统计失真、存储冗余。下面我们系统了解 6 个 SQL 去重关键字或操作符,并系统梳理 SQL 去重方法,即从基础的 DISTINCT 到复杂的窗口函数,结合多数据库特性,让我们能从中精准选择去重方案。(所有代码块与表格都可以左右滚动)

1. DISTINCT:单表基础去重

DISTINCT 是 SQL 中用于消除查询结果集重复行的关键字。它作用于整个 SELECT 子句返回的所有列,仅保留组合值完全唯一的行。若查询多列,需所有列值均相同才算重复。例如: SELECT DISTINCT col1, col2 FROM table 会对两列组合去重。注意:DISTINCT 会隐式排序结果,可能影响性能,大数据量时建议结合索引优化。

原理:在查询结果集上直接过滤重复行,保留唯一值。
语法SELECT DISTINCT column1, column2 FROM table;
模拟数据

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    department VARCHAR(50)
);

INSERT INTO employees VALUES
(1, 'Alice''HR'),
(2, 'Bob''Engineering'),
(3, 'Alice''HR'),   -- 姓名重复
(4, 'Charlie''Marketing'),
(5, 'Bob''Engineering'); -- 姓名+部门重复

查询示例

-- 单列去重
SELECT DISTINCT name FROM employees;

/* 输出:
+----------+
| name     |
+----------+
| Alice    |
| Bob      |
| Charlie  |
+----------+
注释:重复的 'Alice' 和 'Bob' 被合并 */
-- 多列联合去重
SELECT DISTINCT name, department FROM employees;

/* 输出:
+----------+---------------+
| name     | department    |
+----------+---------------+
| Alice    | HR            |
| Bob      | Engineering   |
| Charlie  | Marketing     |
| Bob      | Engineering   | -- 此行保留(因id不同)
+----------+---------------+
注释:多列去重需所有字段值完全相同 */

2. GROUP BY:分组去重

GROUP BY 是 SQL 中按指定字段分组实现去重的关键字,可结合聚合函数(如 COUNT、MAX)处理分组数据。语法为 SELECT 列 FROM 表 GROUP BY 列,仅保留每组唯一值。例如按部门分组统计人数,比 DISTINCT 更灵活,支持复杂计算,大数据量下性能更优(依赖索引)。

原理:按指定字段分组实现去重,支持聚合计算。
语法SELECT column1, COUNT(*) FROM table GROUP BY column1;
查询示例

-- 统计每个部门的员工数
SELECT department, COUNT(*) AS employee_count
FROM employees
GROUP BY department;

/* 输出:
+---------------+----------------+
| department    | employee_count |
+---------------+----------------+
| HR            | 2              |
| Engineering   | 2              |
| Marketing     | 1              |
+---------------+----------------+
注释:按部门分组并计数 */

GROUP BY 与 DISTINCT 对比

均能去重,GROUP BY 按字段分组,支持聚合计算(如 COUNT),适合需统计分析的场景;DISTINCT 直接返回唯一行,语法更简洁。大数据量时 GROUP BY 性能可能更优(依赖索引),且结果可排序,而 DISTINCT 作用于全列组合,无分组逻辑。

3. UNION 与 UNION ALL:多结果集去重

在SQL中,UNION 和 UNION ALL 都是用于合并多个查询结果集的操作符,需保证各查询返回的列数、顺序和数据类型一致。

  • UNION:会对合并后的结果集自动去除重复行,相当于合并+去重,但可能因排序去重消耗更多性能。
  • UNION ALL:直接合并所有结果,包括重复行,不进行去重处理,执行效率更高。

实际使用时,若确认无重复或无需去重,优先用 UNION ALL 提升性能。

原理

  • UNION:拼接结果集后全局去重
  • UNION ALL:直接拼接保留重复项

模拟数据

CREATE TABLE hr_dept (id INT, name VARCHAR(50));
CREATE TABLE eng_dept (id INT, name VARCHAR(50));

INSERT INTO hr_dept VALUES (1, 'Alice'), (2, 'David');
INSERT INTO eng_dept VALUES (2, 'David'), (3, 'Bob'), (1, 'Alice');

查询对比

-- UNION:自动去重
SELECT name FROM hr_dept
UNION
SELECT name FROM eng_dept;

/* 输出:
+-------+
| name  |
+-------+
| Alice |
| David |
| Bob   |
+-------+ */
-- UNION ALL:保留所有记录
SELECT name FROM hr_dept
UNION ALL
SELECT name FROM eng_dept;

/* 输出:
+-------+
| name  |
+-------+
| Alice |
| David |
| David |
| Bob   |
| Alice |
+-------+ */

性能提示

  • UNION 需排序去重,大表慎用
  • UNION ALL 效率更高(无额外操作)

4. EXCEPT / MINUS:差集去重

EXCEPT / MINUS 是SQL中用于求差集的操作符,返回第一个查询结果中不存在于第二个查询的记录并去重。

  • EXCEPT支持SQL Server、PostgreSQL等;
  • MINUS是Oracle对EXCEPT的替代。

需两查询列数、类型一致,MySQL不支持,需用LEFT JOIN模拟。适用于查找数据集差异场景。具体拆解如下:

原理:返回第一个结果集,剔除第二个结果集的重复项。
数据库支持

数据库
语法
SQL Server
EXCEPT
Oracle
MINUS
MySQL
❌(需模拟)

模拟数据

CREATE TABLE all_products (id INT, name VARCHAR(50));
CREATE TABLE sold_products (id INT, name VARCHAR(50));

INSERT INTO all_products VALUES (1, 'Laptop'), (2, 'Phone'), (3, 'Tablet');
INSERT INTO sold_products VALUES (1, 'Laptop'), (3, 'Tablet');

标准实现

-- SQL Server/Oracle
SELECT * FROM all_products
EXCEPT
SELECT * FROM sold_products;  -- Oracle用MINUS

/* 输出:
+----+-------+
| id | name  |
+----+-------+
| 2  | Phone |
+----+-------+ */

MySQL替代方案

-- LEFT JOIN模拟
SELECT ap.* 
FROM all_products ap
LEFT JOIN sold_products sp ON ap.id = sp.id
WHERE sp.id IS NULL;

-- NOT IN模拟
SELECT * FROM all_products
WHERE id NOT IN (SELECT id FROM sold_products);

5. INTERSECT:交集去重

INTERSECT 是SQL中求交集的操作符,返回两个查询结果集中共有的记录并自动去重。需保证两查询列数、顺序和数据类型一致。
支持场景:如查找同时存在于两表的用户ID。
注意:MySQL不支持,需用INNER JOIN或IN子查询模拟;Oracle、SQL Server等主流数据库支持。性能依赖索引,大数据量慎用。具体介绍如下:

原理:返回两个结果集的共同项(自动去重)。
数据库支持

数据库
支持情况
SQL Server
Oracle
MySQL

模拟数据

CREATE TABLE all_members (id INT, name VARCHAR(50));
CREATE TABLE active_members (id INT, name VARCHAR(50));

INSERT INTO all_members VALUES (1, 'Tom'), (2, 'Jerry'), (3, 'Spike');
INSERT INTO active_members VALUES (1, 'Tom'), (3, 'Spike'), (4, 'Tyke');

标准实现

-- SQL Server/Oracle
SELECT * FROM all_members
INTERSECT
SELECT * FROM active_members;

/* 输出:
+----+-------+
| id | name  |
+----+-------+
| 1  | Tom   |
| 3  | Spike |
+----+-------+ */

MySQL替代方案

-- INNER JOIN模拟
SELECT am.* 
FROM all_members am
INNER JOIN active_members ac ON am.id = ac.id;

-- IN子查询模拟
SELECT * FROM all_members
WHERE id IN (SELECT id FROM active_members);

6. 高级去重技巧

1. 窗口函数去重

-- 保留每个部门最新入职记录
SELECT * FROM (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY department 
      ORDER BY hire_date DESC
    ) AS rn
  FROM employees
) t WHERE rn = 1;

2. 子查询去重

-- 查找有订单的用户
SELECT * FROM users 
WHERE user_id IN (
  SELECT DISTINCT user_id FROM orders
);

3. DELETE去重

-- 删除重复邮箱记录
DELETE FROM users 
WHERE user_id NOT IN (
  SELECT MIN(user_id) 
  FROM users 
  GROUP BY email
);

7. 数据库去重差异参考表

功能
MySQL
Oracle
SQL Server
EXCEPT
❌ (LEFT JOIN模拟)
✅ (MINUS)
INTERSECT
❌ (JOIN模拟)
ROW_NUMBER
8.0+ ✅
ROWID
❌ (ROWVERSION替代)

8. 去重性能优化指南

  1. 索引策略

    -- 为去重字段创建索引
    CREATE INDEX idx_dept ON employees(department);
  2. 方法选择

    • 使用EXISTS替代IN
    • 分批处理:LIMIT 1000 + 循环
    • 避免SELECT *,只取必要字段
    • 小数据量:优先用DISTINCT
    • 大数据量:
  3. 去重代价排序(效率降序):
    UNION ALL > DISTINCT ≈ GROUP BY > UNION > EXCEPT/INTERSECT

9. 去重应用场景速查表

场景
推荐方法
示例片段
单表去重
DISTINCT/GROUP BY
SELECT DISTINCT dept FROM emp
多表合并去重
UNION
SELECT col FROM A UNION SELECT col FROM B
保留最新记录
ROW_NUMBER()
PARTITION BY id ORDER BY date DESC
删除重复数据
DELETE + 子查询
DELETE WHERE id NOT IN (SELECT MIN(id)...)
查找差异数据
EXCEPT/MINUS
SELECT FROM A EXCEPT SELECT FROM B
查找交集数据
INTERSECT
SELECT FROM A INTERSECT SELECT FROM B

10. SQL去重方法总结

SQL去重方法主要有三类:

  1. 基础去重DISTINCTGROUP BY适合单表操作
  2. 集合运算UNION/EXCEPT/INTERSECT处理多结果集
  3. 高级技巧:窗口函数和子查询解决复杂场景

选择依据:

  • 数据量大小(小数据用DISTINCT,大数据用GROUP BY
  • 数据库支持(MySQL需注意语法差异)
  • 业务需求(是否需要聚合计算、是否需物理删除等)

SQL 去重需兼顾场景与性能,小数据用 DISTINCT,大数据靠索引与分批。理解这些方法原理、差异及组合使用,可高效解决实际工作中的各类重复问题,提升数据质量。


阅读原文:原文链接


该文章在 2025/9/1 12:18:25 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved