11月26日——培训第6天

今天是星期天啊……早上比昨天要暖和一些,而且由于车很顺的缘故,我们几个是第一个到的。而且来的时候这里还没有开门。刚才稍微整理了一下C盘,删除了
不少没用的垃圾,现在好多了……

由于今天是周日,网速很快,刚才更新了自己的博客,把前几天的培训日记
都传了上去……
------------------------------------------
上午课程开始:

avg函数用法:得到公司所有员工的平均工资:
select avg(salary) from employees;

count函数用法:得到公司所有员工的数量:
select count(salary) from empoyees;  返回107
select count(department_id) from empoyees;统计给定字段不为空的值的数量
select count(employee_id) from empoyees;应该这么写符合题意……

select count(*) from empoyees; 统计所有不为空的列,所有字段都为空的列
                               才不被统计进去。

max、min函数用法:
select max(hire_date) from employees;进入公司最晚的人;
select max(first_name) from employees;比较first_name的第一个字母
                                      并且显示出最大的first_name

stddev:方差(需要开根号)
sum:求和
select sum(salary) from empoyees; 所有员工的工资总和。

select avg(salary) from employees;
select sum(salary)/count(salary) from employees;上下两个语句算出的结果
                                                是一样的
但是注意如果一个员工的工资被置为null值,那么上面的第一个求平均值
select语句和第二条语句仍然是一样的,注意第二个语句中的count(salary),
括号中的字段一定要慎重的写,保证统计的行是正确的行数,否则平均值算出
来会有错误。

回滚语句:rollback; 回滚是针对事务来说的,不针对select语句,只是针对
         更新语句。

--------------
group by 列名

如果求每一个部门的id号(要求不重复)
select distinct department_id from employees;

所以如果求员工表里面部门的数量
select count(distinct department_id) from employees;

distinct作用:过滤掉重复的记录

如果查出每一个部门的平均工资,并且按照平均工资大小来排序,
而且结果要做到四舍五入:
select round(avg(salary),0) from employees group by department_id
                                  order by avg(salary) ;

select department_id,job_id from employees group by
                          department_id,job_id ;
也就是说完全可以按照两个字段来进行分组,先按照部门进行分组,
每一个具体部门里面的工种再具体分组,假如某个部门里面的it工种
有5个,那么求平均值的话就是对这5个进行求平均值。

注意:如果用了group by语句,那么只有组函数或是本来就在group by
      语句后面的列名或是常量是可以出现在select关键字后面的,
      其他的列是绝对不可以出现的!
      否则会出现not a single-group group function错误!
      因为组函数是单行的,如果跟上了其他字段,那就成了多行的了,
      会有冲突

      而且在group by字句后,where中不可以出现组函数或是分组后的字段!
      而是用having来限制条件!比如:

如果要选出各部门中最大工资超过10000的部门,并求出对应的max值
select department_id, max(salary) from employees group by
                department_id having max(salary) > 10000

select 'test', department_id, max(salary) from employees group by
                department_id having max(salary) > 10000

having后边能加的字段肯定也是组函数或是group by后面的列名或是在
前面select中出现的常量,不能是其他的。

having后可以加order by排序语句。
--------------------------
讲解昨天的作业:

6、公司程序员一直在抱怨收入还不如销售人员,做为财务人员,经理要求你提供程序员与财务人员的平均工资,
   这条SQL语句应该怎么写?(从employees表中查询,job_id为IT_PROG的是程序员,SA_REP的是销售员。)

我的答案:
select avg(salary) from employees where job_id='IT_PROG'
union select avg(salary) from employees where job_id='SA_REP';

老师的答案:
select job_id,avg(salary) from employees where
         lower(job_id)='it_prog'or lower(job_id)='sa_rep'
         group by job_id;

或:
select job_id,avg(salary) from employees 
         group by job_id having
         lower(job_id)='it_prog'or lower(job_id)='sa_rep';


