您的位置:首页 > 数据库 > Oracle

oracle基础知识(二)

2012-04-01 13:39 375 查看
第五章 分组函数

-- 分组函数会对结果集中的一组记录计算一次,每一组只返回一个结果

1. MAX(列|表达式) MIN(列|表达式)
练习:查询emp中员工工资的最大值
SELECT MAX(sal), MIN(sal)
FROM emp;

2. SUM -- 求和
AVG -- 取平均值
练习:查询emp表中20部门员工的工资总和
SELECT SUM(sal)
FROM emp
WHERE deptno = 20;
-- 所有的分组函数都是忽略空值
练习:查询emp表中员工平均补助(comm)
SELECT AVG(nvl(comm, 0))
FROM emp;

SELECT 550 *14 FROM dual;
3. COUNT -- 计数
练习:查询emp表中30部门的员工数
SELECT COUNT(*)
FROM emp
WHERE deptno = 30;

练习:查询emp表中员工所在的部门有几个
SELECT COUNT(DISTINCT deptno)
FROM emp;

练习:查询emp表中各个部门的工资的最大值
SELECT deptno, MAX(sal)
FROM emp
GROUP BY deptno
ORDER BY deptno;

练习:查询emp表中各个职位员工工资的平均值
SELECT job, AVG(sal)
FROM emp
GROUP BY job;

-- 必须要使用子查询
练习:查询emp表中各个部门的工资最高的员工的姓名以及工资
SELECT ename, deptno, MAX(sal)
FROM emp
GROUP BY ename, deptno
ORDER BY deptno;

-- 两个原则
-- 1. group by 子句中出现的列,可以不在select子句中出现;
-- 2. select 子句出现的非分组函数列,一定要在group by子句中出现;

练习:查询emp表中平均工资在2000以上的部门编号和平均工资
SELECT deptno, AVG(sal)
FROM emp
--WHERE AVG(sal) > 2000
GROUP BY deptno
HAVING AVG(sal) > 2000;

-- 在where子句中不能出现对分组函数结果的判断
-- 对分组函数结果的筛选需要在having子句中
-- 是SQL语句的执行顺序决定的

练习:查询emp表中员工数多于5人的部门编号以及员工数
SELECT deptno, COUNT(*)
FROM emp
GROUP BY deptno
HAVING COUNT(*) > 5;

-- 分组函数的嵌套(最多嵌套两层)
练习:查询emp表中各部门的平均人数
SELECT AVG(COUNT(*))
FROM emp
GROUP BY deptno;

第六章 多表查询

-- 笛卡尔积
-- A = {a, b}
-- B = {1,2,3}
-- A × B = {(a, 1), (a, 2),(a, 3),(b, 1),(b, 2),(b, 3)}
-- 1. 笛卡尔积元素数量非常庞大,非常耗费系统资源
-- 2. 有意义的数据只占一小部分
-- 结论:在多表查询中一定要避免产生笛卡尔积
-- 方法:一定要为连接的表设定连接条件,两个表连接,至少需要1个连接条件。

-- 连接条件:一般是两个表的公共字段。
-- 公共字段:(狭义)两个表中列名和列的数据类型都相同的那些列;
--                 (广义)两个表中意义相同的那些列

1. 等值连接(连接条件用=来判断的称之为等值连接)

练习:查询emp表中员工姓名,部门编号以及部门名称
SELECT emp.ename, emp.deptno, dept.deptno, dept.dname
FROM emp, dept
WHERE emp.deptno = dept.deptno
ORDER BY emp.ename;
-- 表别名
-- 表名 表别名
-- 表别名中不能包含特殊字符
-- 如果在SQL中给表起了别名了,那么在当前的SQL的任何地方都不能再使用表名,只能
-- 引用表别名

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

2. 不等值连接(连接条件不是用=进行判断)
练习:查询emp表中员工姓名,工资以及工资等级
SELECT e.ename, e.sal, s.grade
FROM emp e, salgrade s
WHERE e.sal BETWEEN s.losal AND s.hisal
ORDER BY e.ename;

