数据查询语言(DQL)

深入学习MySQL SELECT查询语句

数据查询语言(DQL)概述

DQL(Data Query Language)是SQL语言中专门用于从数据库中查询数据的部分,核心命令是SELECT。SELECT语句是SQL中最常用和最复杂的语句,可以实现各种复杂的数据检索需求。

DQL的重要性

在数据库应用中,查询操作占据了绝大部分的比例。掌握DQL不仅能够提高数据检索效率,还能优化数据库性能,减少系统资源消耗。

SELECT语句的基本结构

SQL语法
SELECT [DISTINCT] column1, column2, ...
FROM table_name
WHERE condition
GROUP BY column1, column2, ...
HAVING condition
ORDER BY column1 [ASC|DESC], ...
LIMIT offset, count;

基本SELECT语句

查询所有列

使用星号(*)可以查询表中的所有列。这种方法简单方便,但在生产环境中应谨慎使用,因为它会返回所有列数据,可能导致不必要的网络传输和资源消耗。

SQL语法
SELECT * FROM table_name;
SQL示例
-- 查询用户表的所有数据
SELECT * FROM users;

查询指定列

明确指定需要查询的列名可以提高查询效率和代码可读性。

SQL语法
SELECT column1, column2, ... FROM table_name;
SQL示例
-- 查询用户的用户名和邮箱
SELECT username, email FROM users;

使用列别名

列别名可以使查询结果更易读,特别是在处理复杂的表达式或需要特定显示格式时。

SQL语法
SELECT 
    column_name AS alias_name,
    column_name alias_name  -- AS关键字可选
FROM table_name;
SQL示例
-- 使用列别名
SELECT 
    user_id AS id,
    username AS 用户名,
    email 邮箱,
    created_at '注册时间'
FROM users;

WHERE子句

WHERE子句用于过滤记录,只返回满足条件的行。它是SQL查询中最常用的子句之一。

WHERE子句中的运算符

运算符 描述 示例
= 等于 age = 25
<> 或 != 不等于 age <> 25
> 大于 age > 25
< 小于 age < 25
>= 大于等于 age >= 25
<= 小于等于 age <= 25
BETWEEN 在某个范围内 age BETWEEN 18 AND 65
LIKE 搜索某种模式 name LIKE '张%'
IN 指定多个可能的值 country IN ('中国', '美国')
IS NULL 为空值 phone IS NULL
IS NOT NULL 不为空值 phone IS NOT NULL

WHERE条件示例

SQL示例
-- 等于条件
SELECT * FROM users WHERE username = 'john_doe';

-- 不等于条件
SELECT * FROM users WHERE age <> 18;

-- 比较条件
SELECT * FROM products WHERE price > 100;

-- BETWEEN条件
SELECT * FROM users WHERE age BETWEEN 18 AND 65;

-- IN条件
SELECT * FROM users WHERE country IN ('China', 'USA', 'Japan');

-- LIKE条件(模糊匹配)
SELECT * FROM users WHERE username LIKE 'j%';      -- 以j开头
SELECT * FROM users WHERE email LIKE '%@gmail.com';  -- 以@gmail.com结尾
SELECT * FROM users WHERE name LIKE '%son%';     -- 包含son

-- IS NULL条件
SELECT * FROM users WHERE phone_number IS NULL;

-- 组合条件
SELECT * FROM users 
WHERE (age > 18 AND country = 'China') 
   OR (age > 21 AND country = 'USA');

ORDER BY子句

ORDER BY子句用于对结果集进行排序。可以按一个或多个列排序,每个列可以指定升序(ASC)或降序(DESC)。

基本ORDER BY语法

SQL语法
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;

ORDER BY示例

SQL示例
-- 单列排序
SELECT * FROM products ORDER BY price DESC;

-- 多列排序
SELECT * FROM users 
ORDER BY last_name ASC, first_name ASC;

-- 使用列位置排序
SELECT username, email, created_at 
FROM users 
ORDER BY 3 DESC;  -- 按第三列(created_at)降序排序

-- 使用表达式排序
SELECT product_name, price, stock_quantity 
FROM products 
ORDER BY price * stock_quantity DESC;

LIMIT子句

LIMIT子句用于限制返回的记录数量,常用于分页查询。

基本LIMIT语法

SQL语法
-- 限制返回记录数
SELECT column1, column2, ...
FROM table_name
LIMIT number;

-- 分页查询
SELECT column1, column2, ...
FROM table_name
LIMIT offset, number;

LIMIT示例

SQL示例
-- 返回前10条记录
SELECT * FROM users LIMIT 10;

-- 分页查询:第1页,每页10条
SELECT * FROM users LIMIT 0, 10;

-- 分页查询:第2页,每页10条
SELECT * FROM users LIMIT 10, 10;

-- 结合ORDER BY使用
SELECT * FROM products 
ORDER BY price DESC 
LIMIT 5;  -- 最贵的5个产品

DISTINCT关键字

DISTINCT关键字用于返回唯一不同的值,消除重复记录。

SQL示例
-- 返回不同的国家
SELECT DISTINCT country FROM users;

-- 返回不同的国家和城市组合
SELECT DISTINCT country, city FROM users;

