基础查询 #

一、SELECT基础 #

1.1 基本语法 #

sql
-- 基本查询语法
SELECT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column
LIMIT n;

-- 示例表
CREATE TABLE employees (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    department VARCHAR(50),
    salary DECIMAL(10, 2),
    hire_date DATE,
    status VARCHAR(20) DEFAULT 'active'
);

INSERT INTO employees (name, department, salary, hire_date, status) VALUES
    ('Alice', 'Engineering', 80000, '2020-01-15', 'active'),
    ('Bob', 'Sales', 65000, '2019-06-20', 'active'),
    ('Carol', 'Engineering', 90000, '2018-03-10', 'active'),
    ('David', 'Marketing', 70000, '2021-02-28', 'active'),
    ('Eve', 'Engineering', 85000, '2020-08-05', 'inactive'),
    ('Frank', 'Sales', 60000, '2022-01-01', 'active'),
    ('Grace', 'HR', 55000, '2019-11-15', 'active'),
    ('Henry', 'Engineering', 95000, '2017-05-20', 'active');

-- 查询所有列
SELECT * FROM employees;

-- 查询指定列
SELECT name, department, salary FROM employees;

1.2 列别名 #

sql
-- 使用 AS 设置列别名
SELECT 
    name AS employee_name,
    department AS dept,
    salary AS monthly_salary
FROM employees;

-- 别名可以省略 AS
SELECT name employee_name, department dept FROM employees;

-- 使用表达式别名
SELECT 
    name,
    salary,
    salary * 12 AS annual_salary
FROM employees;

1.3 去重查询 #

sql
-- DISTINCT 去重
SELECT DISTINCT department FROM employees;

-- 多列去重
SELECT DISTINCT department, status FROM employees;

-- 计算去重数量
SELECT COUNT(DISTINCT department) AS dept_count FROM employees;

二、WHERE条件 #

2.1 比较运算符 #

sql
-- 等于
SELECT * FROM employees WHERE department = 'Engineering';

-- 不等于
SELECT * FROM employees WHERE status != 'inactive';
SELECT * FROM employees WHERE status <> 'inactive';

-- 大于、小于
SELECT * FROM employees WHERE salary > 80000;
SELECT * FROM employees WHERE salary >= 80000;
SELECT * FROM employees WHERE salary < 70000;
SELECT * FROM employees WHERE salary <= 70000;

-- 日期比较
SELECT * FROM employees WHERE hire_date > '2020-01-01';
SELECT * FROM employees WHERE hire_date >= '2020-01-01';

2.2 逻辑运算符 #

sql
-- AND 与
SELECT * FROM employees 
WHERE department = 'Engineering' AND salary > 85000;

-- OR 或
SELECT * FROM employees 
WHERE department = 'Engineering' OR department = 'Sales';

-- NOT 非
SELECT * FROM employees 
WHERE NOT status = 'inactive';

-- 组合使用
SELECT * FROM employees 
WHERE (department = 'Engineering' OR department = 'Sales')
  AND salary > 70000;

2.3 范围查询 #

sql
-- BETWEEN ... AND
SELECT * FROM employees 
WHERE salary BETWEEN 60000 AND 80000;

-- 等价于
SELECT * FROM employees 
WHERE salary >= 60000 AND salary <= 80000;

-- 日期范围
SELECT * FROM employees 
WHERE hire_date BETWEEN '2020-01-01' AND '2021-12-31';

-- NOT BETWEEN
SELECT * FROM employees 
WHERE salary NOT BETWEEN 60000 AND 80000;

2.4 IN和NOT IN #

sql
-- IN 列表
SELECT * FROM employees 
WHERE department IN ('Engineering', 'Sales');

-- 等价于
SELECT * FROM employees 
WHERE department = 'Engineering' OR department = 'Sales';

-- NOT IN
SELECT * FROM employees 
WHERE department NOT IN ('HR', 'Marketing');

-- 子查询 IN
SELECT * FROM employees 
WHERE department IN (
    SELECT DISTINCT department FROM employees WHERE salary > 80000
);

2.5 LIKE模糊匹配 #