练习:查询emp表中20部门员工的姓名,工资,部门名称以及工资等级
SELECT E.ENAME, E.SAL, D.DNAME, S.GRADE
FROM EMP E, DEPT D, SALGRADE S
WHERE E.DEPTNO = D.DEPTNO
AND E.SAL BETWEEN S.LOSAL AND S.HISAL
AND E.DEPTNO = 20;

3. 外连接
-- 外连接的符号(+)永远是在连接条件的缺乏表的一端,要查询哪个表的全部记录,另一张表就是缺乏表
练习:列出所有部门名称和员工的姓名,即使这个部门没有员工
SELECT d.dname, e.ename
FROM emp e, dept d
WHERE e.deptno(+) = d.deptno
ORDER BY d.dname;

练习:查询emp表中员工的姓名和部门编号,即使这个员工没有部门
SELECT d.dname, e.ename
FROM emp e, dept d
WHERE e.deptno = d.deptno(+)
ORDER BY d.dname;

练习:查询没有员工部门的名称
SELECT D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO(+) = D.DEPTNO
AND ENAME IS NULL
ORDER BY D.DNAME;

作业:查询没有部门员工的姓名

4. 自连接
-- 查询结果和条件都需要从同一张表中查询的问题
-- 用自连接
-- 语法晦涩,不常用。
-- 日常工作中我们通常用子查询来代替自连接
练习:查询emp表中和SMITH同部门的员工信息,不包括SMITH
SELECT A.*
FROM EMP A, EMP B
WHERE A.DEPTNO = B.DEPTNO
AND B.ENAME = 'SMITH'
AND A.ENAME <> 'SMITH';

第七章 子查询

-- 查询结果和条件都需要从同一个表中查出来的问题

练习:查询emp表中和SMITH同部门的员工信息,不包括SMITH
SELECT *
FROM EMP
WHERE ENAME <> 'SMITH'
AND DEPTNO = (SELECT DEPTNO FROM EMP WHERE ENAME = 'SMITH');
1. 子查询的分类

a. 单行子查询 - 子查询的结果集是一行一列,可以使用单行比较运算符进行比较
练习:查询emp表中和SCOTT部门相同,且同领导的员工信息,不包括SMITH;
SELECT *
FROM emp
WHERE ename <> 'SCOTT'
AND deptno = (SELECT deptno FROM emp WHERE ename = 'SCOTT')
AND mgr = (SELECT mgr FROM emp WHERE ename = 'SCOTT');

练习:查询emp表中部门人数多于平均部门人数的部门编号和人数
SELECT DEPTNO, COUNT(*)
FROM EMP
GROUP BY DEPTNO
HAVING COUNT(*) > (SELECT AVG(COUNT(*))
FROM EMP
GROUP BY DEPTNO);

b. 多行子查询 - 子查询的结果集是多行一列的,不能使用单行比较运算符,要使用in
练习:查询emp表中哪些员工是领导,列出他们的信息
SELECT *
FROM emp
WHERE empno IN (SELECT mgr FROM emp);

练习:查询emp表中哪些员工不是领导,列出他们的信息
SELECT *
FROM emp
WHERE empno NOT IN (SELECT mgr FROM emp WHERE mgr IS NOT NULL);

-- 1. 子查询结果集中出现了null
-- 2. not in不忽略空值,在子查询中不能出现空值

a IN (1, 2, NULL)
==> a = 1 OR a = 2 OR a = NULL

a NOT IN (1, 2, NULL)
==> a <> 1 AND a <>2 AND a <> NULL

c. 多列子查询 - 查询结果集是多行多列形式
练习:查询emp表中各个部门的工资最高的员工的姓名以及工资
SELECT deptno, ename, sal
FROM emp
WHERE (deptno, sal) IN (SELECT deptno, MAX(sal) FROM emp GROUP BY deptno)
ORDER BY deptno;