7、使用一条SQL语句查询出部门平均工资最高值与部门平均工资最低值之差。

我的答案:
select max(avg(salary))-min(avg(salary)) as result,department_name
from employees
join departments using(department_id) group by(department_name);

 

和老师的答案基本一致:

8、分别使用联接和子查询,查询平均工资最多的部门名称。

我的答案:(我的思路见昨天的日记)

select * from
(select avg(salary) as sal,department_name from employees
join departments using(department_id) group by(department_name))
where sal=(select max(avg(salary)) as result from employees
join departments using(department_id) group by(department_name));

--------------------------------
课间休息时,和别人聊了一下蓝点的事情,班里有两个人是10月份在蓝点上
了一个礼拜后退的钱,然后来到的这里,再加上我之前知道的王铮是交了报名
费然后反悔并且来到的这里,这下子事情很清楚了,张老师博客上说的那4个
退学而来的某个培训中心的学员应该就是指的是蓝点世纪了,正是因为这事
得罪了他们,所以不得不把blog评论功能停了,看来往上诋毁张老师的也确实
是那帮人了……
---------------------------------

课间休息结束。


select department_id,max(avg(salary)) from employees
               group by department_id;
这是绝对不行的,因为组函数嵌套说明是进行了第二次分组,所以
这就不能在select后面加department_id了。

子查询:在查询语句中再嵌入一个子查询

select last_name from employees where salary>
(
 select salary from employees
 where lower(last_name)='abel'
);

select last_name from employees where salary in
(
 select salary from employees
 where lower(last_name)!='abel'
);

select last_name from employees where salary not in
(
 select salary from employees
 where lower(last_name)!='abel'
);

注意第三个语句是查不出任何结果的!,注意一下前两个的结果

注意子查询也可以在左边,也就是说:

select last_name from employees
where
(
 select salary from employees
 where lower(last_name)='abel'
) < salary;

类似上面的情况也是可以的。


有三个修饰符:in、any、all

in:等值匹配
any:任意一个匹配,之间是or的关系
all:必须全满足条件才匹配

找出所有部门最低工资小于7000的所有部门员工(要求必须使用in或any或all)

select department_id from employees group by department_id
having min(salary) < 7000; 这是先选出所有平均工资小于7000的部门

select first_name from employees where department_id in
(
 select department_id from employees group by department_id
 having min(salary) < 7000
);

这样就出来了。

select first_name from employees where department_id > some
(
 select department_id from employees group by department_id
 having min(salary) < 7000
);

上面也是一种写法,表达的意思与题目完全不一样,主要是告诉我们
some那里可以换成any或是all,这也是any、all、some派上用场的地方。

any:里面的任何一个满足条件就可以,
all:里面的所有都必须满足条件才可以。

子查询的效率是很低的,大部分情况下是比连接要低的……


查询employees表中,员工所在部门位于美国的所有员工。(要求用子查询实现!)

子查询:

select first_name from employees where department_id in
(
 select department_id from departments where location_id in
 (
   select location_id from locations where country_id in
   (
     select country_id from countries where region_id=
     (
       select region_id from regions where region_name='Americas'
     )
   )
 )
);

下面是用内连接的等值连接来查询:

select department_name,region_name||' '||country_name||' '||state_province||' '||city||' '||street_address as address_a
 from departments,locations,countries,regions
 where departments.location_id = locations.location_id
      and locations.country_id=countries.country_id
      and countries.region_id = regions.region_id ;


select department_name,region_name||' '||country_name||' '||state_province||' '||
                       city||' '||street_address as address_a
         from departments join locations on departments.location_id = locations.location_id
                          join countries on locations.country_id=countries.country_id
     join regions on countries.region_id = regions.region_id ;

对这道题目来说,连接的效率高于子查询,是因为连接里面建立了索引,
查找会快很多。因为索引中用了B+树,它比二叉排序树的搜索速度还要高。