sql
-- % 匹配任意字符
SELECT * FROM employees WHERE name LIKE 'A%';    -- 以A开头
SELECT * FROM employees WHERE name LIKE '%e';    -- 以e结尾
SELECT * FROM employees WHERE name LIKE '%a%';   -- 包含a

-- _ 匹配单个字符
SELECT * FROM employees WHERE name LIKE '_ob';   -- 第二个字符开始是ob
SELECT * FROM employees WHERE name LIKE 'A____'; -- A开头,共5个字符

-- NOT LIKE
SELECT * FROM employees WHERE name NOT LIKE 'A%';

-- 转义特殊字符
SELECT * FROM employees WHERE name LIKE '%\%%';  -- 包含%
SELECT * FROM employees WHERE name LIKE '%\_%';  -- 包含_

2.6 NULL处理 #

sql
-- IS NULL
SELECT * FROM employees WHERE department IS NULL;

-- IS NOT NULL
SELECT * FROM employees WHERE department IS NOT NULL;

-- NULL 比较注意
SELECT * FROM employees WHERE department = NULL;  -- 错误!不会返回结果
SELECT * FROM employees WHERE department IS NULL; -- 正确

-- COALESCE 处理 NULL
SELECT 
    name,
    COALESCE(department, 'Unassigned') AS dept
FROM employees;

-- IFNULL 处理 NULL
SELECT 
    name,
    IFNULL(department, 'Unassigned') AS dept
FROM employees;

三、ORDER BY排序 #

3.1 基本排序 #

sql
-- 升序 (默认)
SELECT * FROM employees ORDER BY salary;
SELECT * FROM employees ORDER BY salary ASC;

-- 降序
SELECT * FROM employees ORDER BY salary DESC;

-- 多列排序
SELECT * FROM employees 
ORDER BY department ASC, salary DESC;

-- 按列位置排序
SELECT name, salary FROM employees 
ORDER BY 2 DESC;  -- 按第二列排序

3.2 表达式排序 #

sql
-- 按表达式排序
SELECT name, salary, salary * 12 AS annual_salary
FROM employees
ORDER BY salary * 12 DESC;

-- 使用别名排序
SELECT name, salary, salary * 12 AS annual_salary
FROM employees
ORDER BY annual_salary DESC;

3.3 NULL排序 #

sql
-- NULL 值排序
-- 默认: 升序时 NULL 在前,降序时 NULL 在后

-- 使用 IS NULL 控制顺序
SELECT * FROM employees 
ORDER BY department IS NULL, department;

-- 或使用 COALESCE
SELECT * FROM employees 
ORDER BY COALESCE(department, 'ZZZ');

四、LIMIT分页 #

4.1 基本分页 #

sql
-- 限制返回行数
SELECT * FROM employees LIMIT 5;

-- 跳过前N行
SELECT * FROM employees LIMIT 3, 5;  -- 跳过前3行,返回5行

-- 推荐写法
SELECT * FROM employees LIMIT 5 OFFSET 3;  -- 跳过前3行,返回5行

-- 分页查询
-- 第1页 (每页10条)
SELECT * FROM employees ORDER BY id LIMIT 10 OFFSET 0;

-- 第2页
SELECT * FROM employees ORDER BY id LIMIT 10 OFFSET 10;

-- 第N页
SELECT * FROM employees ORDER BY id LIMIT 10 OFFSET (N-1)*10;

4.2 分页优化 #

sql
-- 传统分页 (大数据量时性能差)
SELECT * FROM employees ORDER BY id LIMIT 10 OFFSET 1000000;

-- 优化方式1: 使用 WHERE 条件
SELECT * FROM employees 
WHERE id > 1000000 
ORDER BY id LIMIT 10;

-- 优化方式2: 使用子查询
SELECT * FROM employees 
WHERE id IN (
    SELECT id FROM employees 
    ORDER BY id LIMIT 10 OFFSET 1000000
)
ORDER BY id;

-- 优化方式3: 记住上一页最后ID
SELECT * FROM employees 
WHERE id > ?  -- 上一页最后ID
ORDER BY id LIMIT 10;

4.3 获取总数 #

sql
-- 获取总记录数
SELECT COUNT(*) AS total FROM employees;

-- 分页查询带总数
SELECT 
    (SELECT COUNT(*) FROM employees) AS total,
    e.*
