学习笔记:Oracle

    • 写在开头
    • 1. Oracle
      • 1.1 VARCHAR2
      • 1.2 dual
      • 1.3 exist 和 in
    • 2. 查询
      • 2.1 inset into ... select ...
      • 2.2 count()
    • 2. 多表查询
      • 2.1 自连接
      • 2.2 子查询
        • 2.21 单行子查询
        • 2.22 多行子查询
        • 2.23 多列子查询
        • 小总结
      • 2.3 用查询结果创建新表
      • 2.4 合并查询(union、union all、intersect、minus)
    • 3. 排序
    • 4. 聚合函数,分组函数
    • 4. 单行函数
    • 5. 日期函数
    • 6. 转换函数 to_char、to_number
    • 7. 通用函数
    • 8. 多表查询

W3school Oracle

写在开头

如何衡量一个程序员的水平? 网络处理能力,数据库,程序代码的优化程序的效率要很高。

1. Oracle

Oracle 要用单引号,双引号会有语法错误。

1.1 VARCHAR2

把空串等同于null处理,而varchar 仍然按照空串处理。 建议在Oracle中使用 VARCHAR2。

1.2 dual

是 Oracle提供的最小的工作表,只有一行一列,具有某些特殊功用。常用来通过select语句计算常数表达式。

1.3 exist 和 in

Exist 和 in 的区别

2. 查询

注意:
1)切忌动不动就用select * ,使用 * 效率比较低,特别在大表中要注意。
2)oracle对内容的大小写是敏感的,所以ename='smith’和ename='smith’是不同的
3)别名需要使用“”号圈中,英文不需要“”号

2.1 inset into … select …

insert into…select…表复制语句
语法:insert into table2(field1,field2,…) select value1,value2,… from table1

2.2 count()

统计 SFZH 相同的 数量, 效果:前几行是相同的, 其c 的值 > 1, 后几行是不同的,其c=1

select SFZH, count(SFZH) c from table group by SHZH order by c desc;
// 起别名
select empno eno, ename en from emp;

// 去掉 重读的数据
select distinct job from emp;
// 所有写的 字段的值 全相同,才会去重
select distinct ename, job, deptno from emp;

// || 字符串连接 输出结果: 员工编码1姓名是李明的工作是程序员
select '员工编号' || empno '姓名是' ename ||  '的工作是' || job from emp;


// null 要用 is
select * from emp where ename is not null;

// 多个查询条件之间 用 and (两个都要的 用 or)
select * from emp where sal > 1500 and ename is not null;

select * from emp where sal <= 1500 and ename is null;		// 此行和 下一行 效果完全一样
select * from emp where not(sal > 1500 and ename is null);

// between .. and .. (不止可以用在数之间,还可以用在日期之间)
select * from emp where sal between 1500 and 3000;  (1500<= sal <= 3000)
select * from emp where hiredate between to_date('1981-1-1', 'yyyy-mm-dd') and to_date('1981-12-31', 'yyyy-mm-dd');   // 雇佣日期在 1981-1-1 到 1981-12-31 之间的 

// in、not in
select * from emp where empno in (1, 20, 7);
select * from emp where empno not n (1, 20, 7);

// like 模糊查询;  '%' 任意长度,'_' 一个长度
select * from emp where enmae like '_M%';  // 第二个 字母是 M
select * from emp where enmae like '%M';   // M 结尾

// !=
select * from emp where empni != 7;

2. 多表查询

多表查询是指基于两个和两个以上的表或是视图的查询。在实际应用中,查询单个表可能不能满足你的需求,如显示sales部门位置和其员工的姓名,这种情况下需要使用到dept表和emp表。

问题:显示雇员名,雇员工资及所在部门的名字【笛卡尔集】?

SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno;

规定:多表查询的条件是至少不能少于表的个数N-1才能排除笛卡尔集(如果有N张表联合查询,必须得有N-1个条件,才能避免笛卡尔集合)

2.1 自连接

自连接是指在同一张表的连接查询 问题
问题:显示 员工FROD 的上级领导的姓名?

SELECT worker.ename, boss.ename FROM emp worker, emp boss WHERE worker.mgr = boss.empno AND worker.ename = 'FORD';

