数据库操作核心-查询语句

多表查询

  多表查询,又称表联合查询,即一条sql语句涉及到的表有多张,数据通过特定的连接进行联合显示.

笛卡尔积
  在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y.
  假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
  在数据库中,如果直接查询俩张表,那么其查询结果就会产生笛卡尔积
例如:
  select *
  from s_emp,s_dept;

连接查询
  为了在多表查询中避免笛卡尔积的产生,我们可以使用连接查询来解决这个问题.
  连接查询分为:
    1.等值连接
    2.不等值连接
    3.外连接
      左外连接
      右外连接
      全外连接
    4.自连接

1.等值连接
利用一张表中某列的值和另一张表中某列的值相等的关系,把俩张表连接起来。
例如:查询员工的名字、部门编号、部门名字

select last_name,dept_id,name
from s_emp,s_dept
where s_emp.dept_id=s_dept.id;

为了表述的更加清楚,可以给每张表起别名

select se.last_name,se.dept_id,sd.id,sd.name 
from s_emp se,s_dept sd
where se.dept_id=sd.id;

2.不等值连接
假设数据库中还有一张工资等级表:salgrade
  工资等级表salgrade:
  gradeName列表示等级名称
  losal 列表示这个级别的最低工资数
  hisal 列表示这个级别的最高工资数

表中的数据类似于下面内容:
  id  salgrade  losal  hisal
  1  初级程序员 2000  4000
  2  中级程序员 4000  6000

create table salgrade(
id         number primary key,
gradeName  varchar2(200) not null,
losal     number,
hisal        number
);        

例如:
查询出员工的名字、职位、工资、工资等级名称

SELECT e.last_name, e.title, e.salary, s.gradeName
FROM s_emp e, salgrade s
WHERE e.salary BETWEEN s.losal AND s.hisal

3.外连接

外连接分为:  左外连接  右外连接  全连接

先分别在俩s_emp和s_dept表中插入新的数据
特点:新员工tom不在任何部门,新增部门st下面没有任何员工
  insert into s_emp(id,last_name) values(26,'tom');
  insert into s_dept(id,name) values(60,'st');
  commit;

下面条sql语句可以把上面插入的数据给删除掉
  delete from s_emp where id=26;
  delete from s_dept where id=60;
  commit;

这个时候再使用等值连接的话,查询出来的数据就会少,因为新增的员工tom和部门表中的数据连接不上,
当然新增的部门st也和员工表中的数据连接不上.那么这俩条数据都是在等值连接中查询不出来.

  左外连接
  例如:
  查询所有员工 以及对应的部门的名字,没有部门的员工也要显示出来

  select last_name,dept_id,name 
  from s_emp,s_dept
  where s_emp.dept_id=s_dept.id(+);

  或者 俩者是等价的

  select last_name,dept_id,name 
  from s_emp left outer join s_dept
  on s_emp.dept_id=s_dept.id;

  注意:outer可以省去不写

  查询所有的部门中的员工,没有部门的员工也要显示出来

  select last_name,dept_id,name 
  from S_DEPT right outer join S_EMP
  on s_emp.dept_id=s_dept.id;

  右外连接
  例如:
  查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来

  select last_name,dept_id,name 
  from s_emp,s_dept
  where s_emp.dept_id(+)=s_dept.id;

  select last_name,dept_id,name 
  from s_emp right outer join s_dept
  on s_emp.dept_id=s_dept.id;

  注意:outer可以省去不写

  注:左右连接的操作要找好基准表。

  全连接
  例如:
  查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来,没有部门的员工也要显示出来

  select last_name,dept_id,name 
  from s_emp full outer join s_dept 
  on s_emp.dept_id=s_dept.id;

  注意:outer可以省去不写

  自连接
  一张表,自己和自己连接
  例如:
  查询每个员工的名字以及员工对应的管理者的名字

  select s1.last_name,s2.last_name manager_name
  from s_emp s1,s_emp s2
  where s1.manager_id = s2.id;

