Mysql比知必会系列教程(七) --------mysql多表高级检索信息

Mysql 多表高级检索信息

联结join:

是将一个数据表中的信息与另一个数据表结合起来才能得到查询结果。

根据某个数据表中的每一行数据与另一个数据表里的每一行组合来连接操作(笛卡尔积),

select t1.*,t2. * from t1,t2 where t1.i1=t2.i2;

select t1.*, t2. * from t1 join t1.i1=t2.i2;

“,”(逗号)关联的操作符的效果与 inner join 相似。逗号操作符的优先级和其他联结类型不一致,有时会导致语法错误。避免使用逗号操作符。

select student_id,date,score,category 
from grade_event inner join score
on grade_event.event_id=score.event_id
where date='2019-09-23'

这个inner join 查询是先根据指定日期查询出grade_event行,再利用行里的event_id把score数据表里拥有同一event_id的考试分数查询出来。把学生的学号,分数,日期,考试事件的类型。from 子句从哪些数据表中匹配信息。on子句给出匹配的条件。

select student_id,date,score,category 
from grade_event inner join score inner jon student
on grade_event.event_id=score.event_id
and score.student_id=student.student_id
where date='2019-09-23'

这个inner join 查询是先根据指定日期查询出grade_event行,再利用行里的event_id把score数据表里拥有同一event_id的考试分数查询出来。把学生的学号,分数,日期,考试事件的类型。再通过student数据表将分数与学生进行关联起来。from 子句从哪些数据表中匹配信息。on子句给出匹配的条件。

left join

left join的工作情况是:给出用来匹配两个数据表里的数据行的数据列,当来自左数据列的某个数据行与右侧数据表的某个数据行匹配时,那两个数据行的内容就会被选取一个输出行;如果来自左数据表的某个数据行在右侧不能找到匹配,他也会被选取一个输出数据行,此时与他关联的是一个来自右侧数据表的“假”数据行,这个“假”数据行的所有数据列都包含null值。

left join 是将连接操作的第一张数据表(左表)的数据行生成一个输出行。来自左侧数据表中的每一个数据行在结果集里都有一个对应的数据行,不管他在右侧的数据表里有没有匹配。在结果集里,在右侧数据表里没有匹配的结果数据行有这样一个特征:来自右数据表的所有数据列都是Null值,这个特征可以让知道右数据表里缺少了哪些数据行。

如:得到每一个学生的缺勤次数》

select student.student_id,student name 
count (absence.date) as absence
from student left join absence
on student.student_id = absence.student_id
group by student.student_id

例:

数据表t1:

i1 c1
1 a
2 b
3 c

数据表t2:

i2 c2
2 c
3 b
4 a

select t1.*,t2. * from t1 inner join t2 on t1.i1 = t2.i2;

i1 c1 i2 c2
2 b 2 c
3 c 3 b

左连接操作会为t1数据表里每一行生成一个输出数据行,不管他在t2里有没有匹配。

select t1.* t2. * from t1 left join t2 on t1.i1=t2.i2;

i1 c1 i2 c2
1 a NULL NULL
2 b 2 c
3 c 3 b

在使用左连接时需要注意一个问题:如果右数据表里的数据列没有被全部定义成Not NUll,结果集里的数据行就很可能不能反映真实情况,比如右数据表里某个数据列允许取值为NULL并被收录在结果集里,用这个数据列的null值来判断“在右数据表里没有匹配”就可能出问题。

select t1.* ,t2.* from t1 left join t2 on t1.i1=t2.i2;

select t1.* ,t2.* from t2 right join t1 on t1.i1=t2.i2;

1.on条件在生成临时表时使用的条件,他不管on中的条件是否为真,都会返回左边表的记录2.where 条件是在临时表生成后,再对临时表进行过滤。这时已经没有left join 的含义,条件不为真的就全部过滤掉3.left join 适合解决“哪些值是缺失的”这个问题

在left join时在结果集里在右侧数据表里没有匹配的结果数据行时:来自右数据表的所有数据列都是Null值,这个特征可以让知道右数据表里缺少了哪些数据行。如果left join 后过滤了右表的为null的情况下,就是和inner join 结果一致了

用union 语句进行多表检索