2.2 子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。

2.21 单行子查询

单行子查询? 单行子查询是指只返回一行数据的子查询语句

请思考:显示与SMITH同部门的所有员工? 思路: 

1)查询出SMITH的部门号(返回单行结果集) 
select deptno from emp WHERE ename = 'SMITH'; 
2)显示 
SELECT * FROM emp WHERE deptno = (select deptno from emp WHERE ename = 'SMITH'); 
数据库在执行sql是从左到右扫描的,如果有括号的话,括号里面的先被优先执行。

2.22 多行子查询

多行子查询 多行子查询指返回多行数据的子查询。

请思考:如何查询和部门10的工作相同的雇员的名字、岗位、工资、部门号

1)查询出部门10的所有工作(返回多行结果集)

SELECT DISTINCT job FROM emp WHERE deptno = 10;

2)显示

SELECT * FROM emp WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10);
	
注意:不能用job=..,因为等号=是一对一的

在多行子查询中使用all操作符
问题:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号?

--方法一

SELECT ename, sal, deptno FROM emp WHERE sal > all(SELECT sal FROM emp WHERE deptno = 30);

--方法二(执行效率最高,使用聚合函数)

SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT max(sal) FROM emp WHERE deptno = 30);

在多行子查询中使用any操作符
问题:如何显示工资比部门30的任意一个员工的工资高的员工姓名、工资和部门号?

--方法一

SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30);

--方法二(执行效率最高,使用聚合函数)

SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT min(sal) FROM emp WHERE deptno = 30);

2.23 多列子查询

单行子查询是指子查询只返回单列、单行数据,多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句。

请思考如何查询与SMITH 的部门和岗位完全相同的所有雇员。

SELECT deptno, job FROM emp WHERE ename = 'SMITH';

SELECT * FROM emp WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = 'SMITH');

在from子句中使用子查询
请思考:如何显示高于自己部门平均工资的员工的信息?
思路: 1. 查出各个部门的平均工资和部门号 SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno; 2. 把上面的查询结果看做是一张子表

SELECT e.ename, e.deptno, e.sal, ds.mysal 
FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) ds   // deptno需要是分组函数,所以要写进 group by里
WHERE e.deptno = ds.deptno AND e.sal > ds.mysal;

小总结

小总结: 在这里需要说明的当在from子句中使用子查询时,该子查询会被作为一个视图来对待,因此叫做内嵌视图,当在from 子句中使用子查询时,必须给子查询指定别名。 注意:别名不能用as,

如:SELECT e.ename, e.deptno, e.sal, ds.mysal 
FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) as ds 
WHERE e.deptno = ds.deptno AND e.sal > ds.mysal;

在ds前不能加as,否则会报错(给表取别名的时候,不能加as;但是给列取别名,是可以加as的)

2.3 用查询结果创建新表

这个命令是一种快捷的建表方式

CREATE TABLE mytable (id, name, sal, job, deptno) as SELECT empno, ename, sal, job, deptno FROM emp;

2.4 合并查询(union、union all、intersect、minus)

有时在实际应用中,为了合并多个select语句的结果,可以使用集合操作符号union,union all,intersect,minus。 多用于数据量比较大的数据局库,运行速度快。

1) union 该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。

SELECT ename, sal, job FROM emp WHERE sal >2500
UNION
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';

2)union all 该操作符与union相似,但是它不会取消重复行,而且不会排序。

SELECT ename, sal, job FROM emp WHERE sal >2500
UNION ALL
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';

该操作符用于取得两个结果集的并集。当使用该操作符时,不会自动去掉结果集中重复行。

3) intersect 使用该操作符用于取得两个结果集的交集。

SELECT ename, sal, job FROM emp WHERE sal >2500
INTERSECT
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';

4) minus 使用该操作符用于取得两个结果集的差集,他只会显示存在第一个集合中,而不存在第二个集合中的数据。

SELECT ename, sal, job FROM emp WHERE sal >2500
MINUS
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';

(MINUS就是减法的意思)

3. 排序