除非连接是笛卡儿式的没有连接条件的连接,那就另当别论了。


注意in要谨慎使用,一般in出现的话效率都会很低。

注意子查询中有时如果要选择其他字段的话,那么用子查询就不行了,
因为一旦涉及到查出的字段不隶属于一个表的话,用子查询就无力实现了,
只能用连接,但是有时子查询能够实现的东东连接是实现不了的。

连接和子查询是互补的,但是你还需要考虑性能的问题。

-----------------------------------------------------------------
问题:查询平均工资最多的部门id:

select department_id,max(avg(salary)) from employees group by
        department_id;
这是绝对不可以的!!

select department_id, avg(salary) from employees group by department_id
这个可以。


select first_name,salary from employees where salary=
(
 select max(salary) from employees
);

这就查出了工资最高的员工名字和对应的工资数目


select department_id,avg(salary) from employees group by department_id
这就查出了部门id对应的部门平均工资了。可以把这个查询结果看作是
一张视图,以它为基准查询即可了。

select department_id from
(
 select department_id,avg(salary) as avgsal from employees
 group by department_id
)
where avgsal=
(
 select max(avg(salary)) from employees group by department_id
);

这就查出了平均工资最高的部门id,如果再想查出部门名称的话那就容易了,
直接把上面的查询结果作为子查询

select department_name from departments
where department_id = (上面查询的结果);

当然也可以这么来作:

select * from
(
 select avg(salary) as sal,department_name from employees
 join departments using(department_id) group by(department_name)
)
where sal=
(
 select max(avg(salary)) from employees group by(department_id)
);

-----------但是如果我要用连接来作这道题目呢??
首先想这道题目涉及几个表,首先是employees表,其次是department表,
但是我们这里考虑的是把表和前面创建的视图联系起来……

select department_name from departments join
(
  select department_id,avg(salary) as avgsal from employees
  group by department_id
)
using(department_id)
where avgsal=
(
 select max(avg(salary)) as avgsal from employees
 group by department_id
);

--------------------------------------------------------------------------------------

上午到此结束了

下午开始是DML数据操纵语言

中午去看了下离这里很近的那个房子,就是居民楼的单元间,很小,4个人倒是还可以,但我们
5个人就彻底没戏了,更何况屋子里还住其他人,这就显得厕所和洗脸的地方不够用了,也是
问题,还是就搬到隔壁吧,觉得还是学生公寓比较适合我们,走了一大圈,挺累的……
-------------------------------------------
真梱啊……下午的课程已经开始了,我精神头还没缓过来呢……

该data manipulating了

sql语句分四组:data define language、data control language、
               query language、data manipulating language

connect by语句:读出树状结构……

比如下面这道以前做过的题目:

现在要求以如下方式显示所有员工:
如果经理为100的员工有101、102、103,而101的直接下属为104、105, 102直接下属为106、107, 103直接下属为108,则显示为
101
--104
--105
102
--106
--107
103
--108
那么这条SQL语句应该怎么写?(注意,不能使用connect by)

最好的例子就是员工表中的manager_id和employee_id就是树状的关系。
start with condition(s)
connect by prior condition(s)

也就是叶子节点的manager_id要等于根节点的employee_id

select employee_id, manager_id from employees
start with last_name='King'
connect by
manager_id=prior employee_id; 
当前manager_id等于前一条记录的employee_id
从last_name是King的记录开始,

select employee_id,last_name,job_id,manager_id
from employees
start with employee_id=101
connect by prior manager_id=employee_id
从employee_id是101的用户开始,
当前的employee_id等于上一条记录的manager_id
也就是从当前的员工号向上司那方向追述

要是把上面的prior换到employee_id那边的话,这就是从King开始
向下追溯了……注意它是先序遍历的做法,先将一边遍历到底,然后
从顶层开始再遍历别的分支。

         1
    2         3
 4


