跳到主要内容

SELECT 查询

SELECT 是 SQL 中最常用的语句,用于从数据库中查询数据。本章将详细介绍 SELECT 的各种用法。

基本 SELECT

查询所有列

使用 * 查询表中的所有列:

SELECT * FROM users;

* 表示所有列,这在探索数据时很方便,但在生产代码中不推荐使用,因为:

  • 可能返回不需要的列,浪费资源
  • 表结构变化时可能产生意外结果

查询指定列

明确列出需要的列名:

SELECT name, email FROM users;

这是推荐的做法,因为:

  • 只返回需要的数据,效率更高
  • 代码更清晰,易于理解
  • 表结构变化时不会受影响

列别名

使用 AS 关键字为列设置别名:

SELECT 
name AS 姓名,
email AS 邮箱,
age AS 年龄
FROM users;

AS 关键字可以省略:

SELECT name 姓名, email 邮箱 FROM users;

别名的作用:

  • 使结果更易读
  • 为计算列命名
  • 解决列名冲突

DISTINCT 去重

使用 DISTINCT 关键字去除重复值:

-- 查询所有不同的城市
SELECT DISTINCT city FROM users;

-- 多列去重(组合唯一)
SELECT DISTINCT city, country FROM users;

去重的原理:比较所有选中列的值,完全相同才认为是重复。

-- 示例数据
-- | city | country |
-- |---------|---------|
-- | 北京 | 中国 |
-- | 上海 | 中国 |
-- | 北京 | 中国 | <- 与第一行重复

SELECT DISTINCT city, country FROM users;
-- 结果:
-- | city | country |
-- |---------|---------|
-- | 北京 | 中国 |
-- | 上海 | 中国 |

LIMIT 限制结果

基本用法

限制返回的行数:

-- MySQL / PostgreSQL / SQLite
SELECT * FROM users LIMIT 10;

-- SQL Server
SELECT TOP 10 * FROM users;

-- Oracle
SELECT * FROM users WHERE ROWNUM <= 10;

分页查询

结合 OFFSET 实现分页:

-- MySQL / PostgreSQL / SQLite
-- 每页 10 条,第 2 页(跳过前 10 条)
SELECT * FROM users LIMIT 10 OFFSET 10;

-- 简写形式(MySQL)
SELECT * FROM users LIMIT 10, 10; -- LIMIT offset, count

分页公式:

-- 第 page 页,每页 size 条
SELECT * FROM users LIMIT size OFFSET (page - 1) * size;

计算列

SELECT 可以包含计算表达式:

算术运算

SELECT 
product_name,
price,
quantity,
price * quantity AS total_price,
price * 0.9 AS discount_price
FROM order_items;

支持的运算符:+-*/

字符串拼接

-- MySQL
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;

-- PostgreSQL / Oracle
SELECT first_name || ' ' || last_name AS full_name FROM users;

-- SQL Server
SELECT first_name + ' ' + last_name AS full_name FROM users;

条件表达式

使用 CASE WHEN 进行条件判断:

SELECT 
name,
score,
CASE
WHEN score >= 90 THEN '优秀'
WHEN score >= 80 THEN '良好'
WHEN score >= 60 THEN '及格'
ELSE '不及格'
END AS grade
FROM students;

常用函数

字符串函数

-- 转换大小写
SELECT UPPER(name) FROM users; -- 大写
SELECT LOWER(name) FROM users; -- 小写

-- 字符串长度
SELECT LENGTH(name) FROM users; -- MySQL / PostgreSQL
SELECT LEN(name) FROM users; -- SQL Server

-- 截取字符串
SELECT SUBSTRING(name, 1, 3) FROM users; -- 从第1个字符开始,取3个字符
SELECT LEFT(name, 3) FROM users; -- 取左边3个字符
SELECT RIGHT(name, 3) FROM users; -- 取右边3个字符

-- 去除空格
SELECT TRIM(name) FROM users; -- 去除两端空格
SELECT LTRIM(name) FROM users; -- 去除左边空格
SELECT RTRIM(name) FROM users; -- 去除右边空格

数值函数

-- 四舍五入
SELECT ROUND(3.14159, 2); -- 3.14

-- 向上取整
SELECT CEIL(3.14); -- 4

-- 向下取整
SELECT FLOOR(3.14); -- 3

-- 绝对值
SELECT ABS(-10); -- 10

-- 取模
SELECT MOD(10, 3); -- 1

日期函数

-- 当前日期和时间
SELECT NOW(); -- MySQL / PostgreSQL
SELECT GETDATE(); -- SQL Server
SELECT SYSDATE; -- Oracle

-- 当前日期
SELECT CURRENT_DATE; -- PostgreSQL / MySQL

-- 提取日期部分
SELECT YEAR(created_at) FROM orders; -- 提取年份
SELECT MONTH(created_at) FROM orders; -- 提取月份
SELECT DAY(created_at) FROM orders; -- 提取日期

-- 日期计算
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY); -- MySQL:加7天
SELECT created_at + INTERVAL '7 days' FROM orders; -- PostgreSQL

类型转换

-- CAST 函数(标准 SQL)
SELECT CAST(price AS CHAR) FROM products;
SELECT CAST('123' AS INT);

-- MySQL 特有
SELECT CONVERT(price, CHAR) FROM products;

NULL 值处理

NULL 表示缺失或未知的值,需要特殊处理:

NULL 的特点

-- NULL 与任何值比较都返回 NULL(不是 true 或 false)
SELECT * FROM users WHERE age = NULL; -- 错误!不会返回任何结果
SELECT * FROM users WHERE age != NULL; -- 错误!不会返回任何结果

-- 正确的 NULL 比较
SELECT * FROM users WHERE age IS NULL; -- 查询 NULL 值
SELECT * FROM users WHERE age IS NOT NULL; -- 查询非 NULL 值

COALESCE 函数

返回第一个非 NULL 值:

SELECT 
name,
COALESCE(phone, mobile, '无联系方式') AS contact
FROM users;

IFNULL / NVL / ISNULL

不同数据库的 NULL 处理函数:

-- MySQL
SELECT IFNULL(phone, '未知') FROM users;

-- Oracle
SELECT NVL(phone, '未知') FROM users;

-- SQL Server
SELECT ISNULL(phone, '未知') FROM users;

NULLIF 函数

如果两个值相等则返回 NULL:

-- 避免除以零错误
SELECT total / NULLIF(count, 0) AS average FROM orders;

表别名

使用 AS 为表设置别名,简化 SQL 并提高可读性:

SELECT u.name, o.order_date
FROM users AS u
JOIN orders AS o ON u.id = o.user_id;

-- AS 可以省略
SELECT u.name, o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id;

表别名的作用:

  • 简化长表名
  • 消除多表连接时的列名冲突
  • 自连接时区分同一表的不同实例

小结

本章我们学习了:

  1. 基本 SELECT 语法
  2. 使用 DISTINCT 去重
  3. 使用 LIMIT 限制结果
  4. 计算列和表达式
  5. 常用函数(字符串、数值、日期)
  6. NULL 值处理
  7. 表别名

练习

  1. 查询 users 表的 name 和 email 列,并为它们设置中文别名
  2. 查询 products 表中不同的 category
  3. 计算订单表中每个订单的总金额(单价 × 数量)
  4. 查询 users 表的前 20 条记录
  5. 使用 CASE WHEN 将分数转换为等级