select * from emp (where) order by sal;  // 默认升序 asc
select * from emp order by sal desc, hiredate desc; // sal 相同的 按照 hiredate 降序

4. 聚合函数,分组函数

聚合函数用法:max,min,avg,sum,count

问题:如何显示所有员工中最高工资和最低工资?

select max(sal),min(sal) from emp e;

最高工资那个人是谁?

错误写法:select ename, sal from emp where sal=max(sal);

正确写法:select ename, sal from emp where sal=(select max(sal) from emp);

注意:select ename, max(sal) from emp;这语句执行的时候会报错,说ora-00937:非单组分组函数。因为max是分组函数,而ename不是分组函数.......

但是select min(sal), max(sal) from emp;这句是可以执行的。因为min和max都是分组函数,就是说:如果列里面有一个分组函数,其它的都必须是分组函数,否则就出错。这是语法规定的

group by 和 having 子句 group by 用于对查询的结果分组统计, having 子句用于限制 分组显示结果。


问题:如何显示每个部门的平均工资和最高工资?
(注意:这里暗藏了一点,如果你要分组查询的话,分组的字段deptno一定要出现在查询的列表里面,否则会报错。因为分组的字段都不出现的话,就没办法分组了,又因为其他字段是分组函数,所有必须也的是分组函数,所以 非分组函数字段 都写在 group by后面)

问题:显示每个部门的每种岗位的平均工资和最低工资?
select min(sal), avg(sal), deptno, job from emp group by deptno, job;

问题:显示平均工资低于2000的部门号和它的平均工资?
select avg(sal), max(sal), deptno from emp group by deptno having avg(sal)< 2000;
select avg(sal), max(sal), deptno from emp group by deptno;

问题:显示雇员名,雇员工资及所在部门的名字,并按部门排序?

SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno ORDER by e.deptno;

注意:如果用group by,一定要把e.deptno 放到查询列里面

对数据分组的总结
1) 分组函数只能出现在选择列表、having、order by子句中(不能出现在where中) 2) 如果在select语句中同时包含有group by, having, order by 那么它们的顺序是group by, having, order by 3 在选择列中如果有列、表达式和分组函数,那么这些列和表达式必须有一个出现在group by 子句中,否则就会出错。
如:

select deptno, avg(sal), max(sal) from emp group by deptno having avg(sal) < 2000;这里deptno就一定要出现在group by

4. 单行函数

// 大写 upper,小写 lower, 首字母大写 initcap  也可以写字段,但是不用加引号
select upper('smith') from dual;  // 字段名是 UPPER('SMITH') 值为 SMITH
select initcap('smith') from dual;  // 字段名是 INITCAP('SMITH') 值为 Smith


// 字符串连接 concat() 但是可以用 ||,建议用 ||
select concat("hello", "world") from dual;  // 字段名 CONCAT("HELLO", "WORLD") 值 helloworld
select "hello" || "world" from dual;   // 和上面效果一样,建议使用这个

// substr() 字符串区分。 字符串可以写 不加的 字段! 还可以起别名.
select substr('hello', 1, 3) from dual;   // 字段 SUBSTR('HELLO', 1, 3) 值 hel。下标从1开始。0的话 和 1一样的, 但就是从1开始的。

// length() 获取长度。 也可以写字段,但是不用加引号。 还可以起别名.
select length('length') from dual;    // 字段 LENGTH("HELLO")  值5

// replace() 字符串替换。  也可以写字段,但是不用加引号。 还可以起别名.
select replace('hello', 'l', 'x') name from dual;  // 字段 name, 值 hexxo

// round() 数值函数,四舍五入
select round(12.48) round from dual;  // 字段round  值 12
// 保留2位小数
select round(12.487, 2) round from dual;  // 字段round  值 12.49
// tunc() 去掉小数
select trunc(12.87) trunc from dual;  // 字段 trunc 值12
// 保留几位小数, 去掉后面的, 不进位。
select trunc(12.876, 2) trunc from dual;  // 字段 trunc  值12.87
// mod() 取余,
select mod(10, 3) mod from dual;  // 字段mod  值1

5. 日期函数

日期 - 数字 = 日期

日期 + 数字 = 日期(天)

