目录
- 1 DQL简介
- 2 数据集准备
- 3 select查询简介
- 4 条件查询
-
- 4.1 条件查询简介
- 4.2 比较查询
- 4.3 范围查询
- 4.4 模糊查询
- 4.5 非空查询
- 4.6 逻辑查询
- 5 排序查询
- 6 聚合查询
- 7 分组查询与having子句
-
- 7.1 分组查询简介
- 7.2 group by的使用
- 7.3 group by + 聚合函数的使用
- 7.4 group by + having的使用
- 8 limit分页查询
- 9 多表查询
-
- 9.1 交叉连接(了解)
-
- (1)交叉连接
- (2)笛卡尔积
- 9.2 连接查询
-
- (1)连接查询的介绍
- (2)内连接查询
- (3)左外连接查询
- (4)右外连接查询
- (5)全外连接查询
- 10 子查询
-
- 10.1 子查询简介
- 10.2 子查询的使用
授课老师:杨殿杰
1 DQL简介
DQL是指数据库查询语言(Data Query Language),用于从数据库中检索数据。
最常见的DQL语句是SELECT,它用于从一个或多个表中查询数据,并返回满足指定条件的结果集。
以下是常见的DQL语句和其功能:
- SELECT:用于从数据库中查询数据。
例:SELECT column1, column2 FROM mytable WHERE condition;
- FROM:指定要查询的数据表。
例:SELECT column1, column2 FROM mytable;
- WHERE:指定查询过滤条件。
例:SELECT column1, column2 FROM mytable WHERE condition;
- GROUP BY:按照指定的列对查询结果进行分组。
例:SELECT column1, COUNT(column2) FROM mytable GROUP BY column1;
- HAVING:指定对分组后的结果进行过滤的条件。
例:SELECT column1, COUNT(column2) FROM mytable GROUP BY column1 HAVING COUNT(column2) > 10;
- ORDER BY:指定查询结果的排序顺序。
例:SELECT column1, column2 FROM mytable ORDER BY column1 ASC;
- JOIN:用于将多个表按照某些条件连接在一起进行查询。
例:SELECT t1.column1, t2.column2 FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id;
注意1:除了SELECT语句,DQL还可以包括其他一些语句,如子查询语句(将一个查询结果作为另一个查询的输入)、WITH语句(定义可重用的查询块)、UNION操作(将多个查询结果合并)等。
注意2:DQL语句是用于查询数据的,不会对数据库中的数据进行修改。如果需要修改数据,则需要使用DML语句(如INSERT、UPDATE和DELETE)或DDL语句(如CREATE和ALTER)来操作数据库。
2 数据集准备
CREATE TABLE product ( pid INT PRIMARY KEY, pname VARCHAR(20), price DOUBLE, category_id VARCHAR(32) );
插入数据:
INSERT INTO product VALUES (1,'联想',5000,'c001’); INSERT INTO product VALUES (2,'海尔',3000,'c001’); INSERT INTO product VALUES (3,'雷神',5000,'c001’); INSERT INTO product VALUES (4,'杰克琼斯',800,'c002’); INSERT INTO product VALUES (5,'真维斯',200,'c002’); INSERT INTO product VALUES (6,'花花公子',440,'c002’); INSERT INTO product VALUES (7,'劲霸',2000,'c002’); INSERT INTO product VALUES (8,'香奈儿',800,'c003’); INSERT INTO product VALUES (9,'相宜本草',200,'c003’); INSERT INTO product VALUES (10,'面霸',5,'c003’); INSERT INTO product VALUES (11,'好想你枣',56,'c004’); INSERT INTO product VALUES (12,'香飘飘奶茶',1,'c005’); INSERT INTO product VALUES (13,'海澜之家',1,'c002');
3 select查询简介
SELECT是SQL语言中用于从数据库中检索数据的关键字。
它是最常用的SQL操作之一,用于查询数据库表中的数据并返回结果集。
SELECT语句的基本语法如下:
SELECT [distinct]*|列名1, 列名2, ... FROM 表名 WHERE 条件 GROUP BY 列名 HAVING 条件 ORDER BY 列名 [ASC|DESC]
SELECT语句的解释如下:
- DISTINCT关键字放在SELECT后面的列名之前,用于指示去除重复的记录。
-
表示选择所有列,相当于列出了表中的所有列名。
- 列名:指定要检索的列名。可以使用
*来表示检索表中的所有列,也可以指定单个或多个列名。
- FROM子句:指定要从中检索数据的表名。
- WHERE子句(可选):用于指定数据行的选择条件。只有满足条件的行才会包含在结果集中。
- GROUP BY子句(可选):用于将结果集按指定列进行分组,通常与聚合函数(如SUM、COUNT等)一起使用。
- HAVING子句(可选):用于对分组后的结果集进行过滤,条件表达式用于指定哪些分组结果将包含在结果集中。
- ORDER BY子句(可选):用于按指定列对结果集进行排序。默认情况下,按升序(ASC)排序,可以指定DESC来进行降序排序。
使用SELECT语句可以实现以下操作:
- 检索所有列或指定列的数据。
- 使用WHERE子句根据条件对数据进行过滤。
- 使用GROUP BY子句对数据进行分组。
- 使用HAVING子句对分组后的数据进行过滤。
- 使用ORDER BY子句对结果集进行排序。
SELECT语句是SQL中最核心和基础的部分,非常灵活和强大。它允许用户根据需要从数据库中检索所需的数据,并可根据条件进行过滤、分组和排序,以满足不同的业务需求。
简单查询:
一般来说,简单查询是指从数据库中检索数据的基本查询。
以下是一个简单查询的基本语法:
SELECT 列名1, 列名2, ... FROM 表名
说明:其中,列名1、列名2等表示需要检索的列名,可以选择性地指定需要的列,也可以使用 * 来表示检索所有列。表名表示要从中检索数据的表名。
案例1:假设我们有一个名为 "employees" 的表,包含了列 "employee_id"、"first_name"、"last_name" 和 "salary",我们想要检索并返回所有员工的员工编号、姓名和薪水,可以使用这样的简单查询:
SELECT employee_id, first_name, last_name, salary FROM employees;
上述语句将返回 "employees" 表中所有员工的员工编号、姓名和薪水信息。
简单查询可以根据具体的需求从数据库中检索所需的数据。通过选择需要检索的列和指定相应的表,可以得到符合条件的查询结果。在实际应用中,还可以结合使用其他关键字和子句,如 WHERE 子句用于过滤数据、ORDER BY 子句用于排序结果等,以满足更复杂的查询需求。
案例2:
① 查询所有的商品
select * from product;
② 查询商品名和商品价格
select pname,price from product;
③ 查询结果是表达式(运算查询):将所有商品的价格+10元进行显示
select pname,price+10 from product;
4 条件查询
4.1 条件查询简介
条件查询是指在SELECT语句中使用WHERE子句来过滤出满足特定条件的数据。
它允许根据指定的条件从数据库表中提取出符合条件的数据。
基本语法如下:
SELECT 列名1, 列名2, ... FROM 表名 WHERE 条件;
说明:
- 列名1、列名2表示需要检索的列名,可以选择性地指定需要的列,也可以使用
- 来表示检索所有列。
- 表名表示要从中检索数据的表名。WHERE子句用于指定过滤条件,只有满足条件的行才会包含在结果集中。
在WHERE子句中可以使用各种比较运算符(例如等号、大于、小于、大于等于、小于等于等)、逻辑运算符(如AND、OR和NOT)等来构建条件。
通过在WHERE子句中指定适当的条件,可以对数据库中的数据进行灵活的过滤和查询。
条件查询是在实际应用中经常使用的查询方式,它提供了一种方便的方法来限定要检索的数据范围。
条件查询分为以下几类:
4.2 比较查询
比较查询是数据库中使用比较运算符进行条件筛选的一种查询方式。
它可以用于比较表中的字段与给定值之间的关系,然后返回满足条件的数据。
常用的比较运算符有以下几种:
- 于(=):检查两个值是否相等。
- 不等于(<>或!=):检查两个值是否不相等。
- 大于(>):检查左边的值是否大于右边的值。
- 大于等于(>=):检查左边的值是否大于或等于右边的值。
- 小于(<):检查左边的值是否小于右边的值。
- 小于等于(<=):检查左边的值是否小于或等于右边的值。
比较查询的语法可以根据具体的数据库系统而有所不同,但通常的基本语法如下:
SELECT 列名 FROM 表名 WHERE 列名 运算符 值;
说明:列名代表要比较的字段,运算符代表要使用的比较运算符,值代表要进行比较的值。
比较查询可以根据条件筛选出满足要求的数据,从而实现数据的精确查询和条件筛选。
在实际的应用中,比较查询可以结合逻辑运算符(AND、OR、NOT)和其他查询操作来实现更复杂的查询需求。
案例:
查询商品名称为“花花公子”的商品所有信息: SELECT * FROM product WHERE pname = '花花公子'; # 查询价格为800商品 SELECT * FROM product WHERE price = 800; # 查询价格不是800的所有商品 SELECT * FROM product WHERE price != 800; SELECT * FROM product WHERE price <> 800; # 查询商品价格大于60元的所有商品信息 SELECT * FROM product WHERE price > 60; # 查询商品价格小于等于800元的所有商品信息 SELECT * FROM product WHERE price <= 800;
4.3 范围查询
范围查询是一种常用的数据库查询方式,它可以用来筛选出满足指定范围条件的数据。
(1)使用BETWEEN AND进行范围查询:
语法格式:
column_name BETWEEN value1 AND value2
示例:
SELECT * FROM table_name WHERE column_name BETWEEN value1 AND value2;
描述:BETWEEN AND运算符用于指定某个列中的值在给定范围内的条件。范围包含了value1和value2两个边界值。
(2)使用IN进行范围查询:
语法:
column_name IN (value1, value2, ...)
示例:
SELECT * FROM table_name WHERE column_name IN (value1, value2, ...);
描述:IN运算符允许指定某个列中值的一个列表,只要列中的值与列表中的任何一个值匹配,就会被包含在查询结果中。
这两种范围查询方式的主要区别在于传递给它们的参数类型和数量。
- BETWEEN AND适用于连续的范围条件,可以用于数值、日期等类型的列。它包括了边界值。
- IN适用于离散的范围条件,可以使用多个值进行指定。它可以用于任意数据类型的列,例如字符型、数值型、日期型等。
范围查询常用于筛选指定范围内的数据,例如查询某个时间段内的订单、筛选指定数值范围内的商品价格等。
使用范围查询可以提高查询效率和准确性,同时可以降低查询的复杂度。
案例:
查询商品价格在200到1000之间所有商品 SELECT * FROM product WHERE price BETWEEN 200 AND 1000; # 查询商品价格是200或800的所有商品 SELECT * FROM product WHERE price IN (200,800);
4.4 模糊查询
模糊查询(Like查询)是一种在数据库中使用模式匹配进行条件筛选的查询方式,可以根据指定的模式匹配规则搜索满足条件的数据。
Like查询使用通配符来匹配模式,其中常用的通配符是百分号(%)和下划线(_),以实现更灵活的模式匹配。
(1)百分号(%)通配符:代表零个或多个字符。可以用在模式的任意位置。
示例:
SELECT * FROM table_name WHERE column_name LIKE '%abc%';
描述:该查询会匹配任何包含"abc"的值,如"abc123"、"123abc"、"abcdef"等。
(2)下划线( _)通配符:代表一个单个字符。可以用在模式的任意位置。
示例:
SELECT * FROM table_name WHERE column_name LIKE 'a_';
描述:该查询会匹配以"a"开头,并且后面跟着任何一个字符的值,如"ab"、"ax"、"az"等。
需要注意的是,Like查询通常比精确查询更消耗资源,因为对于大型数据集,模式匹配可能需要更长的时间。尽量避免将通配符放在模式开头,这样可以提高查询性能。
此外,一些数据库系统还支持其他比较特殊的通配符和运算符,如正则表达式匹配、通配符转义字符等。具体语法和使用方式可能因数据库而异,可以参考相应数据库的文档或手册。
案例:
查询以'香'开头的所有商品 SELECT * FROM product WHERE pname LIKE '香%'; # 查询第二个字为'想'的所有商品 SELECT * FROM product WHERE pname LIKE '_想%';
4.5 非空查询
非空查询用于在数据库中查找非空(不为NULL)的值。
在进行非空查询时,我们可以使用IS NOT NULL运算符来筛选出非空值。
非空查询的语法如下:
SELECT * FROM table_name WHERE column_name IS NOT NULL;
说明:
- table
_name是要查询的表名,column_name是要检查非空的列名。
- 执行非空查询时,该语句将返回指定表中指定列中非空的记录。
非空查询的作用是能够排除包含NULL值的记录,只获取有意义和实际存在的数据。在数据库中,NULL表示一个缺失、未知或不适用的值,而非空查询则可以帮助我们过滤掉这些无效或不适用的数据。
在进行非空查询时,需要注意以下几点:
- 确保所查询的列允许为NULL,如果该列定义为NOT NULL,则该列不可能包含NULL值,非空查询将不会返回任何记录。
- 注意区分NULL值和空字符串。NULL表示未知或未提供值,而空字符串表示有一个值,但该值是空的。非空查询只能排除NULL值,如果还希望排除空字符串,可以使用额外的条件进行筛选。
总结来说,非空查询是一种常用的数据库查询方式,用于筛选出不包含NULL值的记录,以获取真实的和有意义的数据。在处理数据时,非空查询可以提高查询结果的准确性和可靠性。
案例:
查询没有分类的商品 SELECT * FROM product WHERE category_id IS NULL; # 查询有分类的商品 SELECT * FROM product WHERE category_id IS NOT NULL;
4.6 逻辑查询
逻辑查询是基于逻辑运算符(例如AND、OR、NOT)和条件表达式的一种查询方式,用于从数据库中检索满足指定条件的数据。
在SQL中,逻辑查询通常使用SELECT语句结合WHERE子句来实现。WHERE子句可以包含多个条件表达式,并且通过逻辑运算符组合这些条件来构建复杂的查询条件。
以下是几个常用的逻辑运算符:
(1)AND运算符:用于指定多个条件同时满足的查询。
示例:
SELECT * FROM table_name WHERE condition1 AND condition2;
描述:该查询会返回满足condition1和condition2的记录。
(2)OR运算符:用于指定多个条件中任何一个满足的查询。
示例:
SELECT * FROM table_name WHERE condition1 OR condition2;
描述:该查询会返回满足condition1或condition2的记录。
(3)NOT运算符:用于指定条件的否定查询。
示例:
SELECT * FROM table_name WHERE NOT condition;
描述:该查询会返回不满足condition的记录。
逻辑查询可以根据具体需求对条件进行组合和嵌套,以实现更复杂的查询逻辑。
例如,可以使用括号来明确指定条件的优先级和组合顺序。此外,还可以结合比较运算符(例如等于、大于、小于等)和范围查询(例如BETWEEN AND、IN)来进一步扩展逻辑查询的功能。
逻辑查询常用于根据不同的条件筛选和过滤数据库中的数据,并获得符合特定条件的结果集。通过合理使用逻辑运算符和条件表达式,可以实现对多维度和复杂条件的查询,并对数据进行深入分析和处理。
案例:
查询商品价格在200到1000之间所有商品 SELECT * FROM product WHERE price >= 200 AND price <=1000; # 查询商品价格是200或800的所有商品 SELECT * FROM product WHERE price = 200 OR price = 800; # 查询价格不是800的所有商品 SELECT * FROM product WHERE NOT(price = 800);
5 排序查询
排序查询是通过SQL语句对数据库中的数据进行排序的查询操作。
它可以根据一个或多个字段对查询结果进行排序,以便更好地理解和分析数据。
语法格式:
SELECT column1, column2, ... FROM table ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
说明:
- SELECT
:指定要查询的列名或表达式。
- FROM
:指定要查询的表名。
- ORDER BY
:排序子句,用于指定排序规则。
- column1
,column2...:要排序的列名或表达式。
- [ASC|DESC]
:可选参数,用于指定排序的方式,ASC表示升序(默认),DESC表示降序。
- 可以将单个字段或多个字段用逗号隔开,并分别指定排序方式。
- 默认情况下,如果没有指定排序方式,默认为升序排序。
- 在使用多个字段进行排序时,首先会根据第一个字段进行排序,如果有相同的值,再按照第二个字段进行排序,依此类推。
- SQL语句执行顺序:首先执行
SELECT语句获取结果集,然后根据ORDER BY子句对结果集进行排序。
案例1:
假设有一个名为customers的表,其中包含如下列:customer_id、customer_name和amount。现在要对amount字段进行降序排序,如果有相同的amount值,再对customer_name字段进行升序排序。
SELECT customer_id, customer_name, amount FROM customers ORDER BY amount DESC, customer_name ASC;
在上述示例中,首先根据amount字段进行降序排序,然后对相同amount值的记录再按照customer_name字段进行升序排序。
通过上述的语法格式和示例,可以轻松理解并使用排序查询对数据库中的数据进行排序。
案例2:
1 使用价格排序(降序) SELECT * FROM product ORDER BY price DESC; # 2 在价格排序(降序)的基础上,以分类排序(降序) SELECT * FROM product ORDER BY price DESC,category_id DESC;
6 聚合查询
之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断。
而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;
另外聚合函数会忽略空值。
聚合查询是一种用于对数据库中的数据进行统计和计算的查询操作,通常结合使用聚合函数。
聚合查询用于对数据进行统计和计算,而不是简单的返回原始数据。
通过聚合查询,可以计算数据的总和、平均值、最大值、最小值、数量等。
基本语法格式:
SELECT aggregate_function(column1), aggregate_function(column2), ... FROM table WHERE condition GROUP BY column1, column2, ... HAVING condition;
说明:
- SELECT
:指定要返回的聚合结果。
- aggregate_function
:聚合函数,用于计算数据的统计值。
- FROM
:指定要查询的表名。
- WHERE
:可选项,添加查询条件对数据进行筛选。
- GROUP BY
:指定按照哪些字段进行分组。
- HAVING
:可选项,对分组后的数据进行筛选。
- 常用聚合函数:
| 聚合函数 | 作用 |
| COUNT(column) | 统计某一列的非空值数量。 |
| SUM(column) | 计算某一列的数据之和,如果指定列类型不是数值类型,则计算结果为0。 |
| MAX(column) | 找出某一列中的最大值,如果指定列是字符串类型,使用字符串排序运算。 |
| MIN(column) | 找出某一列中的最小值,如果指定列是字符串类型,使用字符串排序运算。 |
| AVG(column) | 计算某一列的数据平均值,如果指定列类型不是数值类型,则计算结果为0。 |
案例1:
假设有一个名为products的表,其中包含如下列:product_id、product_name和price。现在要计算产品的总数量、平均价格以及最高和最低价格。
SELECT COUNT(product_id) AS total_products, AVG(price) AS average_price, MAX(price) AS max_price, MIN(price) AS min_price FROM products;
说明:
- 使用
COUNT函数统计product_id的数量,使用AVG函数计算价格的平均值,使用MAX函数找出价格的最大值,使用MIN函数找出价格的最小值。
- 通过上述的语法格式和示例,可以实现对数据进行统计和计算的聚合查询操作。
案例2:
1 查询商品的总条数 SELECT COUNT() FROM product; # 2 查询价格大于200商品的总条数 SELECT COUNT() FROM product WHERE price > 200; # 3 查询分类为'c001'的所有商品的总和 SELECT SUM(price) FROM product WHERE category_id = 'c001'; # 4 查询分类为'c002'所有商品的平均价格 SELECT AVG(price) FROM product WHERE categ ory_id = 'c002'; # 5 查询商品的最大价格和最小价格 SELECT MAX(price),MIN(price) FROM product;
7 分组查询与having子句
7.1 分组查询简介
分组查询是一种用于对数据库中的数据进行分组和聚合的查询操作。通过分组查询,可以按照指定的字段进行分组,并对每个组进行聚合计算。
分组查询用于将数据库中的数据按照指定的字段进行分组,并对每个组进行聚合计算。通过分组查询,可以实现对数据的分组统计。
GROUP BY语句用于将结果按照一个或多个列进行分组,然后对每个组进行聚合运算。
在分组查询中,除了使用GROUP BY对数据进行分组外,还可以使用HAVING子句来对分组后的数据进行筛选。HAVING子句用于筛选满足特定条件的分组结果。
HAVING子句在分组查询中起到了类似于WHERE子句的作用,但是WHERE子句过滤的是行级数据,而HAVING子句过滤的是分组后的结果。
语法格式:
SELECT column1, column2, ..., aggregate_function(column) FROM table WHERE condition GROUP BY column1, column2, ... HAVING condition;
- SELECT
:指定要查询的字段,可以包括普通字段和聚合函数。
- column1, column2, ...
:要查询的字段,可以是单个字段或多个字段。
- aggregate_function(column)
:指定要进行聚合计算的字段。
- FROM
:指定要查询的表名。
- WHERE
:可选项,添加查询条件对数据进行筛选。
- GROUP BY
:指定按照哪些字段进行分组。
- 分组计算:在分组查询中,可以使用各种聚合函数对每个组的数据进行计算,常用的聚合函数有:
SUM、AVG、COUNT、MAX、MIN等。
- 注意事项:需要注意的是,在分组查询中,除了聚合函数计算的字段外,其他字段必须出现在
GROUP BY语句中。例如,如果查询SELECT column1, AVG(column2) FROM table GROUP BY column1;,则column1必须出现在GROUP BY语句中。
- HAVING
:可选项,对分组结果进行筛选。
7.2 group by的使用
案例:
-- 根据gender字段来分组 select gender from students group by gender; -- 根据name和gender字段进行分组 select name, gender from students group by name, gender;
说明:
- group by可以实现去重操作
- group by的作用是为了实现分组统计(group by + 聚合函数)
7.3 group by + 聚合函数的使用
案例:以下示例将列出每个部门的员工数量和平均工资
SELECT department_id, COUNT(*) AS employee_count, AVG(salary) AS average_salary FROM employees GROUP BY department_id;
说明:
- 通过在
GROUP BY语句中指定department_id字段,将结果按照部门进行分组。
- 然后使用
COUNT(*)函数计算每个组的员工数量,并使用AVG(salary)函数计算每个组的平均工资。
- 注意事项:
-
- 在
SELECT子句中,除了聚合函数外,所查询的字段必须是分组字段或存在于GROUP BY子句中,否则将产生错误。
-
- 分组字段的顺序不影响结果,但可以根据需要指定多个分组字段。
7.4 group by + having的使用
HAVING子句在分组查询中起到了类似于WHERE子句的作用,但是WHERE子句过滤的是行级数据,而HAVING子句过滤的是分组后的结果。
所以,having是过滤分组数据的,只能用于group by。
HAVING子句用于对分组后的结果进行筛选。它可以包含聚合函数、分组字段和其他条件表达式。
案例1:
-- 根据gender字段进行分组,统计分组条数大于2的 select gender,count() from students group by gender having count()>2;
案例2:
#1 统计各个分类商品的个数 SELECT category_id ,COUNT() FROM product GROUP BY category_id ; #2 统计各个分类商品的个数,且只显示个数大于1的信息 SELECT category_id ,COUNT() FROM product GROUP BY category_id HAVING COUNT(*) > 1;
案例3:求每个客户的订单总金额大于1000的客户
SELECT customer_id, SUM(order_amount) AS total_amount FROM orders GROUP BY customer_id HAVING SUM(order_amount) > 1000;
案例4:求每个部门的平均工资大于5000的部门
SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id HAVING AVG(salary) > 5000;
说明:
- 使用
HAVING子句对分组后的结果进行筛选,只返回满足条件的分组结果。
- 通过使用
HAVING子句,可以在分组查询中进一步筛选满足特定条件的分组结果。这使得分组查询更加灵活和强大。
8 limit分页查询
LIMIT关键字用于分页查询,它限制了查询结果返回的记录数,从而实现数据的分页显示。
LIMIT语法可以在SELECT语句中使用,具体格式如下:
SELECT column1, column2, ... FROM table LIMIT offset, count;
- column1, column2, ...
:要查询的字段,可以是单个字段或多个字段。
- table
:要查询数据的表名。
- offset
:结果集的起始位置,表示返回结果时忽略前面的多少条记录。(起始位置从0开始)
- count
:要返回的记录数,指定返回多少条记录。
案例:使用LIMIT语句进行分页查询
SELECT * FROM customers LIMIT 10, 5;
说明:
- 查询结果将从第11条记录开始(起始位置为10),返回5条记录。这表示查询结果是从第11条记录到第15条记录。
- 分页查询的常见使用场景是实现网页或移动应用的分页显示功能。通过在每次查询中适当设置
offset和count的值,可以实现分页显示不同页的数据。
- 要注意的是,
LIMIT语句的效果取决于数据库的排序方式。因此,在进行分页查询之前,最好在SELECT语句中使用ORDER BY子句对结果进行排序,以确保分页结果的准确性和一致性。
在处理大量数据时,还可以使用LIMIT语句进行优化,根据需求逐步加载页面数据并减少数据库的压力。
例如:数据共有30条,每页显示5条,第一页显示1-5条,第二页显示6-10条。
SELECT 字段1,字段2... FROM 表名 LIMIT M,N
说明:
- : 整数,表示从第几条索引开始,计算方式:(当前页-1)
*每页显示条数。
- N: 整数,表示查询多少条数据。
案例:
SELECT 字段1,字段2... FROM 表明 LIMIT 0,5 SELECT 字段1,字段2... FROM 表明 LIMIT 5,5
9 多表查询
9.1 交叉连接(了解)
(1)交叉连接
交叉连接(Cross Join)是一种连接操作,它将两个表中的每一行进行组合,生成一个包含所有可能组合的结果集。它是所有连接操作的基础。
交叉连接的结果集包含了表1和表2中的每一行,字段数等于表1字段数加上表2字段数,记录数等于表1中的总数量乘以表2中的总数量(即笛卡尔积)。
结果:
字段数 = 表1字段 + 表2的字段
记录数 = 表1中的总数量 * 表2中的总数量(笛卡尔积)
在SQL语句中,可以使用CROSS JOIN关键字或简写方式进行交叉连接查询。
例如:
SELECT * FROM students CROSS JOIN classes;
或
SELECT * FROM students, classes;
说明:
- students
和classes是要进行交叉连接的两个表。查询结果将包含了这两个表中的所有记录的所有可能组合。
- 需要注意的是,由于交叉连接会生成非常大的结果集,尤其是在涉及大表或多个表的情况下,所以在实际应用中要慎用交叉连接,避免出现性能问题。通常情况下,交叉连接主要用于特定的数据分析需求或特殊场景下的处理。
(2)笛卡尔积
笛卡尔积(Cartesian Product)是集合论中的一个概念,用于描述两个集合之间的组合方式。在关系型数据库中,笛卡尔积指的是通过对两个表进行交叉连接操作,生成一个包含了两个表中所有可能组合的结果集。
具体来说,假设有两个表A和B,分别包含了M条和N条记录。通过对表A和表B执行交叉连接操作,会将表A的每一条记录与表B的每一条记录进行组合,生成一个新表C。
表C的行数等于表A的行数乘以表B的行数,即M * N。而表C的列数等于表A的列数加上表B的列数,即A的列数 + B的列数。
例如,假设有以下两个表:
Table A:
| ID | Name |
| 1 | Alice |
| 2 | Bob |
Table B:
| ID | Course |
| 101 | Math |
| 102 | English |
通过对表A和表B执行交叉连接操作,可以得到它们的笛卡尔积结果:
Table C:
| ID | Name | ID | Course |
| 1 | Alice | 101 | Math |
| 1 | Alice | 102 | English |
| 2 | Bob | 101 | Math |
| 2 | Bob | 102 | English |
可以看出,表C包含了表A和表B中所有可能的组合。每一行表示了表A和表B中的一条记录的组合,其中第一列和第二列是来自表A的字段,第三列和第四列是来自表B的字段。
需要注意的是,当两个表的记录数较大时,笛卡尔积的结果集也会非常庞大,可能会导致性能问题。因此,在实际应用中应谨慎使用笛卡尔积操作,避免不必要的计算开销。
9.2 连接查询
(1)连接查询的介绍
连接查询(Join)是在关系型数据库中用于将多个表中相关联的数据进行关联的一种查询操作。它基于表之间的关联关系,通过共享的列(也称为关联列或连接列)将多个表中的数据进行匹配和组合。
连接查询可以根据表之间的关联条件,将满足条件的数据行进行合并,生成一个包含了来自多个表的相关数据的结果集。连接查询的结果可以包含来自一个表或多个表的列数据,根据关联条件对数据行进行匹配和组合。
在SQL中,连接查询通常使用JOIN关键字来指定连接的表以及关联条件。
常见的连接类型包括:
- 内连接(Inner Join):返回两个表中满足关联条件的数据行。
- 左连接(Left Join):返回左表中的所有数据行以及满足关联条件的右表中的数据行。
- 右连接(Right Join):返回右表中的所有数据行以及满足关联条件的左表中的数据行。
- 全外连接(Full Outer Join):返回满足关联条件的两个表中的所有数据行。
(2)内连接查询
查询两个表中符合条件的共有记录:
内连接(Inner Join)是连接查询中最常用的一种连接类型。它通过关联两个表的列,将满足关联条件的数据行进行合并,生成一个包含了来自多个表的相关数据的结果集。
内连接查询返回的结果集只包含两个表中满足关联条件的数据行。
具体来说,对于两个表A和B,内连接查询会根据给定的关联条件,将表A和表B中符合条件的数据行进行匹配和组合。只有在两个表中都存在匹配的数据行时,才会将这些数据行包含在结果集中。
在SQL中,内连接查询通常使用INNER JOIN关键字来指定连接的表以及关联条件。
内连接查询的特点和应用场景包括:
- 内连接只返回满足关联条件的数据行,因此结果集中会排除那些不满足关联条件的数据行。
- 内连接可以基于一个或多个关联条件进行查询,关联条件可以使用等号、不等号、比较运算符等。
- 内连接可以连接两个以上的表,将多个表中的数据进行关联。
- 内连接可以对多个表中的列进行筛选、聚合和排序等数据操作。
- 内连接可以用于查询多表关联和数据分析等场景,提供了灵活和高效的数据检索和分析手段。
- 需要注意的是,内连接只返回满足关联条件的数据行,因此在实际应用中,需确保关联条件的准确性和合理性,以避免获取不完整或错误的数据。
内连接查询的语法格式:
SELECT 列列表 FROM 表A INNER JOIN 表B ON 关联条件;
说明:
- 通过
INNER JOIN关键字将表A和表B连接起来。
- 并通过
ON子句指定了关联条件,该条件用于匹配和组合两个表中的数据行。
案例1:使用内连接查询学生表与班级表
select * from students as s inner join classes as c on s.cls_id = c.id;
案例2:假设我们有两个表,一个是"Customers"表,包含了客户的ID和姓名信息,另一个是"Orders"表,包含了订单的ID、客户ID和订单日期信息。我们想要查询每个订单的订单ID、客户姓名和订单日期,需要关联两个表。
"Customers"表:
| CustomerID | CustomerName |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
"Orders"表:
| OrderID | CustomerID | OrderDate |
| 101 | 1 | 2021-01-01 |
| 102 | 2 | 2021-02-03 |
| 103 | 1 | 2021-03-05 |
| 104 | 3 | 2021-04-07 |
| 105 | 2 | 2021-05-09 |
我们可以使用内连接查询来获取想要的结果:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate FROM Orders INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
执行上述查询后,将会得到以下结果:
| OrderID | CustomerName | OrderDate |
| 101 | Alice | 2021-01-01 |
| 102 | Bob | 2021-02-03 |
| 103 | Alice | 2021-03-05 |
| 104 | Charlie | 2021-04-07 |
| 105 | Bob | 2021-05-09 |
说明:
- 上述查询将会把"Orders"表中的订单数据和"Customers"表中的客户姓名联合起来,通过客户ID进行匹配,得到每个订单对应的客户姓名和订单日期。
- 通过内连接查询,我们可以根据关联条件对多个表进行联合,从而得到包含多个相关数据的结果集,它是多表关联查询中常用的一种方式。
(3)左外连接查询
以左表为主根据条件查询右表数据,如果根据条件查询右表数据不存在使用null值填充:
左外连接(Left Outer Join)是连接查询中的一种连接类型,它基于左表的所有数据行,将满足关联条件的右表数据行合并到结果集中。
如果右表中没有符合关联条件的数据行,则会在结果集中用 NULL 值表示。
左外连接查询的语法格式如下:
SELECT 列列表 FROM 表A LEFT JOIN 表B ON 关联条件;
说明:
- 通过
LEFT JOIN 关键字将表A和表B进行连接。
- 通过
ON 子句指定了关联条件,该条件用于匹配和组合两个表中的数据行。
案例1:使用左连接查询学生表与班级表
select * from students as s left join classes as c on s.cls_id = c.id;
案例2:假设我们有两个表,一个是 "Customers" 表,包含了客户的 ID 和姓名信息,另一个是 "Orders" 表,包含了订单的 ID、客户 ID 和订单日期信息。我们想要查询每个客户的 ID、姓名以及他们的订单。如果一个客户没有订单记录,仍然要显示该客户的信息。
"Customers" 表:
| CustomerID | CustomerName |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
"Orders" 表:
| OrderID | CustomerID | OrderDate |
| 101 | 1 | 2021-01-01 |
| 102 | 2 | 2021-02-03 |
| 104 | 3 | 2021-04-07 |
| 105 | 2 | 2021-05-09 |
我们可以使用左外连接查询来获取想要的结果:
SELECT Customers.CustomerID, Customers.CustomerName, Orders.OrderID, Orders.OrderDate FROM Customers LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
执行上述查询后,将会得到以下结果:
| CustomerID | CustomerName | OrderID | OrderDate |
| 1 | Alice | 101 | 2021-01-01 |
| 2 | Bob | 102 | 2021-02-03 |
| 2 | Bob | 105 | 2021-05-09 |
| 3 | Charlie | 104 | 2021-04-07 |
说明:
- 在上述查询结果中,左表是 "Customers" 表,右表是 "Orders" 表。
- 通过左外连接查询,我们保留了左表中所有的客户信息,并将满足关联条件的右表数据(即订单信息)合并到结果集中。
- 如果一个客户没有订单记录,那么在结果集中会用 NULL 值表示。
- 通过左外连接查询,我们可以获取左表的所有数据行,并将满足关联条件的右表数据行合并到结果集中,提供了更全面和灵活的数据查询方式。
(4)右外连接查询
以右表为主根据条件查询左表数据,如果根据条件查询左表数据不存在使用null值填充:
右外连接(Right Outer Join)是连接查询中的一种连接类型,它基于右表的所有数据行,将满足关联条件的左表数据行合并到结果集中。如果左表中没有符合关联条件的数据行,则会在结果集中用 NULL 值表示。
右外连接查询的语法格式如下:
SELECT 列列表 FROM 表A RIGHT JOIN 表B ON 关联条件;
说明:
- 通过
RIGHT JOIN 关键字将表A和表B进行连接
- 通过
ON 子句指定了关联条件,该条件用于匹配和组合两个表中的数据行。
案例1:使用右连接查询学生表与班级表
select * from students as s right join classes as c on s.cls_id = c.id;
案例2:假设我们有两个表,一个是 "Customers" 表,包含了客户的 ID 和姓名信息,另一个是 "Orders" 表,包含了订单的 ID、客户 ID 和订单日期信息。我们想要查询每个订单的 ID、订单日期以及订单对应的客户姓名。如果一个订单没有客户记录,仍然要显示该订单的信息。
"Customers" 表:
| CustomerID | CustomerName |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
"Orders" 表:
| OrderID | CustomerID | OrderDate |
| 101 | 1 | 2021-01-01 |
| 102 | 2 | 2021-02-03 |
| 104 | 3 | 2021-04-07 |
| 105 | 2 | 2021-05-09 |
我们可以使用右外连接查询来获取想要的结果:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate FROM Customers RIGHT JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
执行上述查询后,将会得到以下结果:
| OrderID | CustomerName | OrderDate |
| 101 | Alice | 2021-01-01 |
| 102 | Bob | 2021-02-03 |
| 104 | Charlie | 2021-04-07 |
| 105 | Bob | 2021-05-09 |
| NULL | NULL | NULL |
说明:
- 在上述查询结果中,右表是 "Orders" 表,左表是 "Customers" 表。
- 通过右外连接查询,我们保留了右表中所有的订单信息,并将满足关联条件的左表数据(即客户信息)合并到结果集中。
- 如果一个订单没有客户记录,那么在结果集中会用 NULL 值表示。
- 通过右外连接查询,我们可以获取右表的所有数据行,并将满足关联条件的左表数据行合并到结果集中,提供了更全面和灵活的数据查询方式。
(5)全外连接查询
全外连接(Full Outer Join)是连接查询中的一种连接类型,它基于两个表的所有数据行,将满足关联条件的数据行合并到结果集中。
如果一个表中没有符合关联条件的数据行,则会在结果集中用 NULL 值表示。
全外连接查询的语法格式如下:
SELECT 列列表 FROM 表A FULL JOIN 表B ON 关联条件;
说明:
- 通过
FULL JOIN 关键字将表A和表B进行连接。
- 通过
ON 子句指定了关联条件,该条件用于匹配和组合两个表中的数据行。
- 需要注意的是,不同的数据库管理系统(如MySQL、SQL Server)对全外连接的语法支持有所差异。在某些数据库管理系统中,可以使用
OUTER 关键字来表示全外连接。
案例:假设我们有两个表,一个是 "Customers" 表,包含了客户的 ID 和姓名信息,另一个是 "Orders" 表,包含了订单的 ID、客户 ID 和订单日期信息。我们想要查询每个客户的 ID、姓名以及他们的订单,无论该客户是否有订单记录。
"Customers" 表:
| CustomerID | CustomerName |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
"Orders" 表:
| OrderID | CustomerID | OrderDate |
| 101 | 1 | 2021-01-01 |
| 102 | 2 | 2021-02-03 |
| 104 | 3 | 2021-04-07 |
| 105 | 2 | 2021-05-09 |
我们可以使用全外连接查询来获取想要的结果:
SELECT Customers.CustomerID, Customers.CustomerName, Orders.OrderID, Orders.OrderDate FROM Customers FULL JOIN Orders ON Customers.CustomerID = Orders.CustomerID;
执行上述查询后,将会得到以下结果:
| CustomerID | CustomerName | OrderID | OrderDate |
| 1 | Alice | 101 | 2021-01-01 |
| 2 | Bob | 102 | 2021-02-03 |
| 2 | Bob | 105 | 2021-05-09 |
| 3 | Charlie | 104 | 2021-04-07 |
| NULL | NULL | NULL | NULL |
说明:
- 在上述查询结果中,我们将所有的客户信息和订单信息都包括在了结果集中。
- 如果一个客户没有订单记录,则订单相关列会用 NULL 值表示;如果一个订单没有客户记录,则客户相关列会用 NULL 值表示。
- 需要注意的是,全外连接查询在某些数据库管理系统中可能不被支持,可以通过其他方式实现类似的查询效果,如使用 UNION 操作符将左外连接和右外连接的结果合并。
10 子查询
10.1 子查询简介
子查询(Subquery)是指在一个查询语句中嵌套使用的查询。
它可以在主查询中使用一个或多个嵌套的子查询作为条件、表达式或子查询结果集。
子查询可以提供更具体和复杂的查询逻辑,允许我们在查询中使用动态的、基于其他查询结果的值。
子查询的语法格式如下:
SELECT 列列表 FROM 表 WHERE 列 IN (SELECT 列列表 FROM 表 WHERE 条件);
说明:
- WHERE 列 IN
:使用子查询结果作为主查询中的筛选条件,列表示主查询中的列名。
- (SELECT 列列表 FROM 表 WHERE 条件)
:子查询的语法,它会返回一个结果集作为主查询的筛选条件。子查询中可以使用自己的表和条件,也可以使用父查询的表和条件。
- 在上述语法中,子查询被包括在括号内,作为主查询的条件之一或子查询结果集被用于参与主查询的其他部分。
- 子查询可以返回单个值、单列值列表或多列值列表,具体取决于子查询的目的和位置。
主查询和子查询的关系:
- 子查询是嵌入到主查询中。
- 子查询是辅助主查询的,要么充当条件,要么充当数据源(数据表)。
- 子查询是可以独立存在的语句是一条完整的 select 语句。
以下是一些常见的子查询应用场景:
(1)使用子查询作为主查询的条件:子查询返回一个值(标量子查询),可以用于比较、过滤或计算主查询中的条件。
SELECT 列列表 FROM 表 WHERE 列 = (SELECT 列 FROM 表 WHERE 条件);
(2)使用子查询作为主查询的列值:子查询返回一个列(列子查询),可以作为主查询中的一个列值进行显示。
SELECT 列, (SELECT 列 FROM 表 WHERE 条件) AS 列名 FROM 表;
(3)使用子查询作为主查询的表:子查询返回一个结果集,可以用作主查询中的一个表。
SELECT 列列表 FROM (SELECT 列列表 FROM 表 WHERE 条件) AS 子查询表 JOIN 表 ON 子查询表.列 = 表.列;
子查询可以根据实际需要嵌套多层,形成复杂的查询逻辑。它提供了更高级和灵活的查询能力,可以根据查询结果进行动态的条件控制和数据处理。
10.2 子查询的使用
案例1:查询学生表中大于平均年龄的所有学生
需求:查询年龄 > 平均年龄的所有学生
前提:
① 获取班级的平均年龄值
② 查询表中的所有记录,判断哪个同学 > 平均年龄值
第一步:写子查询
select avg(age) from students;
第二步:写主查询
select * from students where age > (平均值);
第三步:第一步和第二步进行合并
select * from students where age > (select avg(age) from students);
案例2:查询学生在班的所有班级名字
需求:显示所有有学生的班级名称
前提:
① 先获取所有学员都属于那些班级
② 查询班级表中的所有记录,判断是否出现在①结果中,如果在,则显示,不在,则忽略。
第一步:编写子查询
select distinct cls_id from students is not null;
第二步:编写主查询
select * from classes where cls_id in (1, 2, 3);
第三步:把主查询和子查询合并
select * from classes where cls_id in (select distinct cls_id from students where cls_id is not null);
案例3:查找年龄最小,成绩最低的学生
第一步:获取年龄最小值和成绩最小值
select min(age), min(score) from student;
第二步:查询所有学员信息(主查询)
select * from students where (age, score) = (最小年龄, 最少成绩);
第三步:把第一步和第二步合并
select * from students where (age, score) = (select min(age), min(score) from students);
案例4:假设有两个表,一个是 "Customers" 表,包含了顾客的ID、姓名和年龄信息,另一个是 "Orders" 表,包含了订单的ID、顾客ID和订单金额信息。现在我们想要查询年龄在30岁以上的顾客的所有订单。
"Customers" 表:
| CustomerID | Name | Age |
| 1 | Alice | 25 |
| 2 | Bob | 35 |
| 3 | Charlie | 30 |
| 4 | Dave | 40 |
"Orders" 表:
| OrderID | CustomerID | Amount |
| 101 | 1 | 100 |
| 102 | 2 | 150 |
| 103 | 3 | 200 |
| 104 | 4 | 300 |
我们可以使用子查询来实现:
SELECT * FROM Orders WHERE CustomerID IN (SELECT CustomerID FROM Customers WHERE Age > 30);
说明:
- 在上述查询中,子查询
(SELECT CustomerID FROM Customers WHERE Age > 30) 返回了年龄大于30岁的顾客的ID。
- 主查询使用这个结果作为筛选条件,在 "Orders" 表中找到对应的订单信息。
- 执行该查询后,将返回所有年龄大于30岁顾客的订单记录:
| OrderID | CustomerID | Amount |
| 102 | 2 | 150 |
| 104 | 4 | 300 |
这样我们就得到了年龄在30岁以上的顾客的所有订单。