FROM employees e
ORDER BY id
LIMIT 10 OFFSET 0;

五、聚合函数 #

5.1 基本聚合 #

sql
-- COUNT 计数
SELECT COUNT(*) AS total_count FROM employees;
SELECT COUNT(department) AS dept_count FROM employees;  -- 不计NULL
SELECT COUNT(DISTINCT department) AS unique_depts FROM employees;

-- SUM 求和
SELECT SUM(salary) AS total_salary FROM employees;

-- AVG 平均值
SELECT AVG(salary) AS avg_salary FROM employees;

-- MAX 最大值
SELECT MAX(salary) AS max_salary FROM employees;

-- MIN 最小值
SELECT MIN(salary) AS min_salary FROM employees;

-- 组合使用
SELECT 
    COUNT(*) AS total,
    SUM(salary) AS total_salary,
    AVG(salary) AS avg_salary,
    MAX(salary) AS max_salary,
    MIN(salary) AS min_salary
FROM employees;

5.2 GROUP BY分组 #

sql
-- 按部门分组统计
SELECT 
    department,
    COUNT(*) AS employee_count,
    AVG(salary) AS avg_salary,
    SUM(salary) AS total_salary
FROM employees
GROUP BY department;

-- 多列分组
SELECT 
    department,
    status,
    COUNT(*) AS count,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department, status;

-- 使用表达式分组
SELECT 
    CASE 
        WHEN salary < 60000 THEN 'Low'
        WHEN salary < 80000 THEN 'Medium'
        ELSE 'High'
    END AS salary_level,
    COUNT(*) AS count
FROM employees
GROUP BY 
    CASE 
        WHEN salary < 60000 THEN 'Low'
        WHEN salary < 80000 THEN 'Medium'
        ELSE 'High'
    END;

5.3 HAVING过滤 #

sql
-- HAVING 过滤分组结果
SELECT 
    department,
    COUNT(*) AS employee_count,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING COUNT(*) > 1;

-- HAVING vs WHERE
-- WHERE 过滤行,HAVING 过滤分组
SELECT 
    department,
    COUNT(*) AS employee_count,
    AVG(salary) AS avg_salary
FROM employees
WHERE status = 'active'  -- 先过滤行
GROUP BY department
HAVING AVG(salary) > 70000;  -- 再过滤分组

-- 复杂 HAVING 条件
SELECT 
    department,
    COUNT(*) AS employee_count,
    AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING COUNT(*) > 1 AND AVG(salary) > 60000;

5.4 WITH ROLLUP #

sql
-- 分组汇总
SELECT 
    department,
    status,
    COUNT(*) AS count,
    SUM(salary) AS total_salary
FROM employees
GROUP BY department, status WITH ROLLUP;

-- 结果包含:
-- 每个部门每种状态的统计
-- 每个部门的小计 (status 为 NULL)
-- 总计 (department 和 status 都为 NULL)

六、常用函数 #

6.1 字符串函数 #

sql
-- 字符串拼接
SELECT CONCAT(name, ' - ', department) AS info FROM employees;
SELECT CONCAT_WS(' - ', name, department) AS info FROM employees;

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

-- 字符串长度
SELECT name, LENGTH(name), CHAR_LENGTH(name) FROM employees;

-- 截取字符串
SELECT SUBSTRING(name, 1, 3) FROM employees;  -- 前3个字符
SELECT LEFT(name, 3), RIGHT(name, 3) FROM employees;

-- 查找替换
SELECT REPLACE(name, 'a', 'A') FROM employees;
SELECT INSTR(name, 'a') FROM employees;  -- 查找位置

-- 去除空格
SELECT TRIM(name), LTRIM(name), RTRIM(name) FROM employees;

6.2 数值函数 #

sql
-- 四舍五入
SELECT ROUND(salary, 0) FROM employees;
SELECT ROUND(salary, -3) FROM employees;  -- 千位四舍五入

-- 向上/向下取整
SELECT CEILING(salary), FLOOR(salary) FROM employees;

-- 取模
SELECT id, id % 2 FROM employees;

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

-- 幂运算
SELECT POWER(2, 10);  -- 2的10次方