日期 - 日期 = 数字

// 当前日期
select sysdate from dual;  // 字段 SYSDATE, 值 当前系统的时间
// (日期 - 日期)/7 就是周数
select trunc((sysdate - hiredate) / 7) week from emp;  // 字段 week, 值 整数值
// 获取两个时间段中的月数
select ename, trunc(months_between(sysdate, hiredate)) months from emp;  // 字段 months, 值 整数值(代表几个月)
// add_months()  加几个月
select add_months(sysdate, 12) result from dual;   // 字段 result, 值 当前系统的一年后
// 下一个 星期一 的日期
select next_day(sysdate, "星期一") result from dual;
// 本月最后一天 的日期
select last_date(sysdate) result from dual;   // 字段 result, 值 比如2020/4/30 星期四 21:05

6. 转换函数 to_char、to_number

// to_char 字符串转换函数
select ename, to_char(system, 'yyyy') 年,
		to_char(hiredate, 'mm') 月,
		to_char(hiredate, 'dd') 日,
		to_char(hiredate, 'HH') 时,
		to_char(hiredate, 'mi') 时,
		to_char(hiredate, 'ss') 时,
from emp; 
select to_char(sysdate, 'yyyy-mm-dd HH24:mi:ss') from dual;  // 24小时制
select to_char(sysdate, 'yyyy-mm-dd HH:mi:ss') from dual;    // 12小时制

// fm去掉 前导0, 比如月份 09   就成了 9
select ename, to_char(hiredate, 'fmyyyy-mm-dd') from emp;

// to_char 给数字  格式化
select ename, to_char(sal) from emp; // 处理数字
select ename, to_char(sal, '99,999') from emp;  // 以三位数字分割,比如 1600  ->  1,600
select ename, to_char(sal, '$99,999') from emp;  // 以三位数字分割,比如 1600  ->  $1,600
select ename, to_char(sal, 'L99,999') from emp;  // 以三位数字分割,比如 1600  ->  ¥1,600


// to_number 数字转换函数。如果写的 a 去掉引号 是 非数值的,会报错
select (to_number('10') + to_number('10')) result from dual;  // 字段 resul, 值20

// to_dade  日期转换函数,这个没啥用,用 to_char 好使。
select to_date('1985-04-22', 'yyyy-mm-dd') date from dual;  // 字段date, 值 1985/4/22 星期一
select to_date('1985-04-22 12:30:20', 'yyyy-mm-dd HH24:mi:ss') date from dual;  // 字段date, 值 1985/4/22 星期一 下午12:30:20

7. 通用函数

// nvl() 空值处理
select ename, nvl(comm, 0) pcomm from emp;  // 会把 comm字段为null 的变成0,不然null做任何运算都是null
select ename, (sal*12 + nvl(comm, 0)) yearsal from emp;  // 如果不加nvl,comm为null 经过运算后 还是null

// decode()  相当于  if...else if ... if
select decode(1, 1, '我是1', 2, '我是2', '其他') from dual;   // 第一次个参数 匹配的内容,会输出 我是1,  如果 第一个参数改为 2, 就会输出  我是2。
// 替换该字段的值
seelct ename, decode(job, 'clerk', '业务员', 'salesman', '销售', 'manager', '经理') cjob from emp;

// case when 替换 字段的值, 效果和 上面一样的
select ename, case when job='clerk' then '业务员'
				   when job='salesman' then '销售'
				   when job='manager' then '经理'
				   else '无业'
				   end from emp;

8. 多表查询

// 2个表关联查询
select * from emp e, dept d where e.deptno = d.deptno;

// 查询 2 表的某些字段
select e.empno, e.name, d.deptno, d.dname d.loc from emp e, dept d where e.deptno = d.deptno;

// 查询每一个员工的上级领导(mgr) (2个字段都在同一个表里) (也就是自连接查询)
select e.empno, e.ename, e1.empno, e1.ename from emp e, emp e1 where e.mgr = e1.empno; // 字段名:  empno  ename empno ename, 值 就是 前两列是员工的编号和姓名,后两列是上级领导的编号和姓名

你可能感兴趣的:(学习笔记)