type   parent_type
 1         0
 2         1
 3         1
 4         2

prior type=parent_type  这一层的type=这一层的parent_type

显示结果必然是:
1
2
4
3

就是二叉树中的先序遍历

connect by仅仅在自连接中才能使用!!

select rowid from employees;
执行后会显示出107行奇怪的字符串,这是oracle添加的伪列,
该列唯一的标识了每一条记录存储的位置,如果数据表中没有
设定主键的话,那么会出现重复记录的情况,如果要删除重复记录
的话必须用那个唯一能标识每一行的rowid

select level , employee_id,last_name,job_id,manager_id
from employees
start with employee_id=101
connect by  manager_id=prior employee_id;

执行后结果是从上往下遍历的

 

select level , employee_id,last_name,job_id,manager_id
from employees
start with employee_id=101
connect by employee_id=prior manager_id;

执行结果是从下往上遍历的

其中levle是伪列和rowid一样。

-----------------------------
这样的话,要想按照如下格式显示的话
101
--104
--105
102
--106
--107
103
--108
 只需根据level这个伪列就可以做到用lpad函数了。
level标识了是第几级。

select
   lpad(employee_id,length(employee_id)+(level-1),'-') as rank
from employees
start with employee_id=100
connect by manager_id=prior employee_id;

这样的话,总boss100不需要左边补‘-’,其他人是几级就补几个'-'
上一行的employee_id等于这行的manager_id,说明上一行是这行的boss!
所以是从上级往下级去遍历的

如果是connect by prior manager_id=employee_id;
上一行的manager_id等于这行的employee_id,说明这一行是上一行的boss!
所以是从下级往上级去遍历的

-------------------------------
介绍了rowid、level两个伪列,还有个rownum伪列

所谓rownum就是按照当前表中记录的顺序由上到下的
把所有记录进行编号

select last_name,rownum from employees
       where rownum < 11 ;
这个能查出1到10条的记录

select last_name,rownum from employees
       where rownum < 20 and rownum > 11;
但是这个却不能查出11到20条记录!

select last_name,rownum from
(
  select last_name,rownum from employees
       where rownum < 20
)
where rownum > 7;
这也是查不出7到20行记录的!因为最后的where条件rownum不能大于7!

可以用minus函数将两个表的结果相减!

select * from
minus(select last_name,rownum from employees where rownum < 20,
     select last_name,rownum from employees where rownum < 10);
注意上面的写法是错误的!


应该是:
select rownum from employees where rownum<10
minus
select rownum from employees where rownum<5;
这就可以了。


如果使用子查询的话:
select rownum,country_name from countries; 可以取出1到25条所有记录

选前十行:
select rownum,country_name from countries
     where rownum <= 10 ;
rownum是在查询时动态生成的。

如果条件写成rownum > 10就选不出来,这是为什么呢?
因为rownum是动态的,不是物理中固定好的,大于号不是不能用,
大于0是允许的, 因为先要选出一条记录,这个记录的rownum必然是1
但是这条记录是不可能大于1的,所以如果where条件后跟
的是rownum>1是绝对选不出来的!


使用子查询的正确写法:

select * from
(
 select last_name,rownum as id from employees
 where rownum<21
)
where id > 11 ;

既然不能够让rownum大于一个具体的非0值,那么先构造一个第一到20个
记录的表,这个表中把rownum的字段抽象成一个别名叫做id
这个id可以作为条件来选择……

这就是分页的解决方法了……在mysql中不支持rownum,所以只有oracle才能
用这种方法分页,mysql中有别的方法来分页!

所谓分页,最重要的思想就是要能自由的取出数据表中的第n条记录到第m条
记录(m > n)

伪列在手册中的basic elements 中的pseudocolumns中,可以在pdf中
ctrl+L来查找。

记住:
oracle中没有sqlserver中的top关键字!

