W3school Oracle
如何衡量一个程序员的水平? 网络处理能力,数据库,程序代码的优化程序的效率要很高。
Oracle 要用单引号,双引号会有语法错误。
把空串等同于null处理,而varchar 仍然按照空串处理。 建议在Oracle中使用 VARCHAR2。
是 Oracle提供的最小的工作表,只有一行一列,具有某些特殊功用。常用来通过select语句计算常数表达式。
Exist 和 in 的区别
注意:
1)切忌动不动就用select * ,使用 * 效率比较低,特别在大表中要注意。
2)oracle对内容的大小写是敏感的,所以ename='smith’和ename='smith’是不同的
3)别名需要使用“”号圈中,英文不需要“”号
insert into…select…表复制语句
语法:insert into table2(field1,field2,…) select value1,value2,… from table1
统计 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;
多表查询是指基于两个和两个以上的表或是视图的查询。在实际应用中,查询单个表可能不能满足你的需求,如显示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个条件,才能避免笛卡尔集合)
自连接是指在同一张表的连接查询 问题
问题:显示 员工FROD 的上级领导的姓名?
SELECT worker.ename, boss.ename FROM emp worker, emp boss WHERE worker.mgr = boss.empno AND worker.ename = 'FORD';
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询。
单行子查询? 单行子查询是指只返回一行数据的子查询语句
请思考:显示与SMITH同部门的所有员工? 思路:
1)查询出SMITH的部门号(返回单行结果集)
select deptno from emp WHERE ename = 'SMITH';
2)显示
SELECT * FROM emp WHERE deptno = (select deptno from emp WHERE ename = 'SMITH');
数据库在执行sql是从左到右扫描的,如果有括号的话,括号里面的先被优先执行。
多行子查询 多行子查询指返回多行数据的子查询。
请思考:如何查询和部门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);
单行子查询是指子查询只返回单列、单行数据,多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句。
请思考如何查询与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的)
这个命令是一种快捷的建表方式
CREATE TABLE mytable (id, name, sal, job, deptno) as SELECT empno, ename, sal, job, deptno FROM emp;
有时在实际应用中,为了合并多个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就是减法的意思)
select * from emp (where) order by sal; // 默认升序 asc
select * from emp order by sal desc, hiredate desc; // sal 相同的 按照 hiredate 降序
聚合函数用法: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中
// 大写 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
日期 - 数字 = 日期
日期 + 数字 = 日期(天)
日期 - 日期 = 数字
// 当前日期
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
// 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
// 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;
// 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, 值 就是 前两列是员工的编号和姓名,后两列是上级领导的编号和姓名