(a,b) IN ((1,1), (2,2),(3,3));
==>
a = 1 AND b = 1 OR a = 2 AND b = 2 OR a = 3 AND b = 3;

2. FROM 子句中的子查询 -- 内联视图
- 视图:是一个虚表。视图也是表,所以和表的操作一样。但是视图没有实体数据,只是表的另一种表现方式
-- From子句中的子查询一定要给它起一个别名,作为视图名
-- 如果内联视图中出现了函数列或表达式列,一定要给这样的列起一个别名,就作为对应列的列名
SELECT e.deptno, e.ename, e.sal
FROM emp e, (SELECT deptno, MAX(sal) maxsal FROM emp GROUP BY deptno) a
WHERE e.deptno = a.deptno AND e.sal  = a.maxsal
ORDER BY e.deptno;

练习:查询emp表中各个部门的工资最高的员工的姓名,工资以及部门名称
SELECT e.deptno, e.ename, e.sal, d.dname
FROM emp e, (SELECT deptno, MAX(sal) maxsal FROM emp GROUP BY deptno) a, dept d
WHERE e.deptno = a.deptno AND e.sal  = a.maxsal AND e.deptno = d.deptno
ORDER BY e.deptno;

SELECT B.ENAME, B.SAL, B.DNAME
FROM (SELECT E.ENAME, E.SAL, D.DNAME, E.DEPTNO
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO) B,
(SELECT DEPTNO, MAX(SAL) MAXSAL FROM EMP GROUP BY DEPTNO) A
WHERE A.DEPTNO = B.DEPTNO
AND A.MAXSAL = B.SAL;

-- Top-N问题

-- 伪列 rownum
-- 所有的查询结果集中都有这样一个伪列
-- 作用是给结果集的记录进行编号

SELECT ROWNUM, dname
FROM dept;

-- 1. rownum编号是在排序之前已经编好的。
练习:查询emp表中工资由高到低排在前三位的员工的信息
SELECT rownum, a.ename, a.sal
FROM (SELECT ename, sal FROM emp ORDER BY sal DESC) a
WHERE ROWNUM <= 3;

-- 2. rownum 只能用 < 或<=来判断,不能用>或>=来判断,如果用=判断,只能=1
-- rownum 会动态重新编号
练习:查询emp表中工资由高到低排在4~6位的员工的信息
SELECT b.* FROM (SELECT ROWNUM r,a.ename bname,a.sal bsal FROM
(SELECT ename,sal FROM emp ORDER BY sal DESC
) a WHERE ROWNUM <=6 ) b WHERE b.r>=4

SELECT B.*
FROM (SELECT ROWNUM R, A.ENAME, A.SAL
FROM (SELECT ENAME, SAL FROM EMP ORDER BY SAL DESC) A
WHERE ROWNUM <= 6) B
WHERE B.R >= 4;

-- 分页问题

--

CREATE TABLE TEST(N NUMBER);
表中的数据都是正整数,而且不重复

SELECT * FROM TEST ORDER BY N;

写一个SQL语句查询所有连续号码段的起始和结束号码

minnum        maxnum
3                    5
7                   10
12                 13

1. 方法1
SELECT AA.N MINNUM, BB.N MAXNUM
FROM (SELECT ROWNUM R, A.N
FROM (SELECT N
FROM TEST
WHERE (N - 1) NOT IN (SELECT N FROM TEST)
ORDER BY N) A) AA,
(SELECT ROWNUM R, B.N
FROM (SELECT N
FROM TEST
WHERE (N + 1) NOT IN (SELECT N FROM TEST)
ORDER BY N) B) BB
WHERE AA.R = BB.R;

2. 方法2
数据    -       数列       =      结果
n                  m                   n-m
n+1              m+1               n-m
n+2              m+2               n-m

n+4              m+3               n-m+1
n+5              m+4               n-m+1
n+6              m+5               n-m+1

n+9              m+6              n-m+3
n+10            m+7              n-m+3

SELECT MIN(B.N) MINNUM, MAX(B.N) MAXNUM
FROM (SELECT A.N - ROWNUM R, A.N FROM (SELECT N FROM TEST ORDER BY N) A) B
GROUP BY B.R
ORDER BY MINNUM;

SELECT MIN(A.N) MINNUM, MAX(A.N) MAXNUM
FROM (SELECT N FROM TEST ORDER BY N) A
GROUP BY A.N - ROWNUM
ORDER BY MINNUM;

第八章 数据操作与事务控制

一. 数据插入
练习:向DEPT表中插入记录,编号 50, 部门名称 '实训', 部门所在地 '沈阳'
INSERT INTO dept (dname, deptno, loc) VALUES ('实训', 50, '沈阳');

INSERT INTO dept VALUES (51, '实训', '沈阳');

练习:向DEPT表中插入记录,编号 60, 部门名称 '商用', 部门所在地待定
-- 1. 直接用null关键字
INSERT INTO dept VALUES (60, '商用', NULL);
-- 2. 可以用两个连续的单引号来代表空值
INSERT INTO dept VALUES (61, '商用', '');
-- 3. 可以在指定列表的时候忽略空值列,被忽略的列如果没有设定默认值的话,就会插入空值
INSERT INTO dept (deptno, dname) VALUES (62, '商用');

练习:将自己的信息插入到emp表中(2012-3-5)。
INSERT INTO emp VALUES (9999, 'Liu', 'CLERK', 7788, to_date('2012-3-5', 'YYYY-MM-DD'), 5001, NULL, 10);

- 插入多条数据
INSERT INTO emp1 SELECT * FROM emp WHERE deptno = 30;

二. 更新数据
练习:把emp表中scott的工资更新成3100
UPDATE emp SET sal = 3100 WHERE ename = 'SCOTT';

练习:给emp表中SMITH涨工资100
UPDATE emp SET sal = sal + 100 WHERE ename = 'SMITH';

练习:将SMITH的领导,部门更新跟SCOTT一样
UPDATE emp SET mgr = (SELECT mgr FROM emp WHERE ename = 'SCOTT')
, deptno = (SELECT deptno FROM emp WHERE ename = 'SCOTT')
WHERE ename = 'SMITH';

练习:给30部门工资最低的员工涨100
UPDATE emp SET sal =sal + 100
WHERE deptno = 30 AND sal = (SELECT MIN(sal) FROM emp WHERE deptno = 30);

SELECT * FROM emp;
练习:将自己的部门调到20部门,工资更新成20部门的平均工资 + 100,并四舍五入到个位

三. 删除数据
DELETE [FROM] 表名
[WHERE 条件];

DELETE FROM emp1; -- 删除emp1所有数据

练习:将本部门工资比自己高的员工记录删除
DELETE FROM EMP
WHERE EMPNO IN
(SELECT EMPNO
FROM EMP E, (SELECT DEPTNO, SAL FROM EMP WHERE EMPNO = 9999) A
WHERE E.DEPTNO = A.DEPTNO
AND E.SAL > A.SAL);

第九章 表和约束(DDL)

一. CREATE
-- 作用:创建数据库对象
-- create  DDL语句,隐式提交,不能回滚

CREATE TABLE [SCHEMA.]表名 -- schema方案名(用户名)
(
列名1 数据类型1 [DEFAULT 表达式],
列名2 数据类型2 [DEFAULT 表达式],
...
列名N 数据类型N [DEFAULT 表达式]
);

- 数据类型
-1. 数字型
- NUMBER[(p[, s])]
-  - p 定义了数字的总长度
-  - s 定义了小数位的长度
- 例子  NUMBER(7,2)
-          NUMBER(4)
-          NUMBER

- 2. 字符型
- a. VARCHAR2(n)  - 可变长度的字符类型
-                            - n代表字符串的长度,n一定要设定,不能省略
-                            - n <= 4000

- b. CHAR[(n)]        - 固定长度的字符型
-                            - n可以省略,n默认是1
-                            - n <= 2000

- 3. LOB 型 -- 容纳4GB的数据
- a. 内部lob
- CLOB  -- 4GB字符型数据
- BLOB  -- 4GB二进制数据
- b. 外部lob
- BFILE  -- 4GB的外部文件

- 4. DATE - 日期型

练习:创建一个 dossier表
dID 数字型
dname 可变长度字符型 30
dheight 数字型 3
dbirthday 日期型
dcountrycode 固定长度字符型,默认值是‘01’

CREATE TABLE dossier
(
did NUMBER,
dname VARCHAR2(30),
dheight NUMBER(3),
dbirthday DATE,
dcountrycode CHAR(2) DEFAULT '01'
);

DROP TABLE dossier

INSERT INTO dossier VALUES (1, '姚明', 226, to_date('1980-10-6', 'YYYY-MM-DD'), DEFAULT);

COMMIT;

INSERT INTO dossier (did, dname, dheight, dbirthday) VALUES (1, '姚明', 226, to_date('1980-10-6', 'YYYY-MM-DD'));

SELECT * FROM dossier;

- 子查询建表
CREATE TABLE 表名 AS 子查询;

CREATE TABLE emp2 AS SELECT * FROM emp WHERE deptno =10;

SELECT * FROM emp2;

练习:用20部门员工的姓名和年薪 创建一个新表 annemp20
CREATE TABLE annemp20
AS
SELECT ename, (sal + NVL(comm, 0)) * 12 annsal
FROM emp
WHERE deptno = 20;

SELECT * FROM User_Tables;

SELECT ROWID, dname
FROM dossier;

二. ALTER
-- 属于DDL语句,自动提交,不能回滚
-- 修改对象的属性
1. 添加列
ALTER TABLE 表名 ADD (列名 数据类型[,...]);

练习:在dossier表中添加一列 sex 列,1位长度固定长度字符型
ALTER TABLE dossier ADD (sex CHAR);

2. 修改列
ALTER TABLE 表名 MODIFY (列名 属性值);
-- 1. 列名一定是在表中存在的列
-- 2. 修改那些属性,就把哪些属性放在列名后面就可以了

练习:为sex列添加默认值,默认为‘1’
ALTER TABLE dossier MODIFY (sex DEFAULT '1');
-- 默认值的修改对表中现有列数据没有任何影响
-- 只会影响以后插入的数据。

-- 将某列更新成其默认值
UPDATE dossier
SET sex = DEFAULT
WHERE did = 1;

3. 删除列
1> ALTER TABLE 表名 DROP COLUMN 列名;
2> ALTER TABLE 表名 DROP (列名列表);

练习:删除表中sex列
ALTER TABLE dossier DROP (sex);
-- 注意:删除列会将列的定义和数据一并删除,不能回滚,在使用之前一定要慎重
-- 必要的时候要现将表中数据备份后再删除。
-- 表中必须至少要含有一列。

三. DROP
-- DDL语句,隐式提交不能回滚
-- 删除数据库对象

DROP TABLE 表名;

DROP TABLE emp1;

四. 重命名表
RENAME oldname TO NEWname;

RENAME dossier TO ouxiang;

SELECT *
FROM dossier;

五. TRUNCATE

TRUNCATE TABLE 表名;
-- 截断:删除表中所有的数据;

TRUNCATE TABLE emp2;

DELETE FROM emp2;

-- 两种语句的区别
-- 1. truncate是DDL语句,自动提交,不能回滚,而Delete是DML语句,能回滚;
-- 2. truncate在删除数据的同时,会释放存储空间,delete不会做这样的事;
-- 3. truncate只能删除所有数据,delete是可以有选择的删除;
-- 4. truncate的效率要远远的高于delete,表越大越明显。

回滚段

五. 约束
定义在表中某列上的规则,防止错误数据进入表中;