课下作业:
-----------------------
-----------------------
start with如果不写的话会怎么样??
apache主要端口,port、listen什么的是怎么回事?
-----------------------
-----------------------


------------------------------
现在开始正式介绍DML语言:

所有DML语句都被包含在一个事务里面

insert into departments values(370,'Public Relation',100,17000);
这就在departments表中新建了一个列,如果这是在一个命令行窗口中创建的话,
那么如果新建一个命令行窗口的话,则不会显示出这个更新后的语句,
这是因为更新是个事务,这个事务还没有提交,所以必须还得在执行完insert
语句后加上一个commit;语句才可以提交事务

插入的时候必须给表中的每一个字段都提供值,哪怕是空值也要提供,绝对
不能漏掉不写!如果想漏掉的话可以在insert into departments后面用
括号把要插入的列包含进去,这样就不用在valuse里面提供所有字段值了,
这样没被插入的值就是null值了

insert into departments(department_id) values(1119);
这句执行后department_id为1的记录中的其他字段全部都是null值。

事务commit后不可以使用rollback来撤销事务,rollback只能用在commit之前!
事务只有两种结果,一是commit,二是rollback,如果更新了一条记录,但是
没有commit或是rollback而是关闭了命令行窗口,这样默认是commit。


注意插入数据时要保证数据类型的重要性,必须和数据表中的对应
类型匹配!

如果要往employees表中插入数据的话
先用desc employees来显示表的结构如下:

名称                                      是否为空? 类型
----------------------------------------- -------- -------------------

EMPLOYEE_ID                               NOT NULL NUMBER(6)
FIRST_NAME                                         VARCHAR2(20)
LAST_NAME                                 NOT NULL VARCHAR2(25)
EMAIL                                     NOT NULL VARCHAR2(25)
PHONE_NUMBER                                       VARCHAR2(20)
HIRE_DATE                                 NOT NULL DATE
JOB_ID                                    NOT NULL VARCHAR2(10)
SALARY                                             NUMBER(8,2)
COMMISSION_PCT                                     NUMBER(2,2)
MANAGER_ID                                         NUMBER(6)
DEPARTMENT_ID                                      NUMBER(4)

于是,sql插入语句如下:
insert into employees values
(99999,'yuan','bin','GavinKing','12345678',
  to_date('1977-12-12','yyyy-mm-dd'),'IT_PROG',111.23,0.2,100,200);

注意这里面有很多的约束性条件

可以用 desc user_constraints;查看

然后

    select constraint_name,constraint_type from user_constraints
    where lower(table_name)='employees';

因为employees表名在sql语句中大小写无所谓,但是现在employees表名
是在user_constraints表中的一个字段,所以大小写在上句话中很重要!!

这就在命令行中查出了employees表中的所有约束名和约束类型。

也可以在oem的方案中的hr中的表里面找到employees表,这里可以直观的看到
约束条件……

首先是employee_id不可以和以前的记录重复!job_id必须是曾经有过的!
manager_id必须要有!department_id也是必须要有的,因为有外键约束……

------------------------------
另外一种插入语句
insert into 表名(列名、……)
select ……
from 表名
where……

-----------------
update更新语句

update departments set manager_id=999999,location_id=1600
        where department_id=……;

也可以在更新语句中用子查询

update departments set department_id=380 where department_id=370;

有时假如有外键引用了这个主键的话那么就无法更改了,得先更改除从表
的对应外键后才能对主表的主键进行更新……

注意表里面如果有触发器的话那么可能你的更改也许只涉及两个表,但是触发
器的存在可能还会涉及第三个表的插入操作,那么你必须还得把第三个表中的
对应记录干掉才可以。


insert into(select ……from …… where……)
     values(……)

这种情况中我们把数据插入到了一个临时创建的视图中,
这个视图是一个用select查询出的一个临时表。