如果想把多个查询的结果合并在一起并且创建一个结果集,可以使用union 语句来做这件事。

select i from t1 union select i from t2 union select from t3;

union语句有以下特性:

  • 数据列的名字和数据类型

    unoin 结果集里的数据列名字来自第一个select 语句里的数据列的名字,union中的第二个和再后面的select语句必需选取个数相同的数据列,但各有关数据列不必有同样的名字或数据类型(一般说,同一条union语句里的各有数据列会是相同的数据类型,但不是一项要求,如果他们一样,Mysql会进行必要的类型转换。)数据列是根据位置而不是名字进行匹配的。

    select i, c from t1 union select i,d from t3;

    select i, c from t1 union select d,i from t3;

    i c i c
    1 red 1 red
    100 1904-01-01 1904-01-01 100
  • 重复行的处理。

    在默认情况下,union将从结果集里剔除重复的数据行。union distinct是union同义词,他们都是死只保留不重复的数据行.去除重复行

    如果你想保留数据的重复行,需要把每个union都改为union all.

    如果把union (或union distinct)和union all 混杂在一起使用,每个union (或union distinct )操作将优先于他左边的 任何 union all 操作

  • order by 和limit 处理

    如果想把将union 结果作为一个整体进行排序,需要用括号把每一个select 语句包括起来并在最后一个 select 语句的后面加上一个order by 子句。注意,因为uoin 的结果集数据列的名字来自第一个select语句,所以你在order by 子句里必须引用那些名字,而不是最后一个select语句的数据列名字。(select i ,c from t1) union (select i,d from t3) order by c; 如果某个数据列有别名,则位于union 语句末尾的order by 子句必须引用这个别名。此外order by 不能引用数据表的名字。(select t.i ,t.c from t1 t) union (select i,d from t3) order by t.c;

    若果想限制union的行数则可以使用:

    (select i ,c from t1) union (select i,d from t3) limit 3;

子查询

Mysql支持子查询。子查询就是嵌套select语句进行查询》比如从grada_event 数据表里找出对应于考试(‘T’)的event_id再用他们去选取考试成绩;

select * from score where event_id in(select event_id from grade_event where category=‘T’)

子查询可以返回以下不同类型的信息。

  • 标量子查询将返回一个值。
  • 数据列子查询将返回一个由一个或多个值构成的数据列
  • 数据行子查询将返回一个由一个或多个值构成的数据行
  • 数据表子查询将返回一个或多个数据行构成的数据表,数据行可以由一个或多个数据列构成。

子查询的结果可以用以下的不同的方法进行测试。

  • 标量子查询的结果可以用诸如“=”或“<”之类的相对比较操作符进行求值。
  • 可以用in和not in操作符把某个定值是否包含在子查询的结果集中。
  • 可以用all any和some操作符吧某给定值与子查询的结果集进行比较。
  • 可以用exists和not exists操作符来测试子查询的结果集是否为null.
子查询与关系比较符

=,<>,>,>=,<,<=操作符用来进行相对值比较。他们可以和标量子查询配合使用:用子查询返回值来构造一个检索条件,再有主查询根据该条件进一步检索。

select * from score where event_id =(select event_id from grade_event where date=‘2008-09-23’ and category=‘Q’)

子查询的前面有一个值和一个相似比较操作符,子查询的这种用法要求他只返回一个值。有时候为了确保子查询返回一个值有必要用limit 1对子查询的结果加以限制。

select * from score where event_id = 5 and score >(select AVG(score) from score where event_id = 5);

如果子查询返回的是一个数据行,可以用一个数据行构造器把一组值(一条临时创建的记录)与子查询的结果进行比较。下面是将数据返回一个数据行,他可以告诉我们哪几位总统和john 出生在同一个城市和州。

select last_name,first_name,city,state from president where (city,state) = (select city, stage from president) where last_name =‘Admis’ and first_name =‘john’;

in 和 not in 子查询

如果子查询返回数据行多个,可以用in 和 not in 操作符来构造主查询的检索条件。in和not in 操作符的用途是测试一个给定的比较值有没有出现一个特定的集合里。只要主查询里的数据行与子查询返回的任何一个数据行匹配,in操作符比较结果就是 true,如果主查询里的行与子查询所返回的所有数据行都不匹配,not in 操作符的比较结果为true,