-- 随机数
SELECT RAND();
SELECT FLOOR(RAND() * 100);  -- 0-99随机数

6.3 日期函数 #

sql
-- 当前日期时间
SELECT NOW(), CURRENT_TIMESTAMP();
SELECT CURRENT_DATE(), CURRENT_TIME();

-- 日期提取
SELECT 
    hire_date,
    YEAR(hire_date) AS year,
    MONTH(hire_date) AS month,
    DAY(hire_date) AS day,
    DAYOFWEEK(hire_date) AS weekday,
    DAYNAME(hire_date) AS weekday_name,
    WEEK(hire_date) AS week,
    QUARTER(hire_date) AS quarter
FROM employees;

-- 日期计算
SELECT 
    hire_date,
    DATE_ADD(hire_date, INTERVAL 1 YEAR) AS one_year_later,
    DATE_SUB(hire_date, INTERVAL 1 MONTH) AS one_month_ago,
    DATEDIFF(NOW(), hire_date) AS days_employed
FROM employees;

-- 日期格式化
SELECT 
    hire_date,
    DATE_FORMAT(hire_date, '%Y年%m月%d日') AS formatted_date
FROM employees;

-- 日期比较
SELECT * FROM employees 
WHERE hire_date > DATE_SUB(NOW(), INTERVAL 2 YEAR);

6.4 条件函数 #

sql
-- IF 函数
SELECT 
    name,
    salary,
    IF(salary > 70000, 'High', 'Low') AS salary_level
FROM employees;

-- IFNULL 函数
SELECT 
    name,
    IFNULL(department, 'Unassigned') AS dept
FROM employees;

-- NULLIF 函数
SELECT NULLIF(1, 1);  -- 返回 NULL
SELECT NULLIF(1, 2);  -- 返回 1

-- CASE 表达式
-- 简单 CASE
SELECT 
    name,
    department,
    CASE department
        WHEN 'Engineering' THEN 'Tech'
        WHEN 'Sales' THEN 'Business'
        ELSE 'Other'
    END AS dept_type
FROM employees;

-- 搜索 CASE
SELECT 
    name,
    salary,
    CASE 
        WHEN salary < 60000 THEN 'Low'
        WHEN salary < 80000 THEN 'Medium'
        ELSE 'High'
    END AS salary_level
FROM employees;

七、查询优化 #

7.1 使用索引 #

sql
-- 创建索引
CREATE INDEX idx_department ON employees(department);
CREATE INDEX idx_salary ON employees(salary);

-- 使用索引的查询
SELECT * FROM employees WHERE department = 'Engineering';
SELECT * FROM employees WHERE salary > 80000;

-- 查看执行计划
EXPLAIN SELECT * FROM employees WHERE department = 'Engineering';

7.2 避免全表扫描 #

sql
-- 避免 SELECT *
SELECT name, department, salary FROM employees;

-- 使用覆盖索引
CREATE INDEX idx_dept_salary ON employees(department, salary);

SELECT department, salary FROM employees WHERE department = 'Engineering';

-- 避免在索引列上使用函数
-- 不推荐
SELECT * FROM employees WHERE UPPER(department) = 'ENGINEERING';
-- 推荐
SELECT * FROM employees WHERE department = 'Engineering';

7.3 查询提示 #

sql
-- 使用索引提示
SELECT /*+ USE_INDEX(employees idx_department) */ 
* FROM employees WHERE department = 'Engineering';

-- 强制使用索引
SELECT /*+ FORCE_INDEX(employees idx_department) */ 
* FROM employees WHERE department = 'Engineering';

-- 忽略索引
SELECT /*+ IGNORE_INDEX(employees idx_department) */ 
* FROM employees WHERE department = 'Engineering';

八、总结 #

SELECT 语句要点:

类型 说明
基本查询 列选择、别名、去重
WHERE条件 比较、逻辑、范围、模糊匹配
ORDER BY 升序降序、多列排序
LIMIT分页 分页查询、优化技巧
聚合函数 COUNT、SUM、AVG、MAX、MIN
GROUP BY 分组统计、HAVING过滤
常用函数 字符串、数值、日期、条件

下一步,让我们学习多表连接查询!

最后更新:2026-03-27