事务提交后,实际上并不是插入到了临时创建的视图中,
而实际上是插入了子查询中from后面的实际的数据库中
存在的数据表中了!!可以用select语句来查询确认……

insert into(select employee_id,last_name,email,hire_date,job_id,
             salary,department_id from employees
            where department_id=50 with check option)
      values(……)

这里有一个叫做with check option的东西,说明values里面插入的东西首先
必须满足department_id=50这个条件!也就是说有了with check option
插入的department_id必须是50!如果没有这个with check option的话,
那插入的department_id就可以不是50了……


其实这个with check option是为了防止插入的东西改变那些不在子查询中
的记录,有了with check option无论插入什么记录都只是更改子查询中
已经查出来的那些记录而已,不会涉及到子查询内容之外的记录……毕竟
对子查询出来的视图的更改会实际反映在真实的数据表中,所以基于数据安全
方面的考虑,所作的更改还是不要超出子查询视图的范围,所以要用
with check option

 


课下作业:
-----------------------
-----------------------
start with如果不写的话会怎么样??
apache主要端口,port、listen什么的是怎么回事?
还有老师发下来的数据操纵语言txt中的两道题目
-----------------------
-----------------------

现在是晚上了,网速还是那么慢,可以和乌龟赛跑了,刚才看了一下老师
发的SQL reference R92文档,查了一下start with和connect by这个层次化
查询,发现其实如果不指明start with的话(就是省略start with),则会
默认从第二级开始显示,因为第一级上面没有父亲了,所以默认从第二级别开始

至于那个apache,实在是没办法了,因为没办法上网……汗

晚上老师留了两道题目:

1、以hr/hr进入数据库,先执行
   CREATE TABLE bonuses (employee_id NUMBER, bonus NUMBER DEFAULT 100);
创建表。再向这个表中插入在表employees中工资小于7000的员工ID,逻辑意义
就是工资小于7000的员工,其资金为100。

创建表后,可以很明白的看到表bonuses中只有两个字段,一个是employee_id
另一个就是bonus,两个都是number类型。使用desc bonuses;命令就可以了。

因为number默认是100,说明插入值时如果不插入number的话那么number默认
就是100,正好满足题意了,所以只需要插入员工id就行了。

insert into bonuses(employee_id)
(select employee_id from employees where salary<7000);

这就行了。
---------------------------
2、在第一题的基础上,使用一条SQL语句实现以下功能:
   现在要为编号为80的部门的所有员工设置奖金数,奖金数为工资数的1%。
   如果员工在bonus表中已经存在,则要用已有奖金数加新增奖金数作为
   员工的最终奖金。

可能一次有点想不明白,那么分开来看一下把:

首先呢,编号为80的部门的所有员工都要设置奖金数目,那么首先要知道的
就是编号为80的部门里面的员工都是谁:

select last_name from employees where department_id=80;

上面的人里面有一部分是已经在bonuses表中的,但是有一部分是不在bonuses
表中的。这样操作就有两部分,

第一部分是把在bonuses表中的那部分人员的bonus字段进行更新,
也就是用100+工资*1%;

第二部分则是把不在bonuses表中的那部分人员插入到bonuses表中
并同时设定bonus为工资*1%

select employee_id from bonuses where
       employee_id not in
(
  select employee_id from employees where department_id=80
);

 

select employee_id from employees where department_id=80
         and salary >= 7000;
属于80部门但是不在bonuses表中的员工id;奖金设为工资×1%;


select employee_id from employees where department_id=80
         and salary < 7000;
属于80部门而且在bonuses表中的员工id;奖金设为工资×1%+100

题目要求处理的数据有一部分在bonuses表中根本就没有,这怎么可能设置
奖金呢??除非先向bonuses表中插入数据,可是这样一来又如何在一句话
之内完成题目要求呢???

……我发现这道题目我不太会作了……

更新的时候怎么也需要把那个该死的salary字段给弄进来,不然没法更新
奖金,所以一定要用连接的方式把两个表连接起来