select * from student where student_id in (select student_id from absence)

select * from student where student_id not in (select student_id from absence)

in和not in 还可以将用在返回多个数据列的子查询里。

select last_name,firste_name,city, state from pressident where (city,site) in (select city ,state from president where last_name=‘ADDD’);

all any 和some

其实 in 和 not in操作符和 = any和 <> all的同义词

all 和any操作符的常见用法是结合一个相对比较操作符对一个数据列子查询的结果进行测试,如果比较值小于或等于子查询所返回的每一个值<= All将为true,只要比较值小于或等于子查询所返回的任何一个值,<= any 将是true.

select last_name,first_name birth from student where birth <=all (select birth from president);

当 all ,any 或者some操作符与“=” 比较符配合使用时,子查询可以是一个数据表子查询。此时使用一个数据行构造器来提供与子查询所返回的数据行进行比较的比较值。

select last_name,firste_name,city, state from pressident where (city,site) any (select city ,state from president where last_name=‘ADDD’);

select last_name,firste_name,city, state from pressident where (city,site) in (select city ,state from president where last_name=‘ADDD’);

以上两条sql语句,效果一样。

exists和 not exists子查询

exists和not exists操作符只测试 某个子查询是否返回了数据行,如果是,exists将是true,not exists是false.

select exists (select * from absence)

select not exists(select * from absence)

在使用exists和not exists操作符时子查询通常使用“*”作为数据列清单,这两个操作符是根据子查询是否返回了数据行判断真假,不关心起内容是什么、

与主查询相关的子查询
  • 与主查询无关的子查询不引用主查询的任何值。与主查询无关的子查询可以脱离主查询作为一条独立的查询命令去执行。比如说:select j from t2 where j in (select i from t1)
  • 与主查询相关的子查询需要引用子查询的值,所以必须依赖主查询。因为这种关系可与主查询相关的子查询不能脱离主查询作为独立的查询。比如select j from t2 where (select i from t1 where i =j )

与主查询相关的子查询通常用 exists 和not exists子查询里。这类子查询主要用来在某个数据表里查找另一个数据表里有匹配数据行或没有匹配数据行的数据行。与主查询相关的子查询的工作情况是:把主查询传递到子查询,看到他们是否满足在子查询里面给出的条件。如果数据列中名字可能引起歧义的话建议使用数据库名字限定列

select student_id ,name from student where exists (select * from absence where absence.student_id=student.student_id);

from子句中的子查询

子查询可以用在from子句中,这种情况子查询在行为结果上就像一个数据表,from 子句里的子查询可以参加关联操作,他的值可以在where 子句中被测试,

select * from (select 1,2) as t1 inner join (select 3,4) as t2;

子查询如何改为联结查询

有相当一部分的子查询可以改为连接查询。有时候连接查询要比子查询的效率更高。所以子查询改为连接查询是个更好的注意。

如何改写用来选取匹配值的子查询

select * from score where event_id in (select event_id from grade_event where category=‘T’)

这条语句可以修改为一个联结查询:

select score.* from score inner join grade_event on score.event_id = grade_event.event_id where grade_event.category = ‘T’

这类的子查询都可以更改为联结查询:

select * from table1 where colum1 in (select col2 from table2 where col2= value)

这类的查询可以改为联结查询:

select table1.* from table1 inner join table2 on table1.column1=table2.column2a where table2.column2b=value;

这时改为联结查询时会导致出现重复的数据行,如果防止重复在编写是使用 select distinct 代替select

如果改写用来选取非匹配(缺失)值的子查询

在子查询语句中的另一个常见的用法是检索在一个数据表里有,在另一个数据表没有的值。与“哪些值没有出现”有关问题通常都可以用来left join来解决。

一般以下的子查询都可以改为连接查询:

select * from table1 where column1 not in (select column2 from table2);

可以改为以下联结查询:

select table1.* from table1 left table2 on table2.column1=table2.column2 where table2.column2 is null;

与 left join 相比,子查询具备比较直观和容易理解的优点。绝大多数人都可以毫无困难的理解为“没被包含在…里面”的含义

你可能感兴趣的:(数据库,mysql,数据库,sql)