笔记_DML+查询

有道云笔记 连接:

http://note.youdao.com/share/?id=242091c1298baddb14abb4b7b909bf35&type=note


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

以下可忽略:



Oracle日常操作的命令分为两大类:sqlplus命令和一般sql语句。 


示例的情况:
        CREATE USER scott IDENTIFIED BY m123;
        GRANT DBA TO scott;
        
        
        


【一般查询】:

1.求员工的年工资。
        错:SELECT sal*13+comm 年工资,ename FROM emp;
        
        对:SELECT sal*13+ nvl(comm,0) 年工资,ename FROM emp;

2.查询1980年4月2日后入职的员工名单。
        
        两种方式:SELECT hiredate, ename FROM emp WHERE hiredate > to_date('1980-4-2', 'yyyy-mm-dd');
                        或SELECT hiredate, enameFROM emp WHERE hiredate > '2-4月-1980';
        其中, ' 2-4月-1980'是oracle能默认识别的Date格式。

3.查询工资在2000至2500的员工名单。
        SELECT sal 工资,ename FROM emp WHERE sal>2000 AND sal<2500;
        注意条件之间别忘了and。

4.查询名字第三个字母为大写字母O的员工名单
        SELECT ename FROM emp WHERE ename LIKE '__O%';
         like操作符:%表示任意0到多个字符。_表示任意单个字符。
        这个例子中,注意O后面的%不要落写了。

5.查询员工号码为123或324或550的员工名单。
        SELECT * FROM emp WHERE empno IN(123,324,550);
         查询多个条件时建议用 in( ,, ),而不是多个or。
        因为oracle对in()这种方式的查询有优化,效率特别高。

6.查询工资高于500,或岗位为MANAGER,并且姓名首字母为大写J的员工名单。
        SELECT sal,job,ename FROM emp
                    WHERE (sal>500 OR job='MANAGER')
                                AND ename LIKE 'J%';
        注意 括号



>[ORDER BY]
1.按薪水从低到高排列员工信息。
        SELECT * FROM emp ORDER BY sal;
        注意ORDER BY 默认(ASC)是从小到大(升序)的顺序;从大到小(降序)须加上 DESC

2.按部门号升序而员工工资降序排列员工信息。
        SELECT * FROM emp ORDER BY deptno,sal DESC;
        
         多个排序字段,则用逗号隔开,前面的为第一排序字段,后面的一次降级。
        比如此例,若是ORDER BY sal DESC,deptno,则结果完全不一样。

3.按部门号升序而员工入职时间降序排列员工信息。
        只需将上例的sal改为hiredate。
        注意,Oracle中日期、时间 (Date)字段可排序,即有大小,应该是时间戳形式的。

4.按年薪降序排序(或者说,查询员工的年薪并按从高到低排序)
        SELECT sal*12+NVL(comm,0) "年薪",ename FROM emp
                    ORDER BY "年薪" DESC;
        
        这里用到了 Oracle的“别名”
        a.别名可以是中文或英文,都是用 半角双引号(一大特点);
        b.别名钱可加as,也可省略;
        c.别名作为整体可作为ORDER BY的字段;
        类似本例这种带别名的排序查询,在统计系统、财务系统经常使用。


复杂查询_统计类
        
        复杂SELECT基本分为 两类
        a.数据统计。体现在GROUP BY及相关的数据分组查询。
        b.连接查询。多表相关联。
        另外一个维度,就是逻辑复杂,子查询嵌套。
         结果:单看一个复杂SELECT,很难读懂。

>[合计函数]:
        合计函数(或者叫,聚合函数):MIN,MAX,AVG,SUM,COUNT。
        它们的特点是用在多条记录上,用于统计。
        合计函数不一定与GROUP BY一起使用。

1.显示所有员工的最低工资、最高工资。
        SELECT MIN(sal) "最低工资",MAX(sal) "最高工资" FROM emp;
        

2.显示所有员工的平均工资和工资总和。
        SELECT AVG(sal) "平均工资",SUM(sal) "工资总和" FROM emp;
        

3.显示共有多少员工。
        SELECT COUNT(empno) FROM emp;
        

4.显示职位有多少种。
        错:SELECT count(job)  "职位种数" FROM emp;
        对1(简单 但不建议):SELECT count( DISTINCT job)  "职位种数" FROM emp;
        对2:SELECT COUNT( "tmp") "职位种数" FROM
                            (SELECT  MIN(sal) "tmp" FROM emp 
                                        GROUP BY job);
        
        如此例, 替代DISTINCT(因为它降低效率)的方法:
        a.先用GROUP BY对需要去重的字段做一次查询,SELCET后是任意的聚合函数(越简单越好),病取个别名;
        b.对上面的子查询进行查询,SELECT后是对子查询结果的那个别名的聚合函数。

