SQL DISTINCT 关键字
在 PostgreSQL(以及标准 SQL)中,DISTINCT 关键字是进行数据分析和报表生成的强大工具。它允许你从表的一列或多列组合中识别并仅检索唯一的值(即去重后的数据)。当处理包含大量冗余信息的数据集,且需要清晰了解当前存在哪些不同的类别或条目时,这个功能尤为有用。了解如何有效地使用 DISTINCT 是编写高效、准确的 SQL 查询的关键一步。
1. 了解 DISTINCT 子句
DISTINCT 子句通常与 SELECT 语句结合使用,用于从结果集中消除重复的行。它可以应用于表中的一个或多个列。
基础语法如下:
SELECT DISTINCT column1, column2, ...
FROM table_name;当 DISTINCT 应用于多个列时,它仅返回这些列中值的唯一组合。请务必记住,DISTINCT 将 NULL(空值)也视为一种特定的、独立的值。这意味着如果某一列包含多个 NULL 值,DISTINCT 在结果集中只会返回一个 NULL 值。
1.1 单列 DISTINCT
让我们从一个简单的例子开始,假设有一个名为 customers(客户)的表,包含以下数据:
| customer_id (客户 ID) | name (姓名) | city (城市) |
|---|---|---|
| 1 | John Doe | New York (纽约) |
| 2 | Jane Smith | London (伦敦) |
| 3 | Peter Jones | New York (纽约) |
| 4 | Mary Brown | Paris (巴黎) |
| 5 | John Doe | New York (纽约) |
若要检索不重复的城市列表,你可以使用以下查询:
SELECT DISTINCT city
FROM customers;此查询将返回:
| city (城市) |
|---|
| New York (纽约) |
| London (伦敦) |
| Paris (巴黎) |
请注意,尽管在原始表中“New York”出现了三次,但在结果集中它只出现了一次。
1.2 多列 DISTINCT
现在,假设我们想要查找“姓名”和“城市”的唯一组合。使用相同的 customers 表,我们可以执行以下查询:
SELECT DISTINCT name, city
FROM customers;此查询将返回:
| name (姓名) | city (城市) |
|---|---|
| John Doe | New York (纽约) |
| Jane Smith | London (伦敦) |
| Peter Jones | New York (纽约) |
| Mary Brown | Paris (巴黎) |
尽管 "John Doe" 和 "New York" 各自单独出现了多次,但由于我们同时对这两列使用了 DISTINCT,系统会将它们作为一个组合来考虑。结果集中 "John Doe" 和 "New York" 的组合只出现了一次(即使客户 ID 1 和 5 具有完全相同的姓名和城市)。
1.3 DISTINCT 与 NULL 值
考虑下面这个名为 products(产品)的表:
| product_id (产品 ID) | product_name (产品名称) | category (类别) |
|---|---|---|
| 1 | Laptop (笔记本电脑) | Tech (科技) |
| 2 | Mouse (鼠标) | Tech (科技) |
| 3 | Keyboard (键盘) | Tech (科技) |
| 4 | Monitor (显示器) | NULL |
| 5 | Speaker (音箱) | NULL |
如果我们运行以下查询:
SELECT DISTINCT category
FROM products;结果将是:
| category (类别) |
|---|
| Tech (科技) |
| NULL |
如你所见,DISTINCT 将 NULL 视为一个独立且唯一的值。在处理可能包含缺失值(空值)的数据时,了解这一点非常重要。
2. 实际案例与演示
让我们在不同的业务场景中探索更多使用 DISTINCT 的实际案例。假设你正在为一个在线商店管理数据库。
2.1 案例 1:查找唯一的产品类别
你想找出 products 表中所有不重复的产品类别。表结构可能如下所示:
| product_id | product_name | category | price |
|---|---|---|---|
| 1 | Laptop | Electronics (电子产品) | 1200 |
| 2 | Mouse | Electronics (电子产品) | 25 |
| 3 | Keyboard | Electronics (电子产品) | 75 |
| 4 | T-Shirt | Apparel (服装) | 20 |
| 5 | Jeans | Apparel (服装) | 60 |
| 6 | Coffee Maker | Home Goods (家居用品) | 50 |
| 7 | Blender | Home Goods (家居用品) | 100 |
| 8 | Toaster | Home Goods (家居用品) | 40 |
| 9 | Book | Books (图书) | 15 |
| 10 | E-Book | Books (图书) | 10 |
要检索唯一的类别,你可以使用以下查询:
SELECT DISTINCT category
FROM products;这将返回:
| category |
|---|
| Electronics (电子产品) |
| Apparel (服装) |
| Home Goods (家居用品) |
| Books (图书) |
2.2 案例 2:查找送货城市和州/省的唯一组合
考虑一个名为 orders(订单)的表,结构如下:
| order_id | customer_id | shipping_city (送货城市) | shipping_state (送货州) | order_date |
|---|---|---|---|---|
| 1 | 101 | New York | NY | 2023-01-01 |
| 2 | 102 | Los Angeles | CA | 2023-01-02 |
| 3 | 101 | New York | NY | 2023-01-03 |
| 4 | 103 | Chicago | IL | 2023-01-04 |
| 5 | 102 | Los Angeles | CA | 2023-01-05 |
| 6 | 104 | Houston | TX | 2023-01-06 |
| 7 | 105 | Houston | TX | 2023-01-07 |
要找到送货城市和州的唯一组合,你可以使用以下查询:
SELECT DISTINCT shipping_city, shipping_state
FROM orders;这将返回:
| shipping_city | shipping_state |
|---|---|
| New York | NY |
| Los Angeles | CA |
| Chicago | IL |
| Houston | TX |
2.3 案例 3:处理大小写敏感问题
PostgreSQL 默认是区分大小写的。如果你处理的是英文文本数据,这可能会影响 DISTINCT 查询的结果。例如,考虑以下 colors(颜色)表:
| color_id | color_name |
|---|---|
| 1 | Red |
| 2 | red |
| 3 | Green |
| 4 | Blue |
如果你运行以下查询:
SELECT DISTINCT color_name
FROM colors;结果将包含大小写不同的重复项:
| color_name |
|---|
| Red |
| red |
| Green |
| Blue |
要将首字母大写的 "Red" 和全小写的 "red" 视为同一个值,你可以使用 LOWER() 函数在应用 DISTINCT 之前将所有值统一转换为小写:
SELECT DISTINCT LOWER(color_name)
FROM colors;这将返回彻底去重后的结果:
| lower |
|---|
| red |
| green |
| blue |