5、子查询与连接

作者: 焰火青春 | 来源:发表于2018-04-08 22:39 被阅读29次

    5、子查询与连接

    5.1、数据准备

    mysql 中对记录操作可分为两类

    • 写操作:INSERT、DELETE、UPDATE
    • 读取操作:SELECT

    若在查询数据表时,发现数据是乱码,可以将编码方式修改为 gbk(默认 utf-8),只需在记录插入后添加以下一个语句即可:

    # 需注意的是这只影响 mysql 客户端,并不能改变默认编码方式,只是以 gbk 的编码方式呈现出来
    SET NAMES gbk;
    

    5.2、子查询简介

    5.2.1、定义

    子查询(subquery):指出现在其他 SQL 语句内的 SELECT 子句。

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

    其中 SELECT * FROM t1 ,称为 Outer Query/ Outer Statement(外部查询)

    SELECT col2 FROM t2,称为 SubQuery

    5.2.2、条件:

    • 子查询指嵌套在查询内部,且必须始终出现在圆括号内。
    • 子查询可以包含多个关键字或条件,如DISTINCT、GROUP BY、ORDER BY、LIMIT、函数等。
    • 子查询的外层查询可以是:SELECT、INSERT、UPDATE、SET或DO。

    5.2.3、返回值

    子查询可以返回标量、一行、一列或子查询

    5.3、由比较运算符引发的子查询

    5.3.1、使用比较运算符的子查询

    # 运算符
    =、>、<、>=、<=、<>、!=、<=>
    # 语法结构
    operand comparison_operator subquery
    
    # 一张关于电脑及配件的数据表 tdb_goods,其中有23条记录,有7列,分别是goods_id、goods_name、goods_cate(分类)、brand_name(品牌名)、goods_price、is_show(是否上架)、is_saleoff(是否销售完)
    
    # 求所有商品价格的平均值(AVG聚合函数) 
    mysql> SELECT AVG(goods_price) FROM tdb_goods;
    +------------------+
    | AVG(goods_price) |
    +------------------+
    |     5395.6086957 |
    +------------------+
    1 row in set (0.01 sec)
    
    # 将平均值四舍五入,取小数点后两位(round聚合函数)
    mysql> SELECT ROUND(AVG(goods_price),2) FROM tdb_goods;
    +---------------------------+
    | ROUND(AVG(goods_price),2) |
    +---------------------------+
    |                   5395.61 |
    +---------------------------+
    1 row in set (0.01 sec)
    
    # 查询价格大于平均值的笔记本(一般查询方式)
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price >= 5395.61;
    +----------+----------------------------------+-------------+
    | goods_id | goods_name                       | goods_price |
    +----------+----------------------------------+-------------+
    |        3 | G150TH 15.6英寸游戏本            |    8499.000 |
    |        7 | SVP13226SCB 13.3英寸触控超极本   |    7999.000 |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑  |    9188.000 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑 |   28888.000 |
    |       18 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    |       20 | X3250 M4机架式服务器 2583i14     |    6888.000 |
    |       22 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    +----------+----------------------------------+-------------+
    7 rows in set (0.00 sec)
    
    # 查询价格大于平均值的笔记本(子查询方式)
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price >= (SELECT ROUND(AVG(goods_price),2) FROM tdb_goods);
    +----------+----------------------------------+-------------+
    | goods_id | goods_name                       | goods_price |
    +----------+----------------------------------+-------------+
    |        3 | G150TH 15.6英寸游戏本            |    8499.000 |
    |        7 | SVP13226SCB 13.3英寸触控超极本   |    7999.000 |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑  |    9188.000 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑 |   28888.000 |
    |       18 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    |       20 | X3250 M4机架式服务器 2583i14     |    6888.000 |
    |       22 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    +----------+----------------------------------+-------------+
    7 rows in set (0.02 sec)
    

    5.3.2、用 ANY、SOME 或 ALL 修饰的比较运算符

    当子查询的结果是多个时,在做比较时可以使用 any、some、all 关键字修饰比较运算符。

    # 语法结构,any、some 只需符合其中一个即可,all 需要符合全部
    operand comparison_operator ANY (subquery)
    operand comparison_operator SOME (subquery)
    operand comparison_operator ALL (subquery)
    
    ANY、SOME、ALL关键字
    # 查询笔记本的价格
    mysql> SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本';
    +-------------+
    | goods_price |
    +-------------+
    |    4999.000 |
    |    4299.000 |
    |    7999.000 |
    +-------------+
    3 rows in set (0.00 sec)
    
    # 查询数据表 tdb_price 中所有比子查询中的最小值(4299)大或等于的笔记本,使用了关键字 ANY
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price >= ANY (SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本');
    +----------+----------------------------------+-------------+
    | goods_id | goods_name                       | goods_price |
    +----------+----------------------------------+-------------+
    |        2 | Y400N 14.0英寸笔记本电脑         |    4899.000 |
    |        3 | G150TH 15.6英寸游戏本            |    8499.000 |
    |        5 | X240(20ALA0EYCD) 12.5英寸超极本  |    4999.000 |
    |        6 | U330P 13.3英寸超极本             |    4299.000 |
    |        7 | SVP13226SCB 13.3英寸触控超极本   |    7999.000 |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑  |    9188.000 |
    |       16 | PowerEdge T110 II服务器          |    5388.000 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑 |   28888.000 |
    |       18 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    |       20 | X3250 M4机架式服务器 2583i14     |    6888.000 |
    |       22 |  HMZ-T3W 头戴显示设备            |    6999.000 |
    +----------+----------------------------------+-------------+
    11 rows in set (0.01 sec)
    
    # 查询数据表 tdb_price 中所有比子查询中的最小值(7999)大或等于的笔记本,使用了关键字 ALL
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price >= ALL (SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本');
    +----------+----------------------------------+-------------+
    | goods_id | goods_name                       | goods_price |
    +----------+----------------------------------+-------------+
    |        3 | G150TH 15.6英寸游戏本            |    8499.000 |
    |        7 | SVP13226SCB 13.3英寸触控超极本   |    7999.000 |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑  |    9188.000 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑 |   28888.000 |
    +----------+----------------------------------+-------------+
    

    5.4、使用 [NOT ] IN 的子查询

    5.4.1、IN、NOT IN

    # 语法结构
    operand comparison_operator [NOT] IN (subquery) 
    = ANY 运算符与 IN 等效
    != ALL 或 <> ALL 运符与 NOT IN 等效
    
    # NOT IN
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price NOT IN (SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本');
    
    # != ALL
    mysql> SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price != ALL (SELECT goods_price FROM tdb_goods WHERE goods_cate = '超级本');
    

    5.4.2、EXISTS、NOT EXISTS

    如果子查询返回任何行, EXISTS 将返回 True,否则 False

    5.5、使用 INSERT...SELECT 插入记录

    将查询结果写入数据表

    # 语法结构
    INSERT [INTO] tbl_name [(col_name,...)]
    SELECT ...
    
    # 查看数据表结构
    mysql> SELECT * FROM tdb_goods\G
    *************************** 1. row ***************************
       goods_id: 1
     goods_name: R510VC 15.6英寸笔记本
     goods_cate: 笔记本
     brand_name: 华硕
    goods_price: 3399.000
        is_show: 1
     is_saleoff: 0
    *************************** 2. row ***************************
       goods_id: 2
     goods_name: Y400N 14.0英寸笔记本电脑
     goods_cate: 笔记本
     brand_name: 联想
    goods_price: 4899.000
        is_show: 1
     is_saleoff: 0
    .............................................................
    *************************** 22. row ***************************
       goods_id: 22
     goods_name:  HMZ-T3W 头戴显示设备
     goods_cate: 笔记本配件
     brand_name: 索尼
    goods_price: 6999.000
        is_show: 1
     is_saleoff: 0
    *************************** 23. row ***************************
       goods_id: 23
     goods_name: 商务双肩背包
     goods_cate: 笔记本配件
     brand_name: 索尼
    goods_price: 99.000
        is_show: 1
     is_saleoff: 0
    23 rows in set (0.00 sec)
    
    # 数据表 tdb_goods 中的商品可分为 7 类
    mysql> SELECT * FROM tdb_goods_cates;
    +---------+---------------+
    | cate_id | cate_name     |
    +---------+---------------+
    |       1 | 台式机        |
    |       2 | 平板电脑      |
    |       3 | 服务器/工作站 |
    |       4 | 游戏本        |
    |       5 | 笔记本        |
    |       6 | 笔记本配件    |
    |       7 | 超级本        |
    +---------+---------------+
    7 rows in set (0.00 sec)
    

    通过查看 tdb_goods 的数据表结构发现商品分为7类,使用汉字代替的 goods_cate,因为汉字占的字节比字母长,所以当一个数据表很庞大时,就会影响查询速度,最好的办法是使用外键(即将goods_cate的汉字使用数字代替),而使用外键需要用到两张数据表,因此,我们需要将子查询出来的分类记录插入到另外一张数据表中。
    物理外键指的是使用foreign key 作为外键关联另一张的字段的连接方法,而且限定了引擎为InnoDB,而逻辑外键,又叫做事实外键,是因为存在语法上的逻辑关联而产生的外键,需要有连接关键词inner join 或者left join 等等和连接部分,也就是on后面的部分,如果需要对应的设置,也可以加上set等语句

    # 创建一个新的数据表 tbd_goods_cates,用于存储数据表 tdb_goods 中的商品分类
    mysql> CREATE TABLE IF NOT EXISTS tdb_goods_cates(
        -> cate_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
        -> cate_name VARCHAR(40) NOT NULL
        -> );
    Query OK, 0 rows affected (0.04 sec)
    
    # 查询 tdb_goods_cates 的数据表结构
    mysql> DESC tdb_goods_cates;
    +-----------+----------------------+------+-----+---------+----------------+
    | Field     | Type                 | Null | Key | Default | Extra          |
    +-----------+----------------------+------+-----+---------+----------------+
    | cate_id   | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
    | cate_name | varchar(40)          | NO   |     | NULL    |                |
    +-----------+----------------------+------+-----+---------+----------------+
    2 rows in set (0.00 sec)
    
    # 将查询结果插入到数据表 tdb_goods_cates 的 cate_name 列中
    mysql> INSERT tdb_goods_cates(cate_name) SELECT goods_cate FROM tdb_goods GROUP BY goods_cate;
    Query OK, 7 rows affected (0.02 sec)
    Records: 7  Duplicates: 0  Warnings: 0
    
    # 查看tdb_goods_cates 结构
    mysql> SELECT * FROM tdb_goods_cates;
    +---------+---------------+
    | cate_id | cate_name     |
    +---------+---------------+
    |       1 | 台式机        |
    |       2 | 平板电脑      |
    |       3 | 服务器/工作站 |
    |       4 | 游戏本        |
    |       5 | 笔记本        |
    |       6 | 笔记本配件    |
    |       7 | 超级本        |
    +---------+---------------+
    7 rows in set (0.00 sec)
    

    5.6、多表更新

    # 语法结构
    UPDATE table_references  # 表的参照关系
    SET col_name1 = {expr1 | DEFAULT}
    [, col_name2 = {expr2 | DEFAULT}]...
    [WHERE where_Condition]
    
    # 表的参照关系(table_reference)的语法结构
    table_referenece  # 表 1
    {[INNER | CROSS] JOIN | {LEFT | RIGHT} [OUTER] JOIN}  # 连接类型
    table_reference   # 表 2
    ON conditional_expr  # 连接条件
    
    # 连接类型
    INNER JOIN, 内连接
    在 MySQL 中,JOIN, CROSS JOIN 和 INNER JOIN 是等价的
    LEFT [OUTER] JOIN, 左外连接
    RIGHT [OUTER] JOIN, 右外连接
    
    # 使用内连接的方式把两个数据表连接起来,连接条件为 goods_cate = cate_name,将 goods_cate 设置为 cate_id
    mysql> UPDATE tdb_goods INNER JOIN tdb_goods_cates ON goods_cate = cate_name
        -> SET goods_cate = cate_id;
    Query OK, 23 rows affected (0.01 sec)
    Rows matched: 23  Changed: 23  Warnings: 0
    
    # 查询数据表 tdb_goods 结构,发现 goods_cate 已经更新为 cate_id
    mysql> SELECT * FROM tdb_goods\G
    *************************** 1. row ***************************
       goods_id: 1
     goods_name: R510VC 15.6英寸笔记本
     goods_cate: 5
     brand_name: 华硕
    goods_price: 3399.000
        is_show: 1
     is_saleoff: 0
    ........................................
    

    5.7、多表更新之一步到位

    创建数据表同时将查询结果写入到数据表(CREATE...SELECT)

    CREATE TABLE [IF NOT EXISTS ] tbl_name
    [(create_definition,...)]
    select_statement
    

    将(创建数据表)和(把查询结果插入到新的数据表)两步,合并成一步: **

    # 创建数据表,插入查询结果
    mysql> CREATE TABLE tdb_goods_brands(
        -> brand_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
        -> brand_name VARCHAR(40) NOT NULL
        -> )
        -> SELECT brand_name FROM tdb_goods GROUP BY brand_name;
    Query OK, 10 rows affected (0.05 sec)
    Records: 10  Duplicates: 0  Warnings: 0
    
    # 查看刚创建的数据表
    mysql> SELECT * FROM tdb_goods_brands;
    +----------+------------+
    | brand_id | brand_name |
    +----------+------------+
    |        1 | IBM        |
    |        2 | 九州风神   |
    |        3 | 华硕       |
    |        4 | 宏碁       |
    |        5 | 惠普       |
    |        6 | 戴尔       |
    |        7 | 索尼       |
    |        8 | 联想       |
    |        9 | 苹果       |
    |       10 | 雷神       |
    +----------+------------+
    10 rows in set (0.00 sec)
    

    多表更新:

    # 给两个数据表取别名,以区分各自的 brand_name 列
    mysql> UPDATE tdb_goods AS a INNER JOIN tdb_goods_brands AS b ON a.brand_name = b.brand_name
        -> SET a.brand_name = b.brand_id;
    Query OK, 23 rows affected (0.01 sec)
    Rows matched: 23  Changed: 23  Warnings: 0
    
    # 查看数据表 tdb_goods 结构,发现 brand_name 已更新为 brand_id
    mysql> SELECT * FROM tdb_goods\G
    *************************** 1. row ***************************
       goods_id: 1
     goods_name: R510VC 15.6英寸笔记本
     goods_cate: 5
     brand_name: 3
    goods_price: 3399.000
        is_show: 1
     is_saleoff: 0
     ...
     23 rows in set (0.00 sec)
    

    更改数据类型:

    # 查看数据表 tdb_goods,发现更新了之后,goods_cate、brand_name 的名称和数据类型都没有改变,仍然是字符型而不是数字类型
    mysql> SHOW COLUMNS FROM tdb_goods;
    +-------------+------------------------+------+-----+---------+----------------+
    | Field       | Type                   | Null | Key | Default | Extra          |
    +-------------+------------------------+------+-----+---------+----------------+
    | goods_id    | smallint(5) unsigned   | NO   | PRI | NULL    | auto_increment |
    | goods_name  | varchar(150)           | NO   |     | NULL    |                |
    | goods_cate  | varchar(40)            | NO   |     | NULL    |                |
    | brand_name  | varchar(40)            | NO   |     | NULL    |                |
    | goods_price | decimal(15,3) unsigned | NO   |     | 0.000   |                |
    | is_show     | tinyint(1)             | NO   |     | 1       |                |
    | is_saleoff  | tinyint(1)             | NO   |     | 0       |                |
    +-------------+------------------------+------+-----+---------+----------------+
    7 rows in set (0.01 sec)
    
    # 修改列名和数据类型
    mysql> ALTER TABLE tdb_goods
        -> CHANGE goods_cate cate_id SMALLINT UNSIGNED NOT NULL,
        -> CHANGE brand_name brand_id SMALLINT UNSIGNED NOT NULL;
    Query OK, 23 rows affected (0.09 sec)
    Records: 23  Duplicates: 0  Warnings: 0
    
    # 查看数据表结构
    mysql> SHOW COLUMNS FROM tdb_goods;
    +-------------+------------------------+------+-----+---------+----------------+
    | Field       | Type                   | Null | Key | Default | Extra          |
    +-------------+------------------------+------+-----+---------+----------------+
    | goods_id    | smallint(5) unsigned   | NO   | PRI | NULL    | auto_increment |
    | goods_name  | varchar(150)           | NO   |     | NULL    |                |
    | cate_id     | smallint(5) unsigned   | NO   |     | NULL    |                |
    | brand_id    | smallint(5) unsigned   | NO   |     | NULL    |                |
    | goods_price | decimal(15,3) unsigned | NO   |     | 0.000   |                |
    | is_show     | tinyint(1)             | NO   |     | 1       |                |
    | is_saleoff  | tinyint(1)             | NO   |     | 0       |                |
    +-------------+------------------------+------+-----+---------+----------------+
    7 rows in set (0.01 sec)
    

    5.8、连接

    连接多个数据表,从中获取数据
    MySQL 在 SELECT 语句、多表更新、多表删除语句中支持 JOIN 操作

    # 语法结构
    table_referenece  # 表 1
    {[INNER | CROSS] JOIN | {LEFT | RIGHT} [OUTER] JOIN}  # 连接类型
    table_reference   # 表 2
    ON conditional_expr  # 连接条件
    
    # 连接类型
    INNER JOIN, 内连接
    在 MySQL 中,JOIN, CROSS JOIN 和 INNER JOIN 是等价的
    LEFT [OUTER] JOIN, 左外连接
    RIGHT [OUTER] JOIN, 右外连接
    

    数据表参照(table_reference):

    tbl_name [[AS] alias] | table_subquery [AS] alias
    数据表可以使用 tbl_name AS alias_name
    或 tbl_name alias_name 赋予别名
    
    tbl_subquery 可以作为子查询使用在 FROM 子句中,
    这样的子查询必须为其赋予别名。
    

    5.9、内连接 INNER JOIN

    一般情况都是使用关键字 ON 来作为连接条件,也可以使用 WHERE(对结果集记录的过滤) 来代替。


    内连接
    # 查看 tdb_goods 数据表结构
    mysql> SHOW COLUMNS FROM tdb_goods;
    +-------------+------------------------+------+-----+---------+----------------+
    | Field       | Type                   | Null | Key | Default | Extra          |
    +-------------+------------------------+------+-----+---------+----------------+
    | goods_id    | smallint(5) unsigned   | NO   | PRI | NULL    | auto_increment |
    | goods_name  | varchar(150)           | NO   |     | NULL    |                |
    | cate_id     | smallint(5) unsigned   | NO   |     | NULL    |                |
    | brand_id    | smallint(5) unsigned   | NO   |     | NULL    |                |
    | goods_price | decimal(15,3) unsigned | NO   |     | 0.000   |                |
    | is_show     | tinyint(1)             | NO   |     | 1       |                |
    | is_saleoff  | tinyint(1)             | NO   |     | 0       |                |
    +-------------+------------------------+------+-----+---------+----------------+
    7 rows in set (0.01 sec)
    
    # 查看 tdb_goods_cates 数据表结构
    mysql> SHOW COLUMNS FROM tdb_goods_cates;
    +-----------+----------------------+------+-----+---------+----------------+
    | Field     | Type                 | Null | Key | Default | Extra          |
    +-----------+----------------------+------+-----+---------+----------------+
    | cate_id   | smallint(5) unsigned | NO   | PRI | NULL    | auto_increment |
    | cate_name | varchar(40)          | NO   |     | NULL    |                |
    +-----------+----------------------+------+-----+---------+----------------+
    2 rows in set (0.00 sec)
    
    # 查看数据表 tdb_goods_cates
    mysql> SELECT * FROM tdb_goods_cates;
    +---------+---------------+
    | cate_id | cate_name     |
    +---------+---------------+
    |       1 | 台式机        |
    |       2 | 平板电脑      |
    |       3 | 服务器/工作站 |
    |       4 | 游戏本        |
    |       5 | 笔记本        |
    |       6 | 笔记本配件    |
    |       7 | 超级本        |
    +---------+---------------+
    7 rows in set (0.00 sec)
    
    # 给数据表 tdb_goods 插入一条记录,其中 cate_id 设置为12,因为 cate_id 中没有 12,所有,内连接没有显示这条数据
    mysql> INSERT tdb_goods(goods_name,cate_id,brand_id,goods_price) VALUES(' LaserJet Pro P1606dn 黑白激光打印机','12','4','1849');
    Query OK, 1 row affected (0.00 sec)
    
    # 内连接
    mysql> SELECT goods_id,goods_name,cate_name FROM tdb_goods AS a INNER JOIN tdb_goods_cates AS b ON a.cate_id = b.cate_id;
    +----------+------------------------------------------------------------------------+---------------+
    | goods_id | goods_name                                                             | cate_name     |
    +----------+------------------------------------------------------------------------+---------------+
    |        1 | R510VC 15.6英寸笔记本                                                  | 笔记本        |
    |        2 | Y400N 14.0英寸笔记本电脑                                               | 笔记本        |
    
    |       21 | 玄龙精英版 笔记本散热器                                                | 笔记本配件    |
    |       22 |  HMZ-T3W 头戴显示设备                                                  | 笔记本配件    |
    |       23 | 商务双肩背包                                                           | 笔记本配件    |
    +----------+------------------------------------------------------------------------+---------------+
    23 rows in set (0.00 sec)
    

    5.10、外连接 OUTER JOIN

    左外 右外
    # 数据表tdb_goods_cates 插入一条记录
    mysql> INSERT tdb_goods_cates(cate_name) VALUES('路由器'),('交换机'),('网卡');
    Query OK, 3 rows affected (0.01 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    # 查看数据表 tdb_goods_cates
    mysql> SELECT * FROM tdb_goods_cates;
    +---------+---------------+
    | cate_id | cate_name     |
    +---------+---------------+
    |       1 | 台式机        |
    |       2 | 平板电脑      |
    |       3 | 服务器/工作站 |
    |       4 | 游戏本        |
    |       5 | 笔记本        |
    |       6 | 笔记本配件    |
    |       7 | 超级本        |
    |       8 | 路由器        |
    |       9 | 交换机        |
    |      10 | 网卡          |
    +---------+---------------+
    10 rows in set (0.00 sec)
    
    # 左外连接,显示左表(tdb_goods)的全部记录,和符合(a.cate_id = b.cate_id)条件的右表(tdb_goods_cates)的记录,没有的为 NULL
    mysql> SELECT goods_id,goods_name,cate_name FROM tdb_goods AS a LEFT JOIN tdb_goods_cates AS b ON a.cate_id = b.cate_id;
    +----------+------------------------------------------------------------------------+---------------+
    | goods_id | goods_name                                                             | cate_name     |
    +----------+------------------------------------------------------------------------+---------------+
    |        1 | R510VC 15.6英寸笔记本                                                  | 笔记本        |
    |        2 | Y400N 14.0英寸笔记本电脑                                               | 笔记本        |
    |        3 | G150TH 15.6英寸游戏本                                                  | 游戏本        |
    |        4 | X550CC 15.6英寸笔记本                                                  | 笔记本        |
    |        5 | X240(20ALA0EYCD 12.5英寸超极本                                         | 超级本        |
    |        6 | U330P 13.3英寸超极本                                                   | 超级本        |
    |        7 | SVP13226SCB 13.3英寸触控超极本                                         | 超级本        |
    |        8 | iPad mini MD531CH/A 7.9英寸平板电脑                                    | 平板电脑      |
    |        9 | iPad Air MD788CH/A 9.7英寸平板电脑 (16G WiFi版)                      | 平板电脑      |
    |       10 |  iPad mini ME279CH/A 配备 Retina 显示屏 7.9英寸平板电脑 (16G WiFi版) | 平板电脑      |
    |       11 | IdeaCentre C340 20英寸一体电脑                                         | 台式机        |
    |       12 | Vostro 3800-R1206 台式电脑                                             | 台式机        |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑                                        | 台式机        |
    |       14 | AT7-7414LP 台式电脑 (i5-3450四核 4G 500G 2G独显 DVD 键鼠 Linux )     | 台式机        |
    |       15 | Z220SFF F4F06PA工作站                                                  | 服务器/工作站 |
    |       16 | PowerEdge T110 II服务器                                                | 服务器/工作站 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑                                       | 服务器/工作站 |
    |       18 |  HMZ-T3W 头戴显示设备                                                  | 笔记本配件    |
    |       19 | 商务双肩背包                                                           | 笔记本配件    |
    |       20 | X3250 M4机架式服务器 2583i14                                           | 服务器/工作站 |
    |       21 | 玄龙精英版 笔记本散热器                                                | 笔记本配件    |
    |       22 |  HMZ-T3W 头戴显示设备                                                  | 笔记本配件    |
    |       23 | 商务双肩背包                                                           | 笔记本配件    |
    |       24 |  LaserJet Pro P1606dn 黑白激光打印机                                   | NULL          |
    +----------+------------------------------------------------------------------------+---------------+
    24 rows in set (0.00 sec)
    
    # 右外连接,显示右表(tdb_goods_cates)的全部记录,和符合(a.cate_id = b.cate_id)条件的左表(tdb_goods)的记录,没有的为 NULL
    mysql> SELECT goods_id,goods_name,cate_name FROM tdb_goods AS a RIGHT JOIN tdb_goods_cates AS b ON a.cate_id = b.cate_id;
    +----------+------------------------------------------------------------------------+---------------+
    | goods_id | goods_name                                                             | cate_name     |
    +----------+------------------------------------------------------------------------+---------------+
    |        1 | R510VC 15.6英寸笔记本                                                  | 笔记本        |
    |        2 | Y400N 14.0英寸笔记本电脑                                               | 笔记本        |
    |        3 | G150TH 15.6英寸游戏本                                                  | 游戏本        |
    |        4 | X550CC 15.6英寸笔记本                                                  | 笔记本        |
    |        5 | X240(20ALA0EYCD 12.5英寸超极本                                         | 超级本        |
    |        6 | U330P 13.3英寸超极本                                                   | 超级本        |
    |        7 | SVP13226SCB 13.3英寸触控超极本                                         | 超级本        |
    |        8 | iPad mini MD531CH/A 7.9英寸平板电脑                                    | 平板电脑      |
    |        9 | iPad Air MD788CH/A 9.7英寸平板电脑 (16G WiFi版)                      | 平板电脑      |
    |       10 |  iPad mini ME279CH/A 配备 Retina 显示屏 7.9英寸平板电脑 (16G WiFi版) | 平板电脑      |
    |       11 | IdeaCentre C340 20英寸一体电脑                                         | 台式机        |
    |       12 | Vostro 3800-R1206 台式电脑                                             | 台式机        |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑                                        | 台式机        |
    |       14 | AT7-7414LP 台式电脑 (i5-3450四核 4G 500G 2G独显 DVD 键鼠 Linux )     | 台式机        |
    |       15 | Z220SFF F4F06PA工作站                                                  | 服务器/工作站 |
    |       16 | PowerEdge T110 II服务器                                                | 服务器/工作站 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑                                       | 服务器/工作站 |
    |       18 |  HMZ-T3W 头戴显示设备                                                  | 笔记本配件    |
    |       19 | 商务双肩背包                                                           | 笔记本配件    |
    |       20 | X3250 M4机架式服务器 2583i14                                           | 服务器/工作站 |
    |       21 | 玄龙精英版 笔记本散热器                                                | 笔记本配件    |
    |       22 |  HMZ-T3W 头戴显示设备                                                  | 笔记本配件    |
    |       23 | 商务双肩背包                                                           | 笔记本配件    |
    |     NULL | NULL                                                                   | 路由器        |
    |     NULL | NULL                                                                   | 交换机        |
    |     NULL | NULL                                                                   | 网卡          |
    +----------+------------------------------------------------------------------------+---------------+
    26 rows in set (0.01 sec)
    

    5.11、多表连接

    # 三张表连接,又回到(tdb_goods)最开始的时候
    mysql> SELECT goods_id,goods_name,goods_price,brand_name,cate_name FROM tdb_goods AS a
        -> INNER JOIN tdb_goods_cates AS b ON a.cate_id = b.cate_id
        -> INNER JOIN tdb_goods_brands AS c ON a.brand_id = c.brand_id;
    +----------+------------------------------------------------------------------------+-------------+------------+---------------+
    | goods_id | goods_name                                                             | goods_price | brand_name | cate_name     |
    +----------+------------------------------------------------------------------------+-------------+------------+---------------+
    |        1 | R510VC 15.6英寸笔记本                                                  |    3399.000 | 华硕       | 笔记本        |
    |        2 | Y400N 14.0英寸笔记本电脑                                               |    4899.000 | 联想       | 笔记本        |
    |        3 | G150TH 15.6英寸游戏本                                                  |    8499.000 | 雷神       | 游戏本        |
    |        4 | X550CC 15.6英寸笔记本                                                  |    2799.000 | 华硕       | 笔记本        |
    |        5 | X240(20ALA0EYCD 12.5英寸超极本                                         |    4999.000 | 联想       | 超级本        |
    |        6 | U330P 13.3英寸超极本                                                   |    4299.000 | 联想       | 超级本        |
    |        7 | SVP13226SCB 13.3英寸触控超极本                                         |    7999.000 | 索尼       | 超级本        |
    |        8 | iPad mini MD531CH/A 7.9英寸平板电脑                                    |    1998.000 | 苹果       | 平板电脑      |
    |        9 | iPad Air MD788CH/A 9.7英寸平板电脑 (16G WiFi版)                      |    3388.000 | 苹果       | 平板电脑      |
    |       10 |  iPad mini ME279CH/A 配备 Retina 显示屏 7.9英寸平板电脑 (16G WiFi版) |    2788.000 | 苹果       | 平板电脑      |
    |       11 | IdeaCentre C340 20英寸一体电脑                                         |    3499.000 | 联想       | 台式机        |
    |       12 | Vostro 3800-R1206 台式电脑                                             |    2899.000 | 戴尔       | 台式机        |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑                                        |    9188.000 | 苹果       | 台式机        |
    |       14 | AT7-7414LP 台式电脑 (i5-3450四核 4G 500G 2G独显 DVD 键鼠 Linux )     |    3699.000 | 宏碁       | 台式机        |
    |       15 | Z220SFF F4F06PA工作站                                                  |    4288.000 | 惠普       | 服务器/工作站 |
    |       16 | PowerEdge T110 II服务器                                                |    5388.000 | 戴尔       | 服务器/工作站 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑                                       |   28888.000 | 苹果       | 服务器/工作站 |
    |       18 |  HMZ-T3W 头戴显示设备                                                  |    6999.000 | 索尼       | 笔记本配件    |
    |       19 | 商务双肩背包                                                           |      99.000 | 索尼       | 笔记本配件    |
    |       20 | X3250 M4机架式服务器 2583i14                                           |    6888.000 | IBM        | 服务器/工作站 |
    |       21 | 玄龙精英版 笔记本散热器                                                |      99.000 | 九州风神   | 笔记本配件    |
    |       22 |  HMZ-T3W 头戴显示设备                                                  |    6999.000 | 索尼       | 笔记本配件    |
    |       23 | 商务双肩背包                                                           |      99.000 | 索尼       | 笔记本配件    |
    +----------+------------------------------------------------------------------------+-------------+------------+---------------+
    23 rows in set (0.00 sec)
    

    5.12、关于连接的几点说明

    外连接:

    # 左外连接
    A LIFET JOIN B join_condition
    
    • 数据表 B 的结果集依赖数据表 A
    • 数据表 A 的结果集根据左连接条件依赖所有数据表(B 表除外)
    • 左外连接条件决定如何检索数据表 B (在没有指定 WHERE 条件的情况下)
    • 如果数据表 A 的某条记录符合 WHERE 条件,但是在数据表 B 不存在,符合连接条件的记录,将生成一个所有列为空的额外的 B 行。
    • 如果使用内连接查找的记录在连接数据表中不存在,并且在 WHERE 子句中尝试以下操作: col_name IS NULL 时,如果 col_name 被定义为 NOT NULL,mysql 将在找到符合连接条件的记录后停止搜索更多的行。

    5.13、无限极分类表设计

    一般情况下,网站上的分类分为很多级,如书籍-文学-(散文、诗歌、文言文、歌剧等),因此在创建数据表时,需要对记录的分类进行无限极分类。

    自身连接:
    同一个数据表对其自身进行连接。

    # 数据表 tdb_goods_types
    mysql> 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.01 sec)
    

    现有一张关于家用电器、电脑和办公分类的数据表 tdb_goods_types,其中 parent_id 对应的是 type_id,比如说,电脑、办公和家用电器为顶级分类(对应 parent_id 为 0),大家电、生活电器是属于家用电器分类下的(对应的 parent_id 为 1),平板电视是属于大家电分类下的(对应的 parent_id 为 3),现想将哪种电器是属于哪个分类下的一一呈现出来:

    5.13.1、左表为子表,右表为父表

    将 tdb_goods_types 想象成左右两张表,假设:

    • 左表为子表:s.tdb_goods_types
    • 右表为父表:p.tdb_goods_types

    现将两张表连接起来,其中 child_id,child_name 属于子表,parents_name 属于父表,从表中可以看出,家用电器、电脑、办公为顶级分类,不属于其他分类,大家电、生活电器、平板电视属于家用电器(也就是说它的父类为家用电器)。

    mysql> SELECT s.type_id AS child_id,s.type_name AS child_name,p.type_name AS parents_name FROM tdb_goods_types AS s LEFT JOIN tdb_goods_types AS p
        -> ON s.parent_id = p.type_id;
    +----------+------------+--------------+
    | child_id | child_name | parents_name |
    +----------+------------+--------------+
    |        1 | 家用电器   | NULL         |
    |        2 | 电脑、办公 | NULL         |
    |        3 | 大家电     | 家用电器     |
    |        4 | 生活电器   | 家用电器     |
    |        5 | 平板电视   | 大家电       |
    |        6 | 空调       | 大家电       |
    |        7 | 电风扇     | 生活电器     |
    |        8 | 饮水机     | 生活电器     |
    |        9 | 电脑整机   | 电脑、办公   |
    |       10 | 电脑配件   | 电脑、办公   |
    |       11 | 笔记本     | 电脑整机     |
    |       12 | 超级本     | 电脑整机     |
    |       13 | 游戏本     | 电脑整机     |
    |       14 | CPU        | 电脑配件     |
    |       15 | 主机       | 电脑配件     |
    +----------+------------+--------------+
    15 rows in set (0.00 sec)
    

    5.13.2、左表为父表,右表为父子

    将 tdb_goods_types 想象成左右两张表,假设:

    • 左表为父表:p.tdb_goods_types
    • 右表为子表:s.tdb_goods_types

    现将两张表连接起来,其中 parents_id,parents_name 属于父表,child_name 属于子表。
    一、左为父表,右为子表:

    mysql> SELECT p.type_id AS parents_id,
        -> p.type_name AS parents_name,
        -> s.type_name AS child_name
        -> FROM tdb_goods_types AS p
        -> LEFT JOIN tdb_goods_types AS s
        -> ON s.parent_id = p.type_id;
    +------------+--------------+------------+
    | parents_id | parents_name | child_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       |
    +------------+--------------+------------+
    22 rows in set (0.00 sec)
    

    二、对 p.type_name 进行分类:

    mysql> SELECT p.type_id AS parents_id,
        -> p.type_name AS parents_name,
        -> s.type_name AS child_name
        -> FROM tdb_goods_types AS p
        -> LEFT JOIN tdb_goods_types AS s
        -> ON s.parent_id = p.type_id GROUP BY p.type_name
    +------------+--------------+------------+
    | parents_id | parents_name | child_name |
    +------------+--------------+------------+
    |         14 | CPU          | NULL       |
    |         15 | 主机         | NULL       |
    |          3 | 大家电       | 平板电视   |
    |          1 | 家用电器     | 大家电     |
    |          5 | 平板电视     | NULL       |
    |         13 | 游戏本       | NULL       |
    |          4 | 生活电器     | 电风扇     |
    |          2 | 电脑、办公   | 电脑整机   |
    |          9 | 电脑整机     | 笔记本     |
    |         10 | 电脑配件     | CPU        |
    |          7 | 电风扇       | NULL       |
    |          6 | 空调         | NULL       |
    |         11 | 笔记本       | NULL       |
    |         12 | 超级本       | NULL       |
    |          8 | 饮水机       | NULL       |
    +------------+--------------+------------+
    15 rows in set (0.00 sec)
    

    三、对 p.type_id 进行递增排序:

    mysql> SELECT p.type_id AS parents_id,
        -> p.type_name AS parents_name,
        -> s.type_name AS child_name
        -> FROM tdb_goods_types AS p
        -> LEFT JOIN tdb_goods_types AS s
        -> ON s.parent_id = p.type_id GROUP BY p.type_name ORDER BY p.type_id;
    +------------+--------------+------------+
    | parents_id | parents_name | child_name |
    +------------+--------------+------------+
    |          1 | 家用电器     | 大家电     |
    |          2 | 电脑、办公   | 电脑整机   |
    |          3 | 大家电       | 平板电视   |
    |          4 | 生活电器     | 电风扇     |
    |          5 | 平板电视     | NULL       |
    |          6 | 空调         | NULL       |
    |          7 | 电风扇       | NULL       |
    |          8 | 饮水机       | NULL       |
    |          9 | 电脑整机     | 笔记本     |
    |         10 | 电脑配件     | CPU        |
    |         11 | 笔记本       | NULL       |
    |         12 | 超级本       | NULL       |
    |         13 | 游戏本       | NULL       |
    |         14 | CPU          | NULL       |
    |         15 | 主机         | NULL       |
    +------------+--------------+------------+
    15 rows in set (0.00 sec)
    

    四:对 s.type_name 进行计算数目:

    mysql> SELECT p.type_id AS parents_id,
        -> p.type_name AS parents_name,
        -> count(s.type_name) AS child_count
        -> FROM tdb_goods_types AS p
        -> LEFT JOIN tdb_goods_types AS s
        -> ON s.parent_id = p.type_id GROUP BY p.type_name ORDER BY p.type_id;
    +------------+--------------+-------------+
    | parents_id | parents_name | child_count |
    +------------+--------------+-------------+
    |          1 | 家用电器     |           2 |
    |          2 | 电脑、办公   |           2 |
    |          3 | 大家电       |           2 |
    |          4 | 生活电器     |           2 |
    |          5 | 平板电视     |           0 |
    |          6 | 空调         |           0 |
    |          7 | 电风扇       |           0 |
    |          8 | 饮水机       |           0 |
    |          9 | 电脑整机     |           3 |
    |         10 | 电脑配件     |           2 |
    |         11 | 笔记本       |           0 |
    |         12 | 超级本       |           0 |
    |         13 | 游戏本       |           0 |
    |         14 | CPU          |           0 |
    |         15 | 主机         |           0 |
    +------------+--------------+-------------+
    

    5.14、多表删除

    DELETE tb_name[.*] [,tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]
    

    使用对自身的模拟,来删除数据表中多余的记录:

    # 对数据表 tdb_goods 进行查询发现,有两条记录是多余的
    mysql> SELECT goods_id,goods_name FROM tdb_goods
        -> GROUP BY goods_name
        -> HAVING count(goods_name) >= 2;
    +----------+-----------------------+
    | goods_id | goods_name            |
    +----------+-----------------------+
    |       18 |  HMZ-T3W 头戴显示设备 |
    |       19 | 商务双肩背包          |
    +----------+-----------------------+
    2 rows in set (0.01 sec)
    
    # 删除多余的记录,留下 goods_id 小的那个
    mysql> DELETE t1 FROM tdb_goods AS t1
        -> LEFT JOIN (SELECT 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;
    Query OK, 2 rows affected (0.02 sec)
    
    mysql> SELECT * FROM tdb_goods;
    +----------+------------------------------------------------------------------------+---------+----------+-------------+---------+------------+
    | goods_id | goods_name                                                             | cate_id | brand_id | goods_price | is_show | is_saleoff |
    +----------+------------------------------------------------------------------------+---------+----------+-------------+---------+------------+
    |        1 | R510VC 15.6英寸笔记本                                                  |       5 |        3 |    3399.000 |       1 |          0 |
    |        2 | Y400N 14.0英寸笔记本电脑                                               |       5 |        8 |    4899.000 |       1 |          0 |
    |        3 | G150TH 15.6英寸游戏本                                                  |       4 |       10 |    8499.000 |       1 |          0 |
    |        4 | X550CC 15.6英寸笔记本                                                  |       5 |        3 |    2799.000 |       1 |          0 |
    |        5 | X240(20ALA0EYCD 12.5英寸超极本                                         |       7 |        8 |    4999.000 |       1 |          0 |
    |        6 | U330P 13.3英寸超极本                                                   |       7 |        8 |    4299.000 |       1 |          0 |
    |        7 | SVP13226SCB 13.3英寸触控超极本                                         |       7 |        7 |    7999.000 |       1 |          0 |
    |        8 | iPad mini MD531CH/A 7.9英寸平板电脑                                    |       2 |        9 |    1998.000 |       1 |          0 |
    |        9 | iPad Air MD788CH/A 9.7英寸平板电脑 (16G WiFi版)                      |       2 |        9 |    3388.000 |       1 |          0 |
    |       10 |  iPad mini ME279CH/A 配备 Retina 显示屏 7.9英寸平板电脑 (16G WiFi版) |       2 |        9 |    2788.000 |       1 |          0 |
    |       11 | IdeaCentre C340 20英寸一体电脑                                         |       1 |        8 |    3499.000 |       1 |          0 |
    |       12 | Vostro 3800-R1206 台式电脑                                             |       1 |        6 |    2899.000 |       1 |          0 |
    |       13 | iMac ME086CH/A 21.5英寸一体电脑                                        |       1 |        9 |    9188.000 |       1 |          0 |
    |       14 | AT7-7414LP 台式电脑 (i5-3450四核 4G 500G 2G独显 DVD 键鼠 Linux )     |       1 |        4 |    3699.000 |       1 |          0 |
    |       15 | Z220SFF F4F06PA工作站                                                  |       3 |        5 |    4288.000 |       1 |          0 |
    |       16 | PowerEdge T110 II服务器                                                |       3 |        6 |    5388.000 |       1 |          0 |
    |       17 | Mac Pro MD878CH/A 专业级台式电脑                                       |       3 |        9 |   28888.000 |       1 |          0 |
    |       18 |  HMZ-T3W 头戴显示设备                                                  |       6 |        7 |    6999.000 |       1 |          0 |
    |       19 | 商务双肩背包                                                           |       6 |        7 |      99.000 |       1 |          0 |
    |       20 | X3250 M4机架式服务器 2583i14                                           |       3 |        1 |    6888.000 |       1 |          0 |
    |       21 | 玄龙精英版 笔记本散热器                                                |       6 |        2 |      99.000 |       1 |          0 |
    |       24 |  LaserJet Pro P1606dn 黑白激光打印机                                   |      12 |        4 |    1849.000 |       1 |          0 |
    +----------+------------------------------------------------------------------------+---------+----------+-------------+---------+------------+
    22 rows in set (0.00 sec)
    

    相关文章

      网友评论

        本文标题:5、子查询与连接

        本文链接:https://www.haomeiwen.com/subject/mwcvhftx.html