MySQL学习_子查询和连接

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jt102605/article/details/86719752

子查询

子查询(Subquery)是指出现在其它SQL语句内的SELECT语句.

SELECT * FROM t1 WHERE col1=(SELECT col2 FROM t2);  

其中,SELECT * FROM t1 称为Outer Query / Outer Statement,  SELECT col2 FROM t2 称为SubQuery.

  • 子查询必须始终出现在圆括号内
  • 子查询可以包含多个关键字或条件,如DISTINCT, ORDER BY, GROUP BY, LIMIT, 函数等
  • 子查询的外部查询可以是SELECT, INSERT, UPDATE, SET或DO.
  • 子查询可以返回标量,一行,一列或子查询

使用比较运算符的子查询

  • 语法结构:operand comparision_operator ANY | SOME | ALL (subquery)
  • 使用比较运算符的子查询,若比较运算符后跟的子查询结果有多个值时,用要用关键字ANY, SOME, ALL来做修饰

练习1 

//求所有电脑产品的平均价格,并且保留两位小数,AVG,MAX,MIN、COUNT、SUM为聚合函数
SELECT ROUND(AVG(goods_price),2) AS avg_price FROM tdb_goods;

//查询所有价格大于平均价格的商品,并且按价格降序排序
SELECT goods_id, goods_name, goods_price FROM tdb_goods WHERE goods_price>5845.10 ORDER BY goods_price DESC;

使用子查询来实现

SELECT goods_id, goods_name, goods_price FROM tdb_goods
WHERE goods_price>(SELECT ROUND(AVG(goods_price),2) FROM tdb_goods)
ORDER BY goods_price DESC;

使用 [NOT] IN 的子查询

  • 语法结构:operant [NOT] IN (SubQuery)
  • =ANY, =SOME 等价于 IN; !=ALL,<>ALL d等价与NOT IN

 练习2    

//查询价格大于或等于"超级本"价格的商品,并且按价格降序排列
SELECT goods_id, goods_name, goods_price FROM tdb_goods
WHERE goods_price=ANY(SELECT goods_price FROM tdb_goods WHERE goods_cate='超级本')
ORDER BY goods_price DESC;

 = ANY 或 = SOME 等价于 IN 

