五、子查询与连接

5-1 数据准备

创建数据库

CREATE TABLE IF NOT EXISTS tdb_goods(
    goods_id    SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    goods_name  VARCHAR(150) NOT NULL,
    goods_cate  VARCHAR(40)  NOT NULL,
    brand_name  VARCHAR(40)  NOT NULL,
    goods_price DECIMAL(15,3) UNSIGNED NOT NULL DEFAULT 0,
    is_show     BOOLEAN NOT NULL DEFAULT 1,
    is_saleoff  BOOLEAN NOT NULL DEFAULT 0
  );

如果中文显示为乱码,或者无法插入中文,则设置客户端的编码方式,与数据无关

SET NAMES gbk;

写入记录

NSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('R510VC 15.6英寸笔记本','笔记本','华硕','3399',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Y400N 14.0英寸笔记本电脑','笔记本','联想','4899',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('G150TH 15.6英寸游戏本','游戏本','雷神','8499',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X550CC 15.6英寸笔记本','笔记本','华硕','2799',DEFAULT,DEFAULT);
 
INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X240(20ALA0EYCD) 12.5英寸超极本','超级本','联想','4999',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('U330P 13.3英寸超极本','超级本','联想','4299',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('SVP13226SCB 13.3英寸触控超极本','超级本','索尼','7999',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iPad mini MD531CH/A 7.9英寸平板电脑','平板电脑','苹果','1998',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iPad Air MD788CH/A 9.7英寸平板电脑 (16G WiFi版)','平板电脑','苹果','3388',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' iPad mini ME279CH/A 配备 Retina 显示屏 7.9英寸平板电脑 (16G WiFi版)','平板电脑','苹果','2788',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('IdeaCentre C340 20英寸一体电脑 ','台式机','联想','3499',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Vostro 3800-R1206 台式电脑','台式机','戴尔','2899',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('iMac ME086CH/A 21.5英寸一体电脑','台式机','苹果','9188',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('AT7-7414LP 台式电脑 (i5-3450四核 4G 500G 2G独显 DVD 键鼠 Linux )','台式机','宏碁','3699',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Z220SFF F4F06PA工作站','服务器/工作站','惠普','4288',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('PowerEdge T110 II服务器','服务器/工作站','戴尔','5388',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('Mac Pro MD878CH/A 专业级台式电脑','服务器/工作站','苹果','28888',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' HMZ-T3W 头戴显示设备','笔记本配件','索尼','6999',DEFAULT,DEFAULT);

 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('商务双肩揹包','笔记本配件','索尼','99',DEFAULT,DEFAULT);

 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('X3250 M4机架式服务器 2583i14','服务器/工作站','IBM','6888',DEFAULT,DEFAULT);
 
 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('玄龙精英版 笔记本散热器','笔记本配件','九州风神','',DEFAULT,DEFAULT);

 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES(' HMZ-T3W 头戴显示设备','笔记本配件','索尼','6999',DEFAULT,DEFAULT);

 INSERT tdb_goods (goods_name,goods_cate,brand_name,goods_price,is_show,is_saleoff) VALUES('商务双肩揹包','笔记本配件','索尼','99',DEFAULT,DEFAULT);

 

5-2 子查询简介

子查询是指出现在【其他SQL语句内】的SELECT子句

eg:

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

其中,SELECT * FROM t1 ...称为Outer Query[外查询](或者Outer Statement)

SELECT column1 FROM t2 称为Sub Query[子查询]

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

 

5-3由比较运算符引发的子查询

单独分析筛选时

 

SELECT AVG(goods_price) FROM tdb_goods; //AVG函数代表求其平均值//

SELECT ROUND(AVG(goods_price),2) FROM tdb_goods; //round(@,#)代表输出格式为@数小数点后#位输出//

SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price>=5391.30; //输出价格大于5391.30的id、name、price//

综合起来运用子查询时

ELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price>=(SELECT ROUND(AVG(goods_price),2) FROM tdb_goods); //查找价格大于平均值的商品//

SELECT goods_price FROM tdb_price WHERE goods_cate='超级本'\G; //检索结果非唯一//

对于ANY、SOME、ALL的用法各有不同

SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price>=ANY (SELECT goods_price FROM tdb_goods WHERE goods_cate='超级本');

SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price>=ALL (SELECT goods_price FROM tdb_goods WHERE goods_cate='超级本');

SELECT goods_id,goods_name,goods_price FROM tdb_goods WHERE goods_price>=SOME (SELECT goods_price FROM tdb_goods WHERE goods_cate='超级本');

 

5-4 由[NOT] IN/EXISTS引发的子查询

子查询---in not in

  • in 相当于=any
  • not in 相当于 !=all 或者<>all ——不等于、不包含

子查询----exists not exists ——用得比较少

  • 如果子查询返回任何行 exists返回true 否则返回 false

 = 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 = '超级本')

 

5-5使用INSERT...SELECT插入记录

INSERT [INTO] tbl_name SET col_name={exprDEFAULT},...//可以使用子查询

INSERT [INTO] tbl_name [(col_name,...)] SELECT ...//将查询结果写入数据表

Eg:

INSERT INTO table_name [(column_name)] SELECT column_name2 FROM table_name2 GROUP BY column_name3;

创建商品分类表

CREATE TABLE IF NOT EXISTS tdb_goods_cates(

cate_id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,

cate_name VARCHAR(40) NOT NULL

);

 

SELECT goods_cate FROM tdb_goods GROUP BY goods_cate; //列出所有品牌cate

DESC tdb_goods_cates; //显示出tdb_goods_cates表中的项目名称,与SHOW COLUMNS FROM tdb_goods_cates;作用相同

INSERT tdb_goods_cates(cate_name) SELECT goods_cate FROM tdb_goods GROUP BY goods_cate;//在表tdb_goods_cates中插入tdb_goods中的cate

 

5-6多表更新

UPDATE table_references SET col_name1={expr1 | DEFAULT} [,col_name2={expr2 | DEFAULT}]... [WHERE where_condition]

  • INNER JOIN,内连接
  • 在MySQL中,JOIN, CROSS JOIN 和 INNER JOIN 是等价的。
  • LEFT [OUTER] JOIN ,左外连接
  • RIGHT [OUTER] JOIN,右外连接

update tdb_goods inner join tdb_goods_cates on goods_cate=cate_name set goods_cate=cate_id;

  • tdb_goods:想要更改的表名
  • inner join: 内连接
  • tdb_goods_cates: 关联的附表
  • goods_cate=cate_name 两个表对应列的关系
  • goods_cate=cate_id; 设置 值

 

5-7 多表更新之一步到位

建表、查询、写入三合一

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;

多表更新

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;

通过ALTER TABLE语句修改数据表结构

ALTER TABLE tdb_goods

CHANGE goods_cate cate_id SMALLINT UNSIGNED NOT NULL,

CHANGE brand_name brand_id SMALLINT UNSIGNED NOT NULL;

  • PS:外键,不一定是物理的外键,逻辑的外键也行,当然,物理外键更能保证数据的完整性和一致性。 数字类型的字段占用的空间更小,查询的效率也更高。

 

5-8 连接的语法结构

MySQL在SELECT语句、多表更新、多表删除语句中支持JOIN操作。

table reference A

{[INNER|CROSS] JOIN | {LEFT|RIGHT} [OUTER] JOIN}

table_reference B

ON condition_expr

数据表参照

table_reference

tbl_name [[AS] alias] | table_subquery [AS] alias

数据表可以使用tbl_name AS alias_name 或 tbl_name alias_name赋予别名。

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

 

5-9 内连接INNER JOIN

 

  • 在MySQL中JOIN,INNER JOIN,CROSS JOIN是等价的
  • 交集 仅显示A、B两表符合连接条件的记录。不符合连接条件的记录不显示。

 

5-10外链接 OUTER JOIN

  • LEFT JOIN:显示左表全部和左右符合连接条件的记录
  • RIGHT JOIN:显示左右符合连接条件的记录和右表全部记录
  • 若某字段只存在某一表,则另一表的里字段返回null

 

5-11多表连接

  • 多表的连接跟两张表的连接一样

SELECT A.a,B.b,C.c

FROM tabA

JOIN tabB ON conditonal_expr 

JOIN tabC ON conditonal_expr

 

5-12关于连接的几点说明

外连接:

以左外连接为例:

A LEFT JOIN B join_condition

  • 数据表B的结果集依赖于数据表A
  • 数据表A的结果集根据左连接条件依赖所有数据表(B表除外)
  • 左外连接条件决定如何检索数据表B(在没有指定WHERE条件的情况下)
  • 如果数据表A的某条记录符合WHERE条件,但是在数据表B不存在符合连接条件的记录,将生成一个所有列为空的额外的B行

内连接:

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

 

5-13无限级分类表设计

 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
  ); 

 

无限分类

  • 即在同一张表中既有父类,又有子类
  • 通过在分类表中再增加多一个字段标识其属于哪一个父类的 ID 来实现
  • 可以通过对同一张数据表的自身连接来进行查询,需要对表标识别名

查找显示父级id对应的名称

select s.type_id ,s.type_name,p.type_name As parent_id from tdb_goods_types s left join

tdb_goods_types p on s.parent_id=p.type_id;

查找子级对应的名称

select p.type_id ,p.type_name,s.type_name from tdb_goods_types p left join

tdb_goods_types s on p.type_id=s.parent_id;

查找有多少子级

select p.type_id ,p.type_name,COUNT(s.type_name) from tdb_goods_types p left join

tdb_goods_types s on p.type_id=s.parent_id

GROUP BY p.type_name ORDER BY p.type_id;

 

5-14多表删除

delete t1 from tdb_goods as t1 //从本表中删除,将tdb_goods看做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 //t1和t2的连接条件

where t1.goods_id>t2.goods_id; //删除id号较大的条目

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章