5.显示工资最高员工的工资,名字,工作岗位。
        错:SELECT MAX(sal),ename FROM emp;
        对:SELECT sal,ename FROM emp WHERE sal=(SELECT MAX(sal) FROM emp);
        
         看似简单,但是却需要使用子查询。
        而且 注意到(Oracle的“道理”),
        a.分组函数一般不能跟一般字段 混用作为SELECT的结果集,除非GROUP BY中。
        b.子查询的结果是一个数值,可以 赋值给查询条件。
        
6.显示工资高于平均工资的员工信息。
        SELECT * FROM emp WHERE sal>(SELECT AVG(sal) FROM emp);
        与上例同理。

7.将工资低于平均工资、又是1980年12月31日前入职的的员工工资涨10%(一条SQL搞定)。
        UPDATE emp SET sal=sal*1.1 WHERE sal<(SELECT AVG(sal) FROM emp)
                    AND hiredate<to_date('1980/12/31','yyyy/mm/dd');
        
        此例算是比较复杂的SQL了。



>[GROUP BY及HAVING子句 ]:

1.显示每个部门(号)的平均工资,最高工资。
        SELECT AVG(sal),MAX(sal),deptno FROM emp GROUP BY deptno;
        
2.显示每个部门的各个岗位的平均工资和最高工资。
        SELECT AVG(sal),MAX(sal),job,deptno FROM emp GROUP BY deptno,job;
        
         多层分组:按顺序由逗号分开。(而不是子查询)

3.显示平均工资高于2000的部门号和它的平均工资。
        SELECT AVG(sal),deptno FROM emp GROUP BY deptno having AVG(sal)>2000;
        
         HAVING子句:SQL中增加它就是为了解决WHERE子句无法 与合计函数一起使用的问题。

4.上例,并按从高到低排序。
        SELECT AVG(sal),deptno FROM emp GROUP BY deptno HAVING AVG(sal)>2000 ORDER BY AVG(sal) DESC;
        
        有以下固定顺序(经验):
        GROUP BY-->HAVING-->ORDER BY
        注意的是, 合计函数能出现在SELECT列表、HAVING子句、ORDER BY子句中, 唯不能出现在查询条件WHERE子句中。



【复杂查询_多表】:
        
        实际项目中,更多的是多表查询。原因,一是设计数据库时,避免数据冗余,一个表的结构不应该复杂(字段之间有关联则不合范式);二是,实际的需求逻辑复杂,任何SQL只是工具。
        
         笛卡尔积bug
        
        
        a.像上面的连接查询(不加条件的笛卡尔积),是很危险的,项目中不可能出现,尽管能查出来结果( 病毒?瘫痪数据库服务器)。比如再连接一张5条记录的表,结果就有14*4*5=280条。
        b.2张表则至少有1个连接条件,3张表至少2个连接条件......即 n张表连接查询,则至少有n-1个连接条件。在做复杂多表连接查询时,这条可以作为一个验证,不会出上一条类似的bug。 注意:n-1个连接条件仍不能保证笛卡尔积bug消失,连接条件不合理的话。
        

1.显示部门号为10的部门地址、员工名和工资。
         连接查询写法
        
        

3.显示各个员工的姓名、工资及其工资级别。
        
        写法步骤跟上一例一样,但注意到:emp和salgrade没有主外键关系。
         注意:所以,直观地,两个表做连接查询, 可以想象成两表先做笛卡尔积,然后WHERE子句筛选。(这样,多表连接、自连接等就很好理解了)

4.显示雇员名、雇员工资及所在部门的名字,并按部门排序。
        
        

5.显示员工FORD的上级领导姓名。
        
        



【复杂查询_子查询】:
1.显示SMITH的所有同部门同事姓名。
        
         注意的是:子查询可能嵌套很多层,但不一定同时是连接查询。
         补充:项目中设计表时,不建议把逻辑拆分得太复杂(视图?),这样会造成一个SELECT语句过于复杂(5张表以上的连接才行),不利于 他人开发和维护(读复杂SQL很费时间,可能过段时间自己都读不懂了) 。一般设计为连接的表数量在5个以内
        

2.显示所有工作为SALEMAN员工的部门的MANAGER。
        

3.显示比部门号30的所有部门员工工资都高的员工姓名、工资、部门名。
        
        本例中的多行子查询加ALL可以用合计函数MAX的一种方式替换。而且 推荐后一种,因为效率可能会高一点(比较次数少)。“能快一秒,绝不慢一秒。快0.01秒都是高手(韩顺平)”
         注意到,连接查询的条件a1.deptno=a2.deptno和其它条件的先后顺序不重要。可参考后面的优化技巧-->8-->Oracle扫描顺序-->实验结果。

4.将题目改为"显示比SALES部门的所有部门员工工资都高的员工姓名、工资、部门名"。
        
        可 描述为:2表连接查询+多行子查询(包含2表连接查询,且是同2张表)。相当于对"2表连接查询"做了一次自连接+子查询。
        写起来逻辑不复杂,只要别把别名弄混了。但是若让另个人来读,难度可能就大了。(尤其别名起的不好的情况下)所以, 别名对复杂SQL语句的 可维护性很重要。