也就是
   select employees.employee_id,bonus,salary from
       bonuses right outer join employees
       on bonuses.employee_id = employees.employee_id
       where department_id = 80 ;

之所以用外连接,是因为employees表中80部门的员工有一部分可是不在
bonuses表中的,不能把它们撇下,所以用外连接了……

选出的结果是34个记录,其中5条记录是隶属于80部门且在奖金表中(也就是
工资小于7000的员工),29条记录是在80部门而且呢,不在奖金表中(就是
工资大于7000的员工)。

上面那个子查询选出来的临时视图表就是我们应该更新的表,里面有80部门
的所有员工,而且里面还有每个员工对应的奖金,工资大于7000的员工对应
的奖金肯定是null值,而且最重要的是,里面有每个员工的salary,这样才能
对奖金进行更新操作……

update
(
   select employees.employee_id,bonus,salary from
       bonuses right outer join employees
       on bonuses.employee_id = employees.employee_id
       where department_id = 80
)
set bonus=nvl2(bonus , 0.01 * salary + bonus , 0.01 * salary) ;

这样就达到了更新的目的,由于那个临时表中的bonus只有两种情况,
要么为默认的100,这样的员工收入小于7000,最终奖金是要+100的;
要么为null值,这样的员工收入大于等于7000,最终奖金不加100,
所以用nvl2函数来判断是最合适不过的了。

但是执行后出现“无法修改与非键值保存表对应的列”错误,上csdn上查了
一下(那叫一个慢啊……),说是这种情况和视图一样,视图是不能够更新的,
想更新的话必须在视图上写update的触发器:

 CREATE   OR   REPLACE   TRIGGER   A_V  
      INSTEAD   OF   UPDATE   ON   A_V  
      REFERENCING   OLD   AS   O   NEW   AS   N  
      FOR   EACH   ROW
当然我现在是看不懂上面的创建触发器代码,也许以后能行吧……

看来得借助一下别人了

update
(
   select employees.employee_id,bonus,salary from
       bonuses right outer join employees
       on bonuses.employee_id = employees.employee_id
       where department_id = 80
)
set bonus=nvl2(bonus , 1 , 2) ;

这种方式也更新不了,看来确实是无法更新的问题,和update中表达式的
书写没有任何关系。

刚才问了一下刘栋和杨仕明,
下面是杨仕明的答案:

select DEPARTMENT_ID, SALARY, SALARY*0.01+
 nvl((select BONUS from BONUSES where EMPLOYEE_ID=EMPLOYEES.EMPLOYEE_ID),0)
 as FINAL_BONUS
 from EMPLOYEES
 where DEPARTMENT_ID=80
 order by SALARY
;

如果不是从更新的角度去想的话,他作的非常的正确,
他这个select语句选出的结果确实是题目要求的,这没有一点悬念。

最高明的是他的这种写法:
在nvl中有这么一个子查询:
(select BONUS from BONUSES where EMPLOYEE_ID=EMPLOYEES.EMPLOYEE_ID)
这个语句没有用连接就引用了employees.employee_id,因为后面有from
employees这个表达式,其实在那表达式里面就是用了连接也是没有问题的。

-------------------------------
确实高明啊,我老是往更新的那个角度去想,思维太僵化了……汗,
一个30多岁的人竟然如此的厉害,他以前还是教文科的?呵呵,即便真的如此,
也一定一直或者曾经和it这方面打过交道,不然不可能写得这么好吧,当然
也是我的个人猜测,看看以后吧,遇到问题还得多请教他呢

 这是刘栋的答案:

merge into bonuses c using(select employee_id as eid,salary*0.01 as sal from employees where department_id=80)
on(c.employee_id =eid) when matched then
update set bonus=bonus+sal
when  not matched then
insert values(eid,sal)

呵呵,都是强人啊,牛!……

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                                      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值