4.对查询结果集的操作
如果有俩条sql语句,每一条sql都可以查询出一个结果,这个被称之为结果集。那么我们可以使用下面的关键字对俩个结果集进行操作
union 取俩个结果集的并集
union all 把俩个结果集合在一起显示出来
minus 第一个结果集除去第二个结果集和它相同的部分
intersect 求俩个结果集的交集

注意:前提条件 俩个结果集中查询的列要完全一致

  union 取俩个结果集的并集
例如:

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
union
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

  union all 把俩个结果集合在一起显示出来
例如:

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
union all
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

  minus 第一个结果集除去第二个结果集和它相同的部分
例如:

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
minus
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

对比俩种情况的结果

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id
minus
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+);

  intersect 求俩个结果集的交集

select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id=s_dept.id(+)
intersect
select last_name,dept_id,name 
from s_emp,s_dept
where s_emp.dept_id(+)=s_dept.id;

组函数

group by 在查询表中数据的时候进行分组的关键字
思考:为什么要对数据进行分组
having 分组之后的进行进一步数据筛选的关键字
having和where的功能类似

组函数(分组函数),是指将数据按照某列的值进行分组后,然后使用组函数分别对每个分好的小组中的数据进行处理。所以组函数一般要结合着分组关键字group来使用

组函数:
avg 求平均值
count 计算有多少条数据
max 最大值
min 最小值
sum 求和

stddev 标准差
variance 方差

sql语句的各部分构成
select ....
from ....
where ....
group by ...
having ...
order by ....

注:除了select和from之外其他的都不是必须的。

假如select..from..后面的语句都出现了,那么他们的执行顺序为:
where-->group by分组-->执行组函数-->having筛选->order by

组函数出现的位置:
1.select后面
2.having后面
3.order by后面
4.where后面一定【不能】出现组函数

!!!注意:如果select/having语句后面出现了组函数,那么select/having后面没有被组函数修饰的列,就必须出现在group by 后面

where和having对比:
1.where和having都是做条件筛选的
2.where执行的时间比having要早
3.where后面不能出现组函数
4.having后面可以出现组函数
5.where语句要紧跟from后面
6.having语句要紧跟group by后面

group by和having的关系:
1.group by可以单独存在,后面可以不出现having语句
2.having不能单独存在,有需要的话,必须出现在group by后面

order by语句
1.如果sql语句中需要排序,那么就一定要写在sql语句的最后面
2.order by后也可以出现组函数

使用组函数:不结合group分组使用
注:如果不使用group分组的话,那么默认当前查询到的所有数据是一组
例如:
查询s_emp表中所有员工的平均工资
select avg(salary)
from s_emp;

查询s_emp表中共有多少条数据
select count(*)
from s_emp;

查询s_emp表中所有员工中的最大工资
select max(salary)
from s_emp;

查询s_emp表中所有员工中的最小工资
select min(salary)
from s_emp;

查询s_emp表中所有员工的工资总和
select sum(salary)
from s_emp;

查询s_emp表中所有员工的工资的标准差
select stddev(salary)
from s_emp;

查询s_emp表中所有员工的工资的方差
select variance(salary)
from s_emp;

使用组函数:结合group分组使用
例如:
查询s_emp表中每个部门的平均工资
select dept_id,avg(salary)
from s_emp
group by dept_id;

查询s_emp表中每个部门员工的最高工资
select dept_id,max(salary)
from s_emp
group by dept_id;

查询s_emp表中每个部门员工的工资总和
select dept_id,sum(salary)
from s_emp
group by dept_id;

查询s_emp表中每个部门员工的人数
select dept_id,count(*)
from s_emp
group by dept_id;

//分组之后使用各种组函数
select dept_id,count(*),min(salary),max(salary),sum(salary),avg(salary)
from s_emp
group by dept_id;

使用组函数:结合group分组以及having筛选使用
例如:
查询s_emp表中部门的平均工资大于等于1400的部门
select dept_id,avg(salary)
from s_emp
group by dept_id
having avg(salary)>=1400;

思考:上面的sql语句修改为如下,是否可以?where后不可以使用组函数group function is not allowed here

组函数练习:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
1.查询s_emp表中部门的平均工资大于等于1400的部门,并且显示出这些部门的名字,同时按照部门编号进行排序
select avg(salary),s_dept.name
from s_emp,s_dept
where s_emp.dept_id=s_dept.id
group by dept_id,s_dept.name
having avg(salary)>=1400;
2.查询s_emp表中最大的工资数,并且显示出这个最大工资的员工的名字
方法1:
select max(t1.salary),t2.last_name
from s_emp t1,s_emp t2
group by t2.last_name,t2.salary
having t2.salary=max(t1.salary);
方法2:
select last_name,salary
from s_emp
where salary=(
    select max(salary)
    from s_emp
);
方法3:
select last_name,salary
from s_emp,(
    select max(salary) as max
    from s_emp
) t
where s_emp.salary=t.max;
3.查询s_emp表每个部门的最大工资数,并且显示出这个最大工资的员工名字以及该部门的名字和该部门所属区域,并且使用部门编号进行排序
select max(s1.salary),s1.dept_id,s_dept.name,s2.last_name,s_region.name as regionname
from s_emp s1,s_emp s2,s_dept,s_region
where 
    s1.dept_id=s_dept.id
    and
    s_dept.region_id=s_region.id
group by s1.dept_id,s2.salary,s2.last_name,s_dept.name,s_region.name
having s2.salary=max(s1.salary)
order by s1.dept_id;
注:如果只是针对一个表进行操作,那么分组时的 group by 后的所有字段,都会对分组结果产生影响,进而影响到分组函数的使用,所以如下写是不对的:
select max(s1.salary),dept_id,last_name
from s_emp
group by dept_id,last_name;
order by s1.dept_id;
在这里max(s1.salary),是完全执行完分组后才执行的
但是如果针对两个表进行操作,那么分组时的 group by 后的字段,分组函数是根据有与其字段有关的那个表进行计算,也就是说如上例:max(s1.salary)
先是执行了 group by 后的第一个字段 s1.dept_id,而后计算了max(s1.salary),后再执行剩下的字段s2.salary,s2.last_name,s_dept.name,s_region.name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
嵌套查询:
查询工资比Ngao所在部门平均工资要高的员工信息,同时这个员工所在部门的平均工资也要比Ngao所在部门的平均工资要高显示当前部门的平均工资
select dept_id 
from s_emp 
where last_name='Ngao';

select avg(salary) 
from s_emp
where dept_id=(
    select dept_id 
    from s_emp 
    where last_name='Ngao'
);

select last_name,salary,dept_id
from s_emp
where salary>(
    select avg(salary) 
    from s_emp
    where dept_id=(
        select dept_id 
        from s_emp 
        where last_name='Ngao'
    )
);

select t2.last_name,t2.salary,s_emp.dept_id,avg(s_emp.salary)
from s_emp,(
    select last_name,salary,dept_id
    from s_emp
    where salary>(
    select avg(salary) 
        from s_emp
        where dept_id=(
            select dept_id 
            from s_emp 
            where last_name='Ngao'
        )
    )
) t2
where s_emp.dept_id=t2.dept_id
group by s_emp.dept_id,t2.last_name,t2.salary
having s_emp.dept_id in(
    select distinct dept_id
    from s_emp
    where salary>(
        select avg(salary) 
        from s_emp
        where dept_id=(
            select dept_id 
            from s_emp 
            where last_name='Ngao'
        )
    )
)    
and 
avg(s_emp.salary)>(
    select avg(salary) 
    from s_emp
    where dept_id=(
        select dept_id 
        from s_emp 
        where last_name='Ngao'
    )
);

猜你喜欢

转载自www.cnblogs.com/Magic-Li/p/12705888.html