MySQL--5--subquery和连接

1.子查询

是指出现在其他SQL语句内的select子句

形式: SELECT * FROM T1 WHERE COL1=(SELECT COL2 FROM T2);

其中,select * from t1 称为外部查询(注意,不仅限于select 语句,包括SELECT、INSERT、UPDATE、DELETE)

(SELECT COL2 FROM T2)称为子查询:

子查询指嵌套在查询内部,且必须始终出现在小括号内;
子查询可以包含多个关键字或条件,包括SELECT GROUP BY/ORDER BY/LIMIT

外部查询可以是INSERT、SELECT、UPDATE、DELETE、SET、DO……

子查询的返回值可以是标量、一行、一列、一个表(子子查询)

1.1 使用子查询进行比较

比较运算符: < 、>  =  <=   >=  !=

一般形式:select 字段1[as b],字段2,…… from  where 字段3/字段3表达式’ >=运算符(子查询表达式--select 字段3/字段3表达式 from ……where ……);

  1. select Code,Name,Region,Continent,LifeExpectancy from country where LifeExpectancy >= (select round(avg(LifeExpectancy),1) from country) order by LifeExpectancy desc;
  1. select goods_id,goods_name,goods_price from tdb_goods where goods_price >=(select round(avg(goods_price),2) from tdb_goods); ##avg 是一个聚合函数,只有一个值

当子查询返回的包含多个结果时,需要用ANY、SOME、ALL 做修饰:其中SOME和ANY是一样的,

  1. select goods_price,goods_name,goods_id from tdb_goods where goods_price > any (select goods_price from tdb_goods where goods_cate=‘超级本‘); # any 此处是指只要大于任意符合条件的价格就可以,(就是大于最小的)。若为all。则是大于最大的

  1. select goods_price,goods_name from tdb_goods where goods_price !=all(select goods_price from tdb_goods where cate_id=1);
  2. select goods_price,goods_name from tdb_goods where goods_price =all(select goods_price from tdb_goods where cate_id=1);

1.2 使用【NOT】IN的子查询

 …… 【NOT】IN (subquery)

 =ANY与IN等价;

!=ALL与NOTIN等价

1.3 insert ……select

使用的子查询:

表中可能有很多重复的信息,比如多条记录中的品牌、类型是一样的,因为记录可能无穷多,并且汉字占的空间多。因此数据表庞大查询速度很慢。因此需要做一张数据表存储品牌或者分类,进行关联和原数据表的瘦身。

第一步:

创建品牌表:

  1. create table brands(brand_id smallint unsigned key auto_increment,bname varchar(40) not null);

创建类型表:

  1. create table goods_cates(cate_id smallint unsigned key auto_increment,cate_name varchar(40) not null);

第二步:

将tdb_goods中的goods_brand 和goods_cate 分别插入到对应的数据表:

  1. insert goods_cate(cate_name) select goods_cate from tdb_goods group by goods_cate;
  2. insert brands(bname) select goods_cate from tdb_goods group by goods_cate;

 

第三步:多表更新--与原tdb_goods 创建连接更新--参照分类表、品牌表更新原表,用cate_id 和brand_id 代替相应的中文

形式:UPDATE table_reference SET col1={expr|default},……,[WHERE ……]

  1. update tdb_goods inner join brands on goods_brand=brand_name set goods_brand=brand_id;
  2. update tdb_goods inner join tbd_cates on goods_cate=cate_name set goods_cate=cate_id;
  3. update tdb_goods inner join brands on goods_brand=brand_name set goods_brand=brand_id inner join tbd_cates on goods_cate=cate_name set goods_cate=cate_id;## 试下对不对,明天

table_reference 表的参照关系,由于是多表,就是多表之间的连接。

table_reference可以是table1 [[AS] 别名1]或者是table1_subquery [[AS] 子查询的别名]

连接的结构:

table_reference1 连接类型   table_reference2 ON  连接条件

连接类型:

内连接---INNER JOIN -连接两张表中都有的,交集
外链接--左/右外连接 LEFT/RIGHT [OUTER] JOIN 左边表的全部+右边表符合条件的/右边表的全部+左边表符合条件的

简洁的写法:

  创建和写入一步更新(第一步和第二步):CREATE TABLE table_name(字段 属性) SELSECT col FROM table_name expr;

  1. create table tdb_cates (cate_id smallint unsigned key auto_increment,cate_name varchar(40) not null) select cate_name from tdb_goods group by cate_name;##因为id 是自动编号的,因此可以不用管,只选择cate_name字段的值加插入到tdb_cates的cate_name字段(选择出的字段名和要要插入的表的字段名最好一样,不然就另起一列添加了,如下图1,或者创建的时候只定义id字段/如下图2:)
  2. create table tdb2_brands(brand_id smallint unsigned key auto_increment) select brand_name from tdb_brands group by brand_name;
  1. create table tdb_brands(brand_id smallint unsigned key auto_increment,bname varchar(40) not null) select brand_name from tdb_goods group by brand_name;(列名不一样)

列名不一样

创建时省略列名,直接用插入的列名