-- 统计不同国家的数量
SELECT COUNT(DISTINCT country) FROM users;

聚合函数

聚合函数对一组值执行计算并返回单个值。它们通常与GROUP BY子句一起使用。

常用聚合函数

函数 描述 示例
COUNT() 返回行数 COUNT(*), COUNT(column)
SUM() 返回数值列的总和 SUM(price)
AVG() 返回数值列的平均值 AVG(price)
MAX() 返回最大值 MAX(price)
MIN() 返回最小值 MIN(price)
GROUP_CONCAT() 返回连接字符串 GROUP_CONCAT(name)

聚合函数示例

SQL示例
-- 统计用户总数
SELECT COUNT(*) FROM users;

-- 统计有电话号码的用户数量
SELECT COUNT(phone_number) FROM users;

-- 计算产品平均价格
SELECT AVG(price) FROM products;

-- 计算所有产品的总价值
SELECT SUM(price * stock_quantity) FROM products;

-- 找到最贵和最便宜的产品
SELECT MAX(price), MIN(price) FROM products;

GROUP BY子句

GROUP BY子句用于结合聚合函数,根据一个或多个列对结果集进行分组。

基本GROUP BY语法

SQL语法
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1;

GROUP BY示例

SQL示例
-- 按国家统计用户数量
SELECT country, COUNT(*) AS user_count
FROM users
GROUP BY country;

-- 按产品类别统计平均价格和库存总量
SELECT 
    category_id,
    AVG(price) AS avg_price,
    SUM(stock_quantity) AS total_stock
FROM products
GROUP BY category_id;

-- 多列分组
SELECT 
    country, 
    city, 
    COUNT(*) AS user_count
FROM users
GROUP BY country, city;

HAVING子句

HAVING子句用于对分组后的结果进行过滤,类似于WHERE子句,但用于聚合函数。

基本HAVING语法

SQL语法
SELECT column1, aggregate_function(column2)
FROM table_name
GROUP BY column1
HAVING condition;

HAVING示例

SQL示例
-- 查找用户数量超过100的国家
SELECT country, COUNT(*) AS user_count
FROM users
GROUP BY country
HAVING COUNT(*) > 100;

-- 查找平均价格超过50的产品类别
SELECT category_id, AVG(price) AS avg_price
FROM products
GROUP BY category_id
HAVING AVG(price) > 50;

-- 结合WHERE和HAVING
SELECT 
    country, 
    AVG(age) AS avg_age,
    COUNT(*) AS user_count
FROM users
WHERE age > 18  -- 先过滤成年用户
GROUP BY country
HAVING COUNT(*) > 50;  -- 再过滤用户数超过50的国家
WHERE vs HAVING:
  • WHERE在分组前过滤记录
  • HAVING在分组后过滤记录
  • WHERE不能使用聚合函数
  • HAVING可以使用聚合函数

完整SELECT语句结构

完整的SELECT语句包含以下子句,必须按照特定顺序书写:

SQL语法
SELECT [DISTINCT] column1, column2, ...
FROM table_name
WHERE condition
GROUP BY column1, column2, ...
HAVING condition
ORDER BY column1 [ASC|DESC], ...
LIMIT offset, count;

完整示例

SQL示例
-- 复杂的查询示例
SELECT 
    country,
    AVG(age) AS average_age,
    COUNT(*) AS user_count
FROM users
WHERE age >= 18
    AND created_at >= '2023-01-01'
GROUP BY country
HAVING COUNT(*) > 10
ORDER BY user_count DESC
LIMIT 0, 20;

UNION操作符

UNION操作符用于合并两个或多个SELECT语句的结果集。

SQL示例
-- 合并活跃用户和VIP用户
SELECT user_id, username, 'active' AS user_type
FROM users 
WHERE is_active = 1
UNION
SELECT user_id, username, 'vip' AS user_type
FROM vip_users;
UNION vs UNION ALL:
  • UNION会去除重复行
  • UNION ALL会保留所有行,包括重复行
  • UNION ALL性能更好,因为不需要去重

子查询

子查询是嵌套在其他SQL查询中的查询,可以用于WHERE、FROM或SELECT子句中。

子查询示例

SQL示例
-- 在WHERE子句中使用子查询
SELECT * FROM products 
WHERE price > (SELECT AVG(price) FROM products);

-- 在FROM子句中使用子查询
SELECT * 
FROM (SELECT country, COUNT(*) AS user_count 
      FROM users 
      GROUP BY country) AS country_stats
WHERE user_count > 100;

-- 在SELECT子句中使用子查询
SELECT 
    product_name,
    price,
    (SELECT AVG(price) FROM products) AS avg_price
FROM products;

性能优化建议

  • 尽量避免使用SELECT *,明确指定需要的列
  • 在WHERE子句中避免对列使用函数,这会使索引失效
  • 合理使用索引,特别是在WHERE和JOIN条件中的列
  • 对于大数据量的表,使用LIMIT限制返回结果
  • 避免在WHERE子句中使用!=或<>操作符
  • 使用EXISTS代替IN,特别是对于子查询

下一步学习

掌握了数据查询语言后,您可以继续学习: