Oracle SQL大全

-- 建表
CREATE TABLE ab_student (
id number(4)
)
create table ab_class(
id number(4),
name varchar2(20)
)
-- 修改表
ALTER TABLE ab_student ADD(classid number(4))
ALTER TABLE ab_student ADD(birthday date)
ALTER TABLE ab_student MODIFY(classid number(4))
ALTER TABLE ab_student DROP  COLUMN classid
RENAME ab_student TO ab_student2

-- 删除表
DROP TABLE ab_student
DROP TABLE ab_class

-- 增加一条数据
INSERT INTO ab_student(id, birthday) VALUES(2, '02-8月-13')
ALTER SESSION SET nls_date_format='yyyy-mm-dd'
INSERT INTO ab_student(id, birthday) VALUES(3, '2013-08-05')
INSERT INTO ab_student(id, birthday) VALUES(4, '2014-05-05')
INSERT INTO ab_student(id, birthday) VALUES(5, '1992-05-25')
INSERT INTO ab_student(id) VALUES(10 )

-- 删除一条数据
DELETE FROM ab_student WHERE id = 1
-- 删除所有记录,表结构还在,写日志,可以恢复的,速度慢
DELETE FROM ab_student
-- delete的数据可以恢复,一个有经验的dba,在确保完成无误的情况下要定期创建还原点。
SAVEPOINT sp_201308020941 -- 创建保存点
DELETE FROM ab_student
ROLLBACK TO sp_201308020941 -- 恢复到保存点

SELECT * FROM ab_student
SELECT * FROM ab_student WHERE birthday IS NULL
SELECT * FROM ab_student WHERE birthday IS NOT NULL

-- 连接查询
INSERT INTO ab_class(id, name) VALUES(1, '软件班')
INSERT INTO ab_class(id, name) VALUES(2, '软测班')
INSERT INTO ab_class(id, name) VALUES(3, '多媒体班')
INSERT INTO ab_class(id, name) VALUES(5, '网络班')
SELECT * FROM ab_student
SELECT * FROM ab_class
-- 内连接
SELECT *
FROM ab_student a
INNER JOIN ab_class b ON b.id = a.classid
-- 左外连接
SELECT *
FROM ab_student a
LEFT OUTER JOIN ab_class b ON b.id = a.classid
-- 右外连接
SELECT *
FROM ab_student a
RIGHT OUTER JOIN ab_class b ON b.id = a.classid
-- 交叉连接
SELECT *
FROM ab_student a
CROSS JOIN ab_class b

UPDATE ab_student SET birthday = '1992-05-25' WHERE id = 3
UPDATE ab_student SET classid =1 WHERE id = 3
UPDATE ab_student SET classid =3 WHERE id = 5
UPDATE ab_student SET classid =5 WHERE id = 10

DROP TABLE ab_student --删除表的结构和数据;
DELETE FROM ab_student where id = 1 --删除一条记录;
TRUNCATE TABLE ab_student --删除表中的所有记录,表结构还在,不写日志,无法找回删除的记录,速度快。

二、 表的使用技巧

-- 1. 查看表结构
DESC SCOTT.EMP
SELECT * FROM user_tab_columns WHERE table_name= 'EMP'
GO
SELECT 'SCOTT.EMP' FROM all_tables -- 所有用户的表 
GO
-- 2 表复制语句
CREATE TABLE SCOTT.AA_DEPT (
    DEPTNO     NUMBER(2,0) NOT NULL,
    DNAME      VARCHAR2(14) NULL,
    LOC        VARCHAR2(13) NULL,
    CONSTRAINT PK_AA_DEPT PRIMARY KEY(DEPTNO)
     NOT DEFERRABLE
     VALIDATE
)
GO
INSERT INTO TABLE aa_dept(deptno, dname, loc)
SELECT a.deptno, a.dname, a.loc FROM DEPT a
GO
SELECT deptno, dname, loc FROM AA_DEPT
-- 3. 用查询结果创建新表,这个命令是一种快捷的建表方式
CREATE TABLE AB_DEPT (id, name, sal, job, deptno) AS SELECT empno, ename, sal, job, deptno FROM emp
SELECT * FROM AB_DEPT

三、 SQL基本查询技巧

-- 1. 查询所有
SELECT * FROM EMP
-- 2.使用WHERE子句
-- 查询smith所在部门,工作,薪水
SELECT deptno, job, sal FROM emp WHERE ename = 'SMITH'
-- 显示工资高于三千的员工
SELECT ename, sal FROM emp WHERE sal > 3000
-- 如何查找1982.1.1后入职的员工
ALTER SESSION SET nls_date_format='yyyy-mm-dd'
SELECT ename, hiredate FROM emp WHERE hiredate > '1982-01-01'
-- 如何显示工资在2000到3000的员工
SELECT ename, sal FROM emp WHERE sal >= 2000 AND sal <= 3000
-- 3. 使用IN 
        -- 如何显示empno为7844,7839,123,456的雇员情况?
SELECT * FROM emp WHERE empno IN (7844, 7839, 123, 456)
-- 4. 排除重复行DISTINCT
SELECT DISTINCT  deptno, job FROM emp
-- 5. 使用列的别名AS
SELECT ename AS "姓名" , sal * 12 AS "年收入" FROM emp
-- 6. 连接字符串||
SELECT ename || ' is a ' || job FROM emp
-- 7. 使用LIKE关键字,%:表示0到多个字符 _:表示任意单个字符
-- 如何显示首字符为s的员工姓名和工资?
SELECT ename,sal FROM emp WHERE ename like 'S%'
-- 如何显示第三个字符为大写o的所有员工的姓名和工资?
SELECT ename,sal FROM emp WHERE ename LIKE '__O%'
-- 8. 使用内置函数
-- nvl()函数
/* 格式为:nvl(string1, replace_with) 
功能:如果string1为null,则nvl函数返回replace_with的值,否则返回string1的值。 */
SELECT sal * 13 + NVL(comm, 0) * 13 AS "年薪", ename, comm FROM emp
-- 如何显示没有上级的雇员的情况
SELECT ename,mgr FROM emp WHERE mgr IS NULL
-- count()函数
SELECT COUNT(*) FROM emp
-- 9. 使用逻辑操作符号
-- 问题:查询工资高于500或者是岗位为manager的雇员,同时还要满足他们的姓名首字母为大写的J?
SELECT * FROM emp WHERE (sal > 500 Or job = 'MANAGER') AND ename LIKE 'J%'
-- 10. 使用order by字句 默认asc
-- 问题:如何按照工资从低到高的顺序显示雇员的信息?
SELECT * FROM emp ORDER BY sal
-- 问题:按照部门号升序而雇员的工资降序排列
SELECT * FROM emp ORDER BY deptno ASC, sal DESC
-- 11. 使用列的别名排序
-- 问题:按年薪排序
SELECT ename, (sal + NVL(comm, 0)) * 12 AS "年薪" FROM emp ORDER BY "年薪" ASC
-- 12. 聚合函数用法:max,min,avg,sum,count
-- 问题:如何显示所有员工中最高工资和最低工资?
SELECT MAX(sal), MIN(sal) FROM emp e
-- 最高工资那个人是谁?
SELECT ename, sal FROM emp WHERE sal = (SELECT MAX(sal) FROM emp)
/*
错误写法:select ename, sal from emp where sal=max(sal)
注意:select ename, max(sal) from emp;这语句执行的时候会报错,说ora-00937:非单组分组函数。因为max是分组函数,而ename不是分组函数.......
但是select min(sal), max(sal) from emp;这句是可以执行的。因为min和max都是分组函数,就是说:如果列里面有一个分组函数,其它的都必须是分组函数,否则就出错。这是语法规定的
*/
-- 问题:如何显示所有员工的平均工资和工资总和
SELECT AVG(e.sal) AS "所有员工平均工资", SUM(e.sal) AS "所有员工工资总和" FROM emp e
-- 查询最高工资员工的名字,工作岗位
SELECT e.ename, e.job FROM emp e WHERE e.sal = (SELECT MAX(sal) FROM emp)
-- 显示工资高于平均工资的员工信息
SELECT e.ename FROM emp e WHERE e.sal > (SELECT AVG(sal) FROM emp)
-- 13. GROUP BY的用法
-- 问题:如何显示每个部门的平均工资和最高工资?
SELECT  AVG(sal) AS "平均工资", MAX(sal) AS "最高工资", deptno
FROM emp
GROUP BY deptno
--(注意:这里暗藏了一点,如果你要分组查询的话,分组的字段deptno一定要出现在查询的列表里面,否则会报错。因为分组的字段都不出现的话,就没办法分组了)
-- 问题:显示每个部门的每种岗位的平均工资和最低工资?
SELECT AVG(sal) AS "平均工资", MIN(sal) AS "最低工资", deptno, job
FROM emp
GROUP BY deptno, job
-- 问题:显示平均工资低于2000的部门号和它的平均工资?
SELECT AVG(sal), deptno
FROM emp
GROUP BY deptno
HAVING AVG(sal) < 2000
/*
对数据分组的总结
(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中
*/
-- 14. 多表查询
-- 显示雇员名,雇员工资及所在部门的名字
SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno
-- 问题:显示部门号为10的部门名、员工名和工资
SELECT d.deptno , d.dname, e.deptno, e.empno, e.ename, e.sal FROM emp e, dept d WHERE 1 = 1 AND e.deptno = d.deptno AND d.deptno = 10
-- 问题:显示雇员名,雇员工资及所在部门的名字,并按部门排序
SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno ORDER BY e.deptno ASC
-- 自连接。自连接是指在同一张表的连接查询
-- 问题:显示某个员工的上级领导的姓名?比如显示员工‘FORD’的上级
SELECT  worker.ename, boss.ename FROM emp worker, emp boss WHERE worker.mgr = boss.empno AND worker.ename = 'FORD'
-- 15. 单行子查询?
-- 单行子查询是指只返回一行数据的子查询语句
-- 请思考:显示与SMITH同部门的所有员工?
SELECT e.deptno, e.ename
FROM emp e
WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SMITH')
-- 16. 多行子查询
-- 多行子查询指返回多行数据的子查询
-- 请思考:如何查询和部门10的工作相同的雇员的名字、岗位、工资、部门号
SELECT e.ename, e.job, e.sal, e.deptno
FROM emp e
WHERE e.job IN(SELECT job FROM emp WHERE deptno = 10)
--  在多行子查询中使用all操作符
-- 问题:如何显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号?
SELECT e.ename, e.sal, e.deptno
FROM emp e
WHERE e.sal > ALL(SELECT sal FROM emp WHERE deptno = 30)

SELECT e.ename, e.sal , e.deptno
FROM emp e
WHERE e.sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30)
-- 17. 合并查询
/*有时在实际应用中,为了合并多个select语句的结果,可以使用集合操作符号union,union all,intersect,minus。
多用于数据量比较大的数据局库,运行速度快。*/
1). union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。
2).union all
该操作符与union相似,但是它不会取消重复行,而且不会排序。
3). intersect
使用该操作符用于取得两个结果集的交集。
4). minus
使用该操作符用于取得两个结果集的差集,他只会显示存在第一个集合中,而不存在第二个集合中的数据。
SELECT ename, sal, job FROM emp WHERE sal > 2500
/* UNION */ /*  UNION ALL */ /* INTERSECT */ MINUS
SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'

四、分页查询

1. 方法一 根据rowid来分

SELECT *
FROM EMP
WHERE ROWID IN
       (SELECT RID
          FROM (SELECT ROWNUM RN, RID
                  FROM (SELECT ROWID RID, EMPNO FROM EMP ORDER BY EMPNO DESC)
                 WHERE ROWNUM <= 5
         WHERE RN > 0 
 ORDER BY EMPNO DESC

2. 方法二 按分析函数来分

SELECT *
FROM (SELECT T.*, ROW_NUMBER() OVER(ORDER BY empno DESC) RK FROM emp T)
WHERE RK <= 5
AND RK > 0

3. 方法三 按rownum 来分

SELECT *
FROM (SELECT T.*, ROWNUM RN
          FROM (SELECT * FROM EMP ORDER BY EMPNO DESC) T
         WHERE ROWNUM <= 5)
WHERE RN > 0

五、 复杂表查询

1、查询每个职员的姓名、工种、入社日期,工资和年工资。

SELECT e.ename,e.job,e.hiredate,e.sal,e.sal*12 FROM emp e

2、查找部门平均工资在2000元以上的部门号和部门名称,按平均工资的降序排列。

SELECT v.deptno,v.dname
FROM (
        SELECT AVG(e.sal) avgsal, d.deptno, d.dname
        FROM emp e
        LEFT JOIN dept d ON e.deptno=d.deptno
        GROUP BY e.deptno,d.deptno,d.dname) v
WHERE v.avgsal > 2000

3、查找营业部(SALES)比研究部(RESEARCH)平均工资都高的职员的情况。(要求使用子查询来完成)

SELECT e.*
FROM emp e
LEFT JOIN dept d ON e.deptno=d.deptno
WHERE d.dname='SALES' AND e.sal > (
      SELECT DISTINCT AVG(e.sal) OVER (PARTITION BY e.deptno)
      FROM emp e
      LEFT JOIN dept d ON e.deptno=d.deptno
      WHERE d.dname='RESEARCH' )

4、在EMP表的MGR属性列上建一个名为mgr_bit的位图索引。

CREATE BITMAP INDEX mgr_bit ON emp(mgr)

5、查询各个部门的最高工资的职员情况

SELECT e.ename, e.job, e.sal, e.deptno 
FROM emp
WHERE (sal,deptno) IN (SELECT MAX(e.sal), e.deptno FROM emp e GROUP BY e.deptno)

SELECT e.ename, e.job, e.sal, e.deptno
FROM scott.emp e, (select e.deptno, MAX(e.sal) sal from scott.emp e group by e.deptno) me
WHERE e.deptno = me.deptno AND e.sal = me.sal;

SELECT e.ename, e.job, e.sal, e.deptno
FROM (SELECT e.ename,
               e.job,
               e.sal,
               e.deptno,
               RANK() OVER(PARTITION BY e.deptno ORDER BY e.sal desc) RANK FROM scott.emp e) e
 WHERE e.rank = 1;

SELECT e.ename, e.job, e.sal, e.deptno
FROM (SELECT e.ename,
               e.job,
               e.sal,
               e.deptno,
               DENSE_RANK() OVER(PARTITION BY e.deptno ORDER BY e.sal desc) RANK FROM scott.emp e) e
 WHERE e.rank = 1;
6、 查询各个部门的最高工资的职员情况,同时算出雇员工资与部门最高/最低工资的差额
select e.ename,
         e.job,
         e.sal,
         e.deptno,
         e.sal - me.min_sal diff_min_sal,
         me.max_sal - e.sal diff_max_sal
    from scott.emp e,
         (select e.deptno, min(e.sal) min_sal, max(e.sal) max_sal
            from scott.emp e
           group by e.deptno) me
   where e.deptno = me.deptno
   order by e.deptno, e.sal;

select e.ename,
       e.job,
       e.sal,
       e.deptno,
       nvl(e.sal - min(e.sal) over(partition by e.deptno), 0) diff_min_sal,
       nvl(max(e.sal) over(partition by e.deptno) - e.sal, 0) diff_max_sal
  from scott.emp e;
7、 计算个人工资与比自己高一位/低一位工资的差额
select e.ename,
       e.job,
       e.sal,
       e.deptno,
       lead(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lead_sal,
       lag(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lag_sal,
       nvl(lead(e.sal) over(partition by e.deptno order by e.sal) - e.sal,
           0) diff_lead_sal,
       nvl(e.sal - lag(e.sal) over(partition by e.deptno order by e.sal), 0) diff_lag_sal
  from scott.emp e; 

8、查询各个部门比平均工资高的员工

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

9、 显示deptno和job唯一的员工薪资,并按降序排列

SELECT a.ename, a.sal, a.deptno, a.job
FROM emp a
WHERE a.empno in
(
SELECT MAX(e.empno)  
FROM emp e
GROUP BY e.deptno,e.job
)
ORDER BY a.sal DESC

SELECT a.ename, a.sal, a.deptno, a.job
FROM emp a, (
SELECT MAX(e.rowid) AS myrowid, e.deptno, e.job, count(*)
FROM emp e
GROUP BY e.deptno,e.job
HAVING count(*) >= 1
) me
WHERE a.rowid IN me.myrowid
ORDER BY a.sal DESC