SELECT goods_id,goods_name,goods_price FROM tdb_goods 
WHERE goods_price IN (SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本')
ORDER BY goods_price DESC; 

使用 [NOT] EXISTS 的子查询

  • 如果子查询返回任何行,EXISTS将返回TRUE, 否则返回FALSE 

连接

  • MySQL在SELECT语句,多表更新,多表删除中支持JOIN操作
  • 基本语法结构:table_reference {[INNER | CROSS] JOIN | {LEFT | RIGHT} [OUTER] JOIN} table_reference ON conditional_expr;

table_reference

table_name [[AS] alias_name] | table_subquery [AS] alias_name

table_subquery 可以作为子查询使用在FROM子句中,这样的子查询必须为其赋予别名.

连接类型

内连接( [INNER | CROSS] JOIN): 仅显示左表和右表中符合连接条件的记录

左外连接(LEFT [OUTER] JOIN): 显示左表的全部记录以及右表符合连接条件的记录

右外连接(RIGHT [OUTER] JOIN): 显示右表的全部记录以及左表符合连接条件的记录

连接条件 

使用ON关键字来设定连接条件,也可以使用WHERE来代替

通常,使用ON关键字在设定连接条件,使用WHERE关键字进行结果集记录的过滤

A LEFT JOIN B join_condition

数据表B的结果集依赖于数据表A 

数据表A的结果集根据左连接条件依赖所有数据表(B表除外)

左外连接条件决定如何检索数据表B (在没有指定WHERE条件的情况下)

如果数据表A的某条记录符合WHERE条件,但是在数据表B中不存在符合连接条件的记录,将生成一个所有列为空的额外的B行

如果使用内连接查找的记录在连接数据表中不存在,并且在WHERE子句中尝试以下操作:col_name IS NULL 时,如果col_name被定义为NOT NULL ,MySQL将在找到符合连接条件的记录后停止搜索更多的行

SELECT语句中的多表连接

//SELECT 表tdb_goods中的goods_id,goods_name,goods_price 表tdb_goods_cates中的cate_name 以及 表tdb_goods_brands中的brand_name字段

SELECT goods_id,goods_name,cate_name,brand_name,goods_price FROM tdb_goods AS g
INNER JOIN tdb_goods_cates AS c ON g.cate_id = c.cate_id
INNER JOIN tdb_goods_brands AS b ON g.brand_id = b.brand_id\G;

 无限级分类表的设计

在一个分类下又分出许多子类,在子类下再分出小的子类,一直分下去,这样无限级的表该如何设计呢.

我们可以在一张表中添加一个parent_id字段,该字段的值就是其父类的id,这样通过一张表中的自身连接就可以实现无限子类表的设计

CREATE TABLE tdb_goods_types(
     type_id   SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
     type_name VARCHAR(20) NOT NULL,
     parent_id SMALLINT UNSIGNED NOT NULL DEFAULT 0
  ); 

 插入记录并显示,"家用电器","电脑 办公"两项的parent_id为0, 表示它们为最初始的父类,"大家电","生活电器"的parent_id为1, 表示它们是"家用电器下的子类"

root@localhost goods_test>SELECT * FROM tdb_goods_types;
+---------+-----------------+-----------+
| type_id | type_name       | parent_id |
+---------+-----------------+-----------+
|       1 | 家用电器        |         0 |
|       2 | 电脑、办公      |         0 |
|       3 | 大家电          |         1 |
|       4 | 生活电器        |         1 |
|       5 | 平板电视        |         3 |
|       6 | 空调            |         3 |
|       7 | 电风扇          |         4 |
|       8 | 饮水机          |         4 |
|       9 | 电脑整机        |         2 |
|      10 | 电脑配件        |         2 |
|      11 | 笔记本          |         9 |
|      12 | 超级本          |         9 |
|      13 | 游戏本          |         9 |
|      14 | CPU             |        10 |
|      15 | 主机            |        10 |
+---------+-----------------+-----------+
15 rows in set (0.00 sec)

对于这样的数据表,在查找时可以通过自身连接来实现,即对同一个数据表使用连接操作.

通过自身连接查找父类

SELECT s.type_id, s.type_name, p.type_name FROM tdb_goods_types AS s LEFT JOIN tdb_goods_types AS p ON s.parent_id=p.type_id;

+---------+-----------------+-----------------+
| type_id | type_name       | type_name       |
+---------+-----------------+-----------------+
|       1 | 家用电器        | NULL            |
|       2 | 电脑、办公      | NULL            |
|       3 | 大家电          | 家用电器        |
|       4 | 生活电器        | 家用电器        |
|       5 | 平板电视        | 大家电          |
|       6 | 空调            | 大家电          |
|       7 | 电风扇          | 生活电器        |
|       8 | 饮水机          | 生活电器        |
|       9 | 电脑整机        | 电脑、办公      |
|      10 | 电脑配件        | 电脑、办公      |
|      11 | 笔记本          | 电脑整机        |
|      12 | 超级本          | 电脑整机        |
|      13 | 游戏本          | 电脑整机        |
|      14 | CPU             | 电脑配件        |
|      15 | 主机            | 电脑配件        |
+---------+-----------------+-----------------+

通过自身连接查找子类

SELECT p.type_id, p.type_name, s.type_name FROM tdb_goods_types AS p LEFT JOIN tdb_goods_types AS s ON p.type_id=s.parent_id;

+---------+-----------------+--------------+
| type_id | type_name       | type_name    |
+---------+-----------------+--------------+
|       1 | 家用电器        | 大家电       |
|       1 | 家用电器        | 生活电器     |
|       3 | 大家电          | 平板电视     |
|       3 | 大家电          | 空调         |
|       4 | 生活电器        | 电风扇       |
|       4 | 生活电器        | 饮水机       |
|       2 | 电脑、办公      | 电脑整机     |
|       2 | 电脑、办公      | 电脑配件     |
|       9 | 电脑整机        | 笔记本       |
|       9 | 电脑整机        | 超级本       |
|       9 | 电脑整机        | 游戏本       |
|      10 | 电脑配件        | CPU          |
|      10 | 电脑配件        | 主机         |
|       5 | 平板电视        | NULL         |
|       6 | 空调            | NULL         |
|       7 | 电风扇          | NULL         |
|       8 | 饮水机          | NULL         |
|      11 | 笔记本          | NULL         |
|      12 | 超级本          | NULL         |
|      13 | 游戏本          | NULL         |
|      14 | CPU             | NULL         |
|      15 | 主机            | NULL         |
+---------+-----------------+--------------+

 

多表删除

查询数据表中重复记录

SELECT min(goods_id), goods_name FROM tdb_goods GROUP BY goods_name HAVING count(goods_name)>=2;

+---------------+-----------------------------+
| min(goods_id) | goods_name                  |
+---------------+-----------------------------+
|            18 |  HMZ-T3W 头戴显示设备       |
|            19 | 商务双肩背包                |
+---------------+-----------------------------+

通过子查询和连接实现多表删除(删除一张表中的重复记录)

DELETE t1 FROM tdb_goods AS t1 LEFT JOIN 
(SELECT any_value(goods_id) AS goods_id, goods_name FROM tdb_goods 
GROUP BY goods_name HAVING count(goods_name)>=2) AS t2 
ON t1.goods_name=t2.goods_name 
WHERE t1.goods_id>t2.goods_id;

多表更新

UPDATE tdb_goods AS g 
INNER JOIN tdb_goods_brands AS b 
ON g.brand_name=b.brand_name
SET g.brand_name = b.brand_id;

猜你喜欢

转载自blog.csdn.net/jt102605/article/details/86719752