[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;
解析: 首先以第一个表为核心做左连接, 然后将第二个表中剩余部分也append下来, 相当于两个集合的并集;
注:mysql不支持FULL JOIN, 可以用left join 和 right join的并集 或者直接用笛卡儿积(cross join)

 

复制代码
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.

 

 

5)笛卡尔积(cross join)
在数学中,笛卡尔乘积是指两个集合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语句中用的列明,
  
例2: UNION ALL的用法
复制代码
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

 

posted @ 2021-03-10 17:53  水鬼子  阅读(206)  评论(0编辑  收藏  举报