5.又将题目改为"显示比 部门号30部门 任意 员工工资都高的员工姓名、工资、部门名"。
        SELECT a1.ename,a1.sal,a2.dname FROM emp a1,dept a2
                    WHERE a1.deptno=a2.deptno AND
                         a1.sal>  ANY(SELECT sal FROM emp WHERE deptno=30) ;            
        SELECT a1.ename,a1.sal,a2.dname FROM emp a1,dept a2
                    WHERE a1.deptno=a2.deptno AND
                         a1.sal> (SELECT  MIN(sal) FROM emp WHERE deptno=30) ;
         多行子查询用到ANY。ANY跟ALL正好是个对比,就像MIN和MAX的对比一样。

6.显示与SMITH的部门和岗位完全相同的所有雇员。
        
        重点在,WHERE子句后可有 WHERE (deptno,job)=(......)这种形式。

7.显示高于自己部门平均工资的员工名单。
        
        这是所谓 需要“编程”的SQL语句
        若要完成题目,则需要依题构造一个子查询,即:
        
        说“构造”,是因为这个查询需要有deptno和AVG(sal)两项,以便与emp表由deptno建立连接查询。
        这个FROM后手工构造的子查询,术语叫“ 内嵌视图”。它必须 有别名,这个别名相当于视图名。
         补充(别名):Oracle有一些奇怪又复杂的规定,比如给列起别名可以加as,给表起别名不能加as;再比如列的别名是中文时,可加双引号或不加都可以,但是英文时可能对单引号、双引号和不加引号有区别。
        这可能跟Oracle几十年来版本太多,新版本极力支持老版本,导致系统架构不清有关。Java也有这个趋势,“一切为对象”的最初思想,因为各新版本增加的自动拆装箱、泛型、闭包等函数编程概念,变得模糊起来。
        所以,对于这些地方,千万别较真,只有多积累经验,能记住几条就是几条,就足够了。



【综合_分页Pagination】:

        Oracle的分页比其它数据库都不好理解,要会子查询才能写好。
        由于有好几种写法,而且写法复杂,所以单纯靠记公式(MySql或2000)是行不通的。要知道两条: ROWNUM的机制和 子查询
        不同的分页写法,对效率有影响。
        由于这个地方Oracle没有个标准,所以"到时候能写出来就可以了,老板知道你干什么的就可以了"。
        Oracle的领域许多都是, 首要是把需求实现出来,然后再一点点优化。因为没有人能从根本上说这条SQL语句效率就是最高的。
        
1.分页查询的几个写法。
方法1(易记,易读,效率高,易维护)
        

方法2(最常见)
        
        此写法的分页,很多人都是这么写(将大于和小于两个条件 分别放在主查询和子查询中)。
        容 易出错的地方:子查询的SELECT列表中ROWNUM必须有别名rn(主查询要用),但是子查询的条件不能用别名rn<6,只能ROWNUM<6。
         补充:这个方法产生的思路(非子查询SELECT ROWNUM,ename FROM emp where ROWNUM>=3  AND ROWNUM >=6在Oracle中出错),参考: 笔记_查询优化,及一些细节-->6.查找第x行数据-->a.非子查询方式-->实验

方法3(项目推荐,易维护)
        
        方法3是 方法2的延伸(思路都是将大于和小于分开存放),它的特点在于: 结果集方便控制
        比如,如果想分页结果集是(rn,ename,sal)这3项,只需把最里层子查询b1的*改为ename,sal。
         效率实验
        过程略吧。存了990条数据,三个方法试过后,可能缓存的关系,效率差别不大。
        实际工作中,选哪种方式,自己具体情况具体试一试,只要能够说服就行。
         注意的是,结果集的选取,对效率影响旺旺更大。

方法4(ROWID分法,效率最高):
        韩顺平的效率试验:
        
        问题是ROWID方法太容易写错了,也不好维护。

2.分页查询的排序
        注意到,分页查询的排序有 两种
        a.先把所有记录排序,再取第100到第110条;
        b.取到第100到110条后,再对这10条排序。
        一般,如果需求明确是第一种,那么很简单,写分页时 注意下ORDER BY的位置。如果不明确是第一种,那么一定不要按第一种写,因为效率会低。




【综合_建表由SELECT】:
        这个在Oracle的维护、实验中有用。因为数据很珍贵吧,所以试一试增删改查,先把表用这个方法导出新建一份,在这个上测试。
        



【综合_SELECT的集合】:
        
        这个在实际项目中用的不多,了解有 UNION(合集)、 UNION ALL(合集,包括重复)、 INTERSECT(交集)、 MINUS(差集)这几个集合运算就行。
        
         补充:但是,韩顺平听网上说,大数据量时,这4个集合操作, 效率比WHERE(包括AND,OR)效率高出很多。
        对于这种传说中的查询优化,留心并记下来就可以了。因为数据量不大时,效率差基本看不出来。等到数据量大、数据库吃紧时,又能想到 优化的方向,足够。











































猜你喜欢

转载自blog.csdn.net/na_simon2900086/article/details/53167484
DML