第三步连接:当然因为要连接的两张表的品牌名称字段是一样的,因此要加表名做前缀或者给表其别名,如果字段是唯一的不会引起混淆则不需要:

  1. update tdb_goods as tg inner join tdb_cates as tc on tg.cate_name=tc.cate_name set cate_name=cate_id;

品牌表的一步更新:

  1. create table tdb_brands(brand_id smallint unsigned key auto_increment,bname varchar(40) not null) select brand_name from tdb_goods group by brand_name; ##创建品牌表并且插入查询到的品牌名称
  2. update tdb_goods as tg inner join tdb_brands as tb on tg.brand_name=tb.brand_name set tg.brand_name=tb.brand_id;##连接原表和品牌表,并更新原表

接下来。虽然品牌和类型字段的中文表示都由其对应的参考表的编号代替了,但是tdb_goods的brand_name和cate_name的字段属性在最初定义的时候依旧还是字符类型,因此要修改为相应的int类型,:

  1. alter table tdb_goods change goods_cate cate_id smallint unsigned not nill,change goods_brand brand_id smallint unsigned not null;##原字段名1 新字段名1及其属性,……
  1. select goods_id,goods_name,goods_price,brand_name,cate_name from tdb_goods inner join goods_cates as gc on gc.cate_id=tdb_goods.cate_id inner join tdb_brands as tb on tb.brand_id=tdb_goods.brand_id\G;
  1. alter table tdb_goods change goods_cate cate_id smallint unsigned not null, change goods_brand brand_id smallint unsigned nut null;

自身连接:

  1.无限极分类---:同一个数据表对其自身进行连接,必须起别名。

很多数据库底下有很多很小的分类,例如生活电器下面有厨房电器和家具电器之类的,而厨房电器下面又分为电饭煲、微波炉之类的。底下可能又会具体分为很多类

如要查找表中各个名字的父类是谁。想象 左右一张相同的表 右边为子表 左边为父表

父表的第三列就没有用,

 a.若我想查看子表中的条目对应的父表条目是谁,则子表中的条目应该都出现:

  1. select s.type_id,s.type_name,p.type_name from tdb_goods_types as p right join tdb_goods_types as s on p.type_id=s.parent_id;##子表s中的条目要全部出现,因此连接要选择join右边s的方位,即右连接;

b.若想查看父类条目下都有哪些子类,则父类的条目要全部出现,:

  1. select p.type_id,p.type_name,s.type_name from tdb_goods_types as p left join tdb_goods_types as s on s.parent_id=p.type_id;

b.1 若想查看父类下的子类的数目而不是子类的具体,则:

  1. select p.type_id,p.tyoe_name,count(s.type_name) child_count from tdb_goods_types as p left join tdb_goods_types as s on s.parent_id=p.type_name group by p.type_id order by p.type_id;##先做了一个左连接,然后对查询结果按照父类的type_name做了分组,分组的顺序按照p.type_id的顺序,并且计算了父类下面子类的数目,(注意其表达方式)

 2.多表删除:删除表中重复的记录,保留ID较小的记录。

  首先,查找重复记录:

  1. select goods_id,goods_name from tdb_goods group by goods_id;##将所有的记录查看

group by A 可以理解为列出A字段中无重复的内容;

可以看到,原表表中一共24条记录,但是查询出来的只有22个,因为有重复的商品名称(22、23).

查询父类下对应子类的总数:

  1. select goods_name,count(goods_id) name_count from tdb_goods group by goods_name order by goods_id;

单独挑出有两条或者两条以上的记录:

  1. select goods_name,count(goods_id) name_count,goods_id from tdb_goods group by goods_name having name_count >=2 order by goods_id;

多表删除:DELETE tbl_name1,[tbl2_name,~~~] FROM tbl_references [WHERE where_condition]

下面也是用单表模拟多表删除重复的操作,运用了自身连接--

上表即为我们接下来要删除/保留的表了。

首先,从哪张表中删除(引用别名t1),然后就连接上图中的表--用子查询获取,(引用别名t2),连接的条件是名称相同,但是相同的不是都删除,而是删除id号比较大的记录(上表中的id 号都是相同名称下的小id)。

  1. delete t1 from tdb_goods as t1 left join(select goods_id,goods_name from tdb_goods group by goods_name having count(goods_id) >=2) as t2 on t1.goods_name=t2.goods_name where t1.goods_id >t2.goods_id;
  2. ##小括号中的子查询语句即为我们上一步得出的有两条重复以上的记录。黑色加粗字体是多表删除的框架,删除的是id号较大的重复记录;红色字体的部分--左连接整体是作为参照表,连接的条件是两张表的name相同;绿色底色的部分--子查询整体是连接的右表,子查询返回的结果有两条重复以上的记录,

可以看到,删除后只有22条记录,即22和23号的重复记录都被删除了!

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

时间: 2024-12-17 19:11:30

MySQL--5--subquery和连接的相关文章

mysql忘记root密码连接本地库

