[sql]高级语法-SELECT专题
目录:
1. 用到的表
2. 原生用法,针对select语句提供的一些功能
3. 复合使用多种select语法
一. 表情况
表1: Persons表
mysql> select lastname, firstname, address, age from Persons; +----------+-----------+---------+------+ | lastname | firstname | address | age | +----------+-----------+---------+------+ | wu | xiaohong | L | 40 | | wu | xiaohong1 | H | NULL | | zhao | gao | H | NULL | | sun | bin | H | NULL | | li | bai | H | NULL | +----------+-----------+---------+------+ 5 rows in set
表2: Family表,家族表
mysql> select * from Family; +----------+---------+---------+ | lastname | origin | history | +----------+---------+---------+ | qian | xian | 102 | | sun | NULL | NULL | | wu | dongbei | 200.5 | | zhao | xian | 10.3 | +----------+---------+---------+ 4 rows in set
二. 原生用法
1. 连接(JOIN)
当需要从两个表中获取数据的时候,据需要使用join。当然,既然需要从连个表中获取,那么这两个表一般都是有关联的,比如存放一个人的两部分信息等;通常,联系连个表的字段均为两个表的主键(primary key);而所谓join, 翻译过来就是交叉捆绑的意思, 具体若何捆绑又分: 内连接(inner join), 左连接(left join), 右连接(right join), 以及全连接(full join)
接下里我们就一个个分析来.
0) 使用一般的select语句实现获取某个人的基本信息以及对应的家族信息
mysql>select p.firstname, p.lastname, f.history from Persons as p, Family as f where p.lastname=f.lastname; +-----------+----------+---------+ | firstname | lastname | history | +-----------+----------+---------+ | bin | sun | NULL | | xiaohong | wu | 200.5 | | xiaohong1 | wu | 200.5 | | gao | zhao | 10.3 | +-----------+----------+---------+ 4 rows in set
1)内连接(inner join)/连接(join)
mysql>select p.firstname, p.lastname, f.history from Persons as p INNER JOIN Family as f ON p.lastName = f.lastName ORDER BY f.history; +-----------+----------+---------+ | firstname | lastname | history | +-----------+----------+---------+ | bin | sun | NULL | | gao | zhao | 10.3 | | xiaohong | wu | 200.5 | | xiaohong1 | wu | 200.5 | +-----------+----------+---------+ 4 rows in set mysql> select p.firstname, p.lastname, f.history from Persons as p CROSS JOIN Family as f ON p.lastName = f.lastName ORDER BY f.history; mysql> select p.firstname, p.lastname, f.history from Persons as p JOIN Family as f ON p.lastName = f.lastName ORDER BY f.history;
解析:Persons INNER JOIN Family ON p.lastName = f.lastName 完全等同于
select Persons, Family where p.lastName = f.lastName
其核心思想是: 找到 两个集合中重叠的部分,
所以对于李白家,由于没有家族信息; 对于钱家族,由于已经没有后代成员信息了,
因此结果集中因为找不到匹配(.lastname = .lastname)导致不能将所有成员罗列出来
另外, cross join,返回被连接的两个表的笛卡尔积,返回结果的行数等于两个表行数的乘积, 在有条件(on)的情况下等同inner join,
join(缺省) 就是 inner join, 在没有条件的情况下由于内部实现的算法不同, 则效率要高于cross join;
2)左连接(left join)/左外连接(left Outer join)
mysql> select p.firstname, p.lastname, f.history from Persons as p LEFT JOIN Family as f ON p.lastName = f.lastName; +-----------+----------+---------+ | firstname | lastname | history | +-----------+----------+---------+ | xiaohong | wu | 200.5 | | xiaohong1 | wu | 200.5 | | gao | zhao | 10.3 | | bin | sun | NULL | | bai | li | NULL | +-----------+----------+---------+ 5 rows in set
解析: 左连接顾明思议, 则是以左侧(第一个)表作为核心,向右侧(第二个)表发起连接
核心思想: 取两个集合中,第一个集合 + 二者重叠部分;
所以对于李白家已经可以占有一席之地了,但是钱家仍然不再列
3)右连接(right join)/右外连接(right Outer join)
mysql> select p.firstname, p.lastname, f.history from Persons as p RIGHT JOIN Family as f ON p.lastName = f.lastName;
核心思想等同左连接,只不过核心表为右侧(第二个)...
注:此时取值最好要取右表(如select p.firstname, f.lastname,...),否则有可能会出现全空条目
4)全连接(full join)/(full Outer join)
mysql> select p.firstname, p.lastname, f.history from Persons as p FULL JOIN Family as f ON p.lastName = f.lastName;
mysql>select p.firstname, p.lastname, f.history from Persons as p RIGHT JOIN Family as f ON p.lastName = f.lastName union select p.firstname, f.lastname, f.history from Persons as p RIGHT JOIN Family as f ON p.lastName = f.lastName; +-----------+----------+---------+ | firstname | lastname | history | +-----------+----------+---------+ | xiaohong | wu | 200.5 | | xiaohong1 | wu | 200.5 | | gao | zhao | 10.3 | | bin | sun | NULL | | NULL | NULL | 102 | | NULL | qian | 102 | +-----------+----------+---------+ 6 rows in set
解析:需要注意的是,在做分别的连接时要以取对应的纽带,什么意思?
就是说我们在做连接的时候,使用的是lastname作为纽带,那么在做连接的时候,左连接使用左集合.lastname, 右连接使用右集合.lastname.
在数学中,笛卡尔乘积是指两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y, 即第一个对象是X的成员, 第二个对象是Y的成员的所有可能有序对。
实际上,其等价于select * from A, B;
小结:
所谓连接,实际就是做排列组合,整个的核心原理可以如下图所示
2. 结果限定(limit)
3.联合(union, union all)
核心思想: 用于合并两个或多个 SELECT 语句的结果集。
特点:
1)要求UNION内部的SELECT语句必须拥有相同数量的列。列也必须拥有相似的数据类型(待确定)。同时,每条SELECT语句中的列的顺序必须相同。
2)默认地,UNION 操作符选取不同的值。如果允许重复的值,则使用 UNION ALL。
3)UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
例1: UNION的用法
mysql> select p.lastname, p.firstname, p.address from Persons as p union select f.lastname, f.origin, f.history from Family as f; +----------+-----------+---------+ | lastname | firstname | address | +----------+-----------+---------+ | wu | xiaohong | L | | wu | xiaohong1 | H | | zhao | gao | H | | sun | bin | H | | li | bai | H | | qian | xian | 102 | | sun | NULL | NULL | | wu | dongbei | 200 | | zhao | xian | 10.3 | +----------+-----------+---------+ 9 rows in set
mysql> select p.lastname, p.memebers from Persons as p union select f.lastname, f.memebers from Family as f; +----------+----------+ | lastname | memebers | +----------+----------+ | wu | 4 | | wu | NULL | | zhao | NULL | | sun | NULL | | li | NULL | | qian | 2 | | zhao | 1 | +----------+----------+ 7 rows in set
解析: 首先select的结果集的数量必须相同,即都是3个或者2个;
然后, 另外所谓"相似"类型,则一般指字段必须是有限长度的,比如date,text和float也算, 不同限制的int也算(哪些不算呢?)
最后,合并后的结果集使用的是第一个select语句中用的列明,
mysql> select p.lastname, p.memebers from Persons as p union all select f.lastname, f.memebers from Family as f; +----------+----------+ | lastname | memebers | +----------+----------+ | wu | 4 | | wu | NULL | | zhao | NULL | | sun | NULL | | li | NULL | | qian | 2 | | sun | NULL | | wu | 4 | | zhao | 1 | +----------+----------+ 9 rows in set
解析: 其中wu|4 和sun|NULL 的重复条目也都保留了
4.结果聚合(Group BY)
从所给的列明返回分组的查询结果,可用于查询具有相同值的列
例1: 基础用法
mysql> select lastname, firstname, count(*) from Persons group by lastname; +----------+-----------+----------+ | lastname | firstname | count(*) | +----------+-----------+----------+ | li | bai | 1 | | sun | bin | 1 | | wu | xiaohong | 2 | | zhao | gao | 1 | +----------+-----------+----------+ 4 rows in set
解析: 根据lastename进行分组,于是同姓wu分到一组,且这组里面有2个元素
例2: 高级用法
<<待添加>>
5. 唯一性(distinct)
二. 复合用法
1. 将查询结果作为查询条件
SELECT * FROM udpbind WHERE proxyuuid=(SELECT `uuid` FROM udpbind WHERE
proxyuuid='515c524db84e4ce5a57b20e00110161d' AND pctype=1 AND port=5060 LIMIT 1); 解析:从表中取得符合条件的表项的uuid字段作为新的查询条件:最终获取proxyuuid为上次取得的uuid的所有表项 tip1:因为把查询结果作为条件了,所以别忘了用limit保证只获得一个 tip2:因为uuid和proxyuuid都是字符串,所以作为条件的uuid一定记得用``,否则会作为非字符串,于是匹配不到 tip3:之前还想是不是要使用DISTINCT,于是查了一下他的函数, 的意思表示:如果select的列(可多个)组合有重复的,则取一个, 如果: select a,b from.... 结果是:1 1 1 2 1 1 如果:select distinct a, b from xxx 结果是: 1 1 1 2
2. 待添加1
3. 待添加2