1. 五种约束
1> NOT NULL :非空约束,插入到该列的数据不能为null;
2> UNIQUE     : 唯一键 约束,  该列数据在表中是唯一的,即不能重复;
3> PRIMARY KEY: 主键约束。表中的列或列的组合,其值在表中 可以唯一的确定一条记录;
一个表只能有一个主键。
主键的值必须是非空且唯一的。
在表设计的时候,所有的表必须有主键。

4> FOREIGN KEY : 外键约束。表A和表B的公共字段如果是表A的主键或唯一键的话,那么
就是表B的外键。表A通常成为父表,表B称为子表。 外键是定义在子表上的。

i. 子表的公共字段中不能出现父表中没有的值
UPDATE emp SET deptno = 90 WHERE empno = 7788;
ii. 如果父表中的某一个值被子表所引用的话,这条数据不能被删除;
DELETE FROM dept WHERE deptno = 10;

5> CHECK :检查约束。在某列上定义的一个boolean表达式,要求插入到该列的值必须要保证
boolean表达式为真,否则无法插入。

2. 约束定义
1> 列级约束定义
CREATE TABLE dossier
(
did NUMBER PRIMARY KEY,
dname VARCHAR2(30) NOT NULL,
dheight NUMBER(3) UNIQUE,
dbirthday DATE,
dcountrycode CHAR(2) DEFAULT '01' REFERENCES country(countrycode)
);

2> 表级约束定义
CONSTRAINT 约束名 约束类型(列名)

CREATE TABLE dossier
(
did NUMBER,
dname VARCHAR2(30),
dheight NUMBER(3),
dbirthday DATE NOT NULL,
dcountrycode CHAR(2) DEFAULT '01',
CONSTRAINT dossier_did_pk PRIMARY KEY(did),
CONSTRAINT dossier_dname_uk UNIQUE(dname),
CONSTRAINT dossier_dheight_ck CHECK(dheight > 0),
CONSTRAINT dossier_countycode_fk FOREIGN KEY(dcountrycode)
REFERENCES county(countrycode)
);
-- not null只能做列级的约束定义,不能做表级的约束定义

练习:创建一个country表
countrycode 两个字符长度固定字符类型 主键
countryname 非空

CREATE TABLE country
(
countrycode CHAR(2),
countryname VARCHAR2(30) NOT NULL,
CONSTRAINT county_code_pk PRIMARY KEY(countrycode)
);

INSERT INTO country VALUES('01', '中国');

SELECT * FROM country;

3> 给现有的表添加约束
ALTER TABLE 表名 ADD [CONSTRAINT 约束名] 约束类型(列名);

练习:给dossier表添加主键约束
ALTER TABLE dossier ADD CONSTRAINT dossier_did_pk PRIMARY KEY(did);

练习:给dossier表的dname列,添加唯一键约束
ALTER TABLE dossier ADD CONSTRAINT dossier_dname_uk UNIQUE(dname);

练习:给dossier表添加check约束,身高不能小于0
ALTER TABLE dossier ADD CONSTRAINT dossier_dheight_ck CHECK(dheight > 0);

练习:给dossier表的生日列添加非空约束
-- ALTER TABLE dossier ADD CONSTRAINT dossier_dbirthday_nn NOT NULL(dbirthday);
ALTER TABLE dossier MODIFY (dbirthday NOT NULL);

ALTER TABLE dossier ADD CONSTRAINT dossier_dbirthday_ck CHECK (dbirthday IS NO NULL);

练习:给dossier表添加外键约束
ALTER TABLE dossier ADD CONSTRAINT dossier_dcountrycode_fk
FOREIGN KEY(dcountrycode) REFERENCES country(countrycode);

4> 删除约束
ALTER TABLE 表名 DROP CONSTRAINT 约束名;

练习:删除dossier表的唯一键约束
ALTER TABLE dossier DROP CONSTRAINT dossier_dname_uk;

练习:删除country表的主键约束
ALTER TABLE country DROP CONSTRAINT county_code_pk CASCADE;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息