今天想做个小项目,决定用mysql数据库,但是好久没用mysql了,也忘掉了当时建库时root密码是什么了,找到了一篇文章,在这里记录下. Windows下mysql忘记root密码的解决方法: Mysql版本:5.1.55-community MySQL Community Server (GPL) 1. 首先检查mysql服务是否启动,若已启动则先将其停止服务,可在开始菜单的运行,使用命令: net stop mysql 或者在windows任务管理器中结束mysqld.exe进程,或者在控

mysql如何开启远程连接(默认未开启,即使密码正确,仍然无法访问)

mysql如何开启远程连接 | 浏览:1846 | 更新:2015-03-11 20:19 1 2 3 4 5 6 分步阅读 百度经验:jingyan.baidu.com 大家在公司工作中,经常会遇到mysql数据库存储于某个人的电脑上,大家要想连接mysql服务,装有mysql服务的电脑就必须开启远程连接. 百度经验:jingyan.baidu.com 工具/原料 mysql windows 百度经验:jingyan.baidu.com 方法/步骤 1 使用“Ctrl + R”组合键快速打开c

centos里mysql无法用localhost连接的解决方法

遇到这个问题可能是由于我未安装在默认路径导致的 解决方法: 由于mysql 默认的mysql.sock 是在/var/lib/mysql/mysql.sock,但linux系统总是去/tmp/mysql.sock查找,所以会报错 [[email protected] ~]# find / -name mysql.sock/var/lib/mysql/mysql.sock 1.直接指定mysql通道 [[email protected] ~]# mysql --socket=/var/lib/my

mysql连接的空闲时间超过8小时后 MySQL自动断开该连接解决方案 详细出处参考:http://www.jb51.net/article/32284.htm

MySQL 的默认设置下,当一个连接的空闲时间超过8小时后,MySQL 就会断开该连接,而 c3p0 连接池则以为该被断开的连接依然有效.在这种情况下,如果客户端代码向 c3p0 连接池请求连接的话,连接池就会把已经失效的连接返回给客户端,客户端在使用该失效连接的时候即抛出异常 解决这个问题的办法有三种: 1. 增加 MySQL 的 wait_timeout 属性的值. 修改 /etc/mysql/my.cnf文件,在 [mysqld] 节中设置: # Set a connection to w

Python/MySQL表操作以及连接

Python/MySQL表操作以及连接 mysql表操作: 主键:一个表只能有一个主键.主键可以由多列组成. mysql> create table yuan(id int auto_increment,yuangongname int,bumen_id int, primary key(id,yuangongname))engine=innodb default charset=utf8; Query OK, 0 rows affected (0.43 sec) 外键 :可以进行联合外键,操作

利用openssl实现私有CA以及mysql服务器的ssl连接的配置

利用openssl实现私有CA以及mysql服务器的ssl连接的配置 一.CA简介 CA 也拥有一个证书(内含公钥和私钥).网上的公众用户通过验证 CA 的签字从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书. 如果用户想得到一份属于自己的证书,他应先向 CA 提出申请.在 CA 判明申请者的身份后,便为他分配一个公钥,并且 CA 将该公钥与申请者的身份信息绑在一起,并为之签字后,便形成证书发给申请者. 如果一个用户想鉴别另一个证书的真伪,他就用 CA 的公钥对

解决mysql、vsftp远程连接速度慢的问题

以 centOS 6.3(其他操作系统类似,同样适用)说明: 当我们的服务都配置正常的情况下,有时会出现连接速度慢而导致连接失败的问题 问题分析:这些情况一般都是DNS解析惹的祸 mysql连接速度慢解决: 修改my.cnf ,在[mysqld]中添加下面一句 skip-name-resolve 重启mysql(#service mysql restart或者/etc/init.d/mysql restart),问题解决. 注意:这样的话,程序中是不能用localhost的,只能使用127.0.

MySQL 可以用localhost 连接,但不能用IP连接的问题

ubuntu下安装了mysql,通过localhost, 127.0.0.1都可以连接上,但是使用IP时就连接不上 可能原因: 1.查看/etc/mysql/my.cnf cat /etc/mysql/my.cnf | grep 127 可以看到 bind-address = 127.0.0.1 mysql默认只监听127.0.0.1,通过分配到的IP连接就失败了 注释掉该行 # bind-address = 127.0.0.1 并关闭mysql service mysql stop 再启动 s

mysql数据库可以远程连接或者说用IP地址可以访问

mysql数据库可以远程连接或者说用IP地址可以访问 一般情况不建议直接修改root的权限, 先看下,自己mysql数据库的用户级权限 mysql -u root -p----->用root登陆   use mysql------->切换到mysql数据库(这个mysql是数据库的名字,---->安装的时候系统自带的吧) 可以看到我的是这样的,至于为什么有2个root我还不太清楚,我记得mysql安装的时候有个选项是---(是否可以远程访问)可能第一个root是这个作用吧,而我们常用的是

安装好mysql后允许远程连接

1. 改表法 我就是使用这种方法!! (可能是你的帐号不允许从远程登陆,只能在localhost.这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 "user" 表里的 "host" 项,从"localhost"改称"%") c:/mysql/mysql server 5.1>mysql -u root -p 输入相应密码 mysql>use mys