列别名:
当SELECT子句中一个字段是函数或者表达式,那么在结果集中该字段的名字就是这个函数或表达式,可读性差,为此可以为列提供一个别名,这样在结果集中会使用该别名作为该字段的名字。应当养成一个好习惯,即:凡是表达式或函数都指定一个别名。
别名本身不区分大小写,若希望别名区分大小写或者别名中包含空格,那么需要使用双引号将其括起来。
SELECT ename,sal+NVL(comm,0) "sal"FROM emp
OR,AND用于连接多个条件使用:
OR的优先级低于AND,所以若希望提高OR的优先级,可以使用括号。查看工资高于1000,并且职位是CLERK或者SALESMAN的员工?
SELECT
ename,job,sal
FROM
emp
WHERE
sal>1000
AND
(job='SALESMAN' OR job='CLERK')
LIKE用于模糊匹配字符串支持两个通配符:
%:0-多个字符(任意个字符)
_:单一的一个字符
查看名字第二个字母是A的员工?
SELECT
ename,sal,deptno
FROM
emp
WHERE
ename LIKE '_A%'
IN(list) 和 NOT IN(listr)判断在列表中和不在列表中
IN,NOT IN常被用在子查询上使用。
查看职位是CLERK和SALESMAN的员工?
SELECT
ename,job,sal
FROM
emp
WHERE
job IN('CLERK','SALESMAN')
BETWEEN...AND...判断在一个区间范围内:
查看工资在1500到3000之间的员工?
SELECT
ename,sal
FROM
emp
WHERE
sal BETWEEN 1500 AND 3000
查看工资在1000-3000之间,20和30号部门名字中含有A的员工?
SELECT
ename,sal,deptno,job
FROM
emp
WHERE
sal BETWEEN 1000 AND 3000 AND deptno IN (20,30) AND ename LIKE '%A%'
ANY(list),ALL(list):
ANY,ALL是配合>,>=,<,<=使用的
>ANY(list):大于列表之一,大于最小
>ALL(list):大于列表所有,大于最大
实际意义,它们通常配合子查询使用。
SELECT
empno, ename, job,sal, deptno
FROM
emp
WHERE sal>ANY(3500,4000,4500)
DISTINCT关键字:
DISTINCT可以将结果集中指定字段值一样的记录去重。
查看公司有哪些职位?
SELECT DISTINCT job FROM emp
可以按照多字段去重,那么这些字段值的组合没有重复记录出现在结果集中。
SELECT DISTINCT deptno,job FROM emp
ORDER BY子句:
ORDER BY用于对查询的结果集按照指定
字段的值进行排序。
排序分为:升序(ASC),降序(DESC).
默认为升序
ORDER BY子句必须定义在SELECT语句中
的最后一个子句上。
查看公司中工资的排名?
SELECT
ename,sal,job
FROM
emp
ORDER BY
sal DESC
查看20号部门的工资排名?
SELECT
ename,sal,deptno
FROM
emp
WHERE
deptno=20
ORDER BY
sal DESC
多字段排序时,ORDER BY是有排序的优先级的,首先按照第一个字段先进行排序,当该字段中有记录值重复时,再将这些记录按照第二个字段排序。依此类推。
SELECT
ename,deptno,sal
FROM
emp
ORDER BY
deptno DESC,sal DESC
若排序的字段中含有NULL值,NULL被认定为最大值。
SELECT ename,comm FROM emp ORDER BY comm
聚合函数:
聚合函数又称为分组函数,多行函数。聚合函数的作用是对结果集指定字段的值进行统计工作的。MAX(),MIN(),SUM(),AVG()求最大值,最小值,总和,平均值,还有一个是对记录数的统计COUNT()。
查看公司的最高工资是多少?
SELECT MAX(sal) FROM emp
SELECT MAX(sal),MIN(sal),SUM(sal),AVG(sal) FROM emp
查看公司共多少人?
SELECT COUNT(ename) FROM emp
SELECT COUNT(*) FROM emp
SELECT COUNT(1) FROM emp
聚合函数忽略NULL值。
SELECT SUM(comm),AVG(comm)FROM emp
SELECT AVG(NVL(comm,0)) FROM emp
分组:
GROUP BY子句
GROUP BY子句可以将结果集按照给定的字段值一样的记录进行分组。配合聚合函数使用可以完成分组统计工作。
查看每个部门的平均工资?
SELECT
AVG(sal),deptno
FROM
emp
GROUP BY deptno
当SELECT中含有聚合函数时,那么凡不在聚合函数中的单独字段,都需要出现在GROUP BY子句中。
查看每种职位的最高工资与最低工资是多少?
SELECT
MAX(sal),MIN(sal),job
FROM
emp
GROUP BY job
GROUP BY按照多字段分组时,是将这些字段值组合一样的记录看做一组。
统计同部门同职位的员工的各多少人?
SELECT
COUNT(*),deptno,job
FROM
emp
GROUP BY deptno,job
查看部门的平均工资,前提是该部门的平均工资高于2000
SELECT
AVG(sal),deptno
FROM
emp
WHERE
AVG(sal)>2000
GROUP BY deptno
上面的SQL语句会抛出异常,WHERE子句中是不能使用聚合函数做为过滤条件的,原因在于过滤的时机不对。WHERE是伴随查询表中数据逐行进行过滤使用的,用来确定结果集中可以查询出的条目数。而聚合函数是建立在查询出来的数据基础上进行统才能得到结果,所以使用聚合函数过滤应当是在WHERE之后进行的。HAVING子句可以根据聚合函数进行过滤,并且是用来根据条件过滤 GROUP BY的分组。HAVING不能单独出现,不定义GROUP BY子句不能单独出现HAVING子句。
查看部门的平均工资,前提是该部门的平均工资高于2000
SELECT
AVG(sal),deptno
FROM
emp
GROUP BY
deptno
HAVING
AVG(sal)>2000
查看平均工资高于2000的那些部门的最高工资是多少?
SELECT
MAX(sal),deptno
FROM
emp
GROUP BY
deptno
HAVING
AVG(sal)>2000
关联查询
关联查询的结果集中的字段来自多张表。这就需要在查询的时候联合多张表进行查询,根据给定的连接条件将表与表的数据建立对应关系,再分别从这些记录中提取要查询的字段来形成结果集中的每条记录。
查看每个员工的名字以及其所在部门的名字?
SELECT
ename,dname
FROM
emp,dept
WHERE
emp.deptno=dept.deptno
当在关联查询中要查询的字段在这些表中都出现时,需要使用表名来明确字段所属表。可以为表名取一个别名来简化复杂度。
SELECT
e.ename,e.deptno,d.dname
FROM
emp e,dept d
WHERE
e.deptno=d.deptno
在进行关联查询时若有过滤要求,那么过滤条件必须与连接条件同时成立。
查看在NEW YORK工作的员工都有谁?
SELECT
e.ename,e.deptno,d.dname,d.loc
FROM
emp e,dept d
WHERE
e.deptno=d.deptno AND d.loc='NEW YORK'
关联查询中不指定连接条件或者连接条件无效时,会产生笛卡尔积,这通常是一个无意义的结果集。
SELECT e.ename,d.dname FROM emp e, dept d
N表查询至少要有N-1个连接条件。
内连接
内连接也是用来完成关联查询的。采用JOIN...ON...的形式关联多表。
查看每个员工的名字以及其所在部门名称?
SELECT e.ename,d.dname FROM emp e,dept d WHERE e.deptno=d.deptno
内连接写法:
SELECT
e.ename,d.dname
FROM
emp e
JOIN
dept d
ON
e.deptno = d.deptno
不满足关联条件的记录不会被查询出来。
外链接
外链接在关联查询中除了可以将满足连接条件的记录查询出来之外,还可以将不满足连接条件的记录也列出来。
外链接分为:
左外连接,右外连接,全外连接
左外连接:以JOIN左侧表做为驱动表,该表记录都要查询出来,当某条记录不满足连接条件时,那么在结果集中该条记录来自JOIN右侧表的字段的值全部为NULL。
SELECT
e.ename,e.job,e.sal,d.dname,d.loc
FROM
emp e
LEFT|RIGHT|FULL OUTER JOIN
dept d
ON
e.deptno=d.deptno
SELECT
e.ename,d.dname
FROM
emp e,dept d
WHERE
e.deptno(+)=d.deptno
自连接
自连接指的是当前表的一条数据可以对应当前表自己的多条数据。
自连接是为了解决数据的属性相同,但是本身又存在上下级关系的树状结构数据。查看每个员工以及其领导的名字?
SELECT
e.ename,m.ename
FROM
emp e,emp m
WHERE
e.mgr=m.empno(+)
SELECT
e.ename,m.ename
FROM
emp e
LEFT OUTER JOIN
emp m
ON
e.mgr=m.empno
子查询
子查询是一条查询语句,它是嵌套在其他SQL语句中的,目的是将查询的结果提供给外层的SQL语句。
查看谁的工资高于CLARK的工资?
SELECT
ename,sal FROM emp
WHERE
sal>(SELECT sal FROM emp WHERE ename='CLARK')
查看与CLARK同部门的员工?
SELECT
ename,deptno
FROM
emp
WHERE
deptno=(SELECT deptno FROM emp WHERE ename='CLARK')
AND
ename<>'CLARK'
查看高于公司平均工资的员工?
SELECT
ename,sal
FROM
emp
WHERE
sal>(SELECT AVG(sal) FROM emp)
在DDL中使用子查询,可以将一个子查询的结果集当做表快速创建出来。
CREATE TABLE
employee
AS
SELECT e.empno,e.ename,e.sal,e.job,d.deptno,d.dname,d.loc
FROM
emp e,dept d
WHERE
e.deptno=d.deptno(+)
在使用子查询创建表的时候,查询多少个字段创建的表就有多少个字段,字段名与查询的字段名字一致(不含有表别名),类型,长度也一致。但是需要注意的是,若查询的字段是函数或者表达式,那么这个字段必须指定别名,并且生成的表对应的该字段名就是这个别名。
DML中使用子查询
将CLARK所在部门的员工工资上浮10%
UPDATE
emp
SET
sal=sal*1.1
WHERE
deptno=(SELECT deptno FROM emp WHERE ename='CLARK')
子查询根据查询结果分为:
单行单列,多行单列,多行多列子查询其中单列子查询常用在过滤条件中多列子查询常被当做表使用。
对于多行单列子查询在进行过滤判断时,需要配合IN,ANY,ALL使用。
查看与职位是SALESMAN同部门的员工?
SELECT
ename,job,deptno
FROM
emp
WHERE
deptno IN (SELECT deptno FROM emp WHERE job='SALESMAN')
AND
job<>'SALESMAN'
查看比职位是SALESMAN和CLERK工资都高的员工?
SELECT
ename,sal,job
FROM
emp
WHERE
sal>ALL(SELECT sal FROM emp WHERE job IN('SALESMAN','CLERK'))
SELECT deptno, dname FROM dept d
EXISTS关键字
EXISTS用在WHERE中进行过滤,其后跟一个子查询,只要该子查询至少可以查询出一条记录,那么则该条件为true.
查看有下属的员工?
SELECT
m.ename,m.job,m.sal
FROM
emp m
WHERE
EXISTS(SELECT * FROM emp e WHERE e.mgr = m.empno)
HAVING中使用子查询:
查看每个部门的最低薪水,前提是要高于30号部门的最低薪水?
SELECT
MIN(sal),deptno FROM emp
GROUP BY
deptno
HAVING
MIN(sal)>(SELECT MIN(sal) FROM emp WHERE deptno=30)
在FROM中使用子查询通常多列子查询在FROM子句中出现,作用是当做一张表使用。
查看高于自己所在部门平均工资的员工?
SELECT
e.ename,e.sal,e.deptno
FROM
emp e,(SELECT deptno,AVG(sal) avg_sal FROM emp GROUP BY deptno) x
WHERE
e.deptno=x.deptno AND e.sal>x.avg_sal
分页查询:
分页查询就是将表中要查询出来的数据分批分段查询出来。这样做的好处是当查询的数据量过大时可以减少内存开销,
提高系统响应速度,减少网络传输。分页是方言,不同数据库都提供了分页查询的机制,但是语法定义各不相同。
ORACLE是依靠提供了一个伪列:ROWNUMROWNUM不存在于任何一张表中,但是每张表都可以查询该字段,该字段在结果集中的值就是每条记录的行号。而行号的生成是伴随查询过程进行的,只要可以从表中查询出一条记录,ROWNUM字段就是为该条记录在结果集中产生对应的行号,从1开始递增。
需要注意,在使用ROWNUM对结果集编行号的过程中,不要使用ROWNUM做大于1以上数字的判断,否则得不到结果。
SELECT
ROWNUM,ename,job,sal
FROM
emp
WHERE
ROWNUM >1
SELECT
*
FROM
(SELECT ROWNUM rn,ename,job,sal FROM emp)
WHERE
rn BETWEEN 6 AND 10
查看公司工资排名的第6-10名
SELECT
*
FROM
(SELECT ROWNUM rn,t.* FROM(SELECT ename,job,sal FROM emp ORDER BY sal DESC) t)
WHERE
rn BETWEEN 6 AND 10
SELECT
*
FROM
(SELECT ROWNUM rn,t.* FROM(SELECT ename,job,sal FROM emp ORDER BY sal DESC) t WHERE ROWNUM <=10 )
WHERE
rn >= 6
换算范围的公式:
PageSize:每页可以显示的条目数
Page:页数
start:(Page-1)*PageSize + 1
end:PageSize*Page
DECODE函数
DECODE函数可以实现分支结构
SELECT
ename, job, sal,DECODE(job,'MANAGER', sal * 1.2,'ANALYST', sal * 1.1,'SALESMAN', sal * 1.05,sal) bonus
FROM
emp;
DECODE在GROUP BY中可以实现将字段不同值的记录分为一组。
将职位是ANALYST与MANAGER看做一组,其他职位看做另一组,分别统计人数?
SELECT
COUNT(*),DECODE(job,'MANAGER','VIP','ANALYST','VIP','OTHER')
FROM
emp
GROUP BY
DECODE(job,'MANAGER','VIP','ANALYST','VIP','OTHER')
排序函数
排序函数可以将结果集按照指定的字段分组然后组内再按照指定的字段排序后对每组的记录产生一个行号。
ROW_NUMBER():生成组内连续且唯一的数字。
查看每个部门的工资排名?
SELECT
ename,job,sal,deptno,ROW_NUMBER() OVER(PARTITION BY deptno ORDER BY sal DESC) rank
FROM
emp
RANK():生成组内不连续也不唯一的数字
SELECT
ename,job,sal,deptno,RANK() OVER(PARTITION BY deptno ORDER BY sal DESC) rank
FROM
emp
DENSE_RANK():生成组内连续但不唯一的数字
SELECT
ename,job,sal,deptno,DENSE_RANK() OVER(PARTITION BY deptno ORDER BY sal DESC) rank
FROM
emp
高级分组函数
查看每天的营业额?
SELECT
year_id,month_id,day_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
year_id,month_id,day_id
ORDER BY
year_id,month_id,day_id
查看每月的营业额?
SELECT
year_id,month_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
year_id,month_id
ORDER BY
year_id,month_id
查看每年的营业额?
SELECT
year_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
year_id
ORDER BY
year_id
查看总共的营业额?
SELECT SUM(sales_value) FROM sales_tab
在一个结果集中看到每天,每月,每年以及总共的营业额?
SELECT
year_id,month_id,day_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
year_id,month_id,day_id
UNION
ALL
SELECT
year_id,month_id,NULL,SUM(sales_value)
FROM
sales_tab
GROUP
BY year_id,month_id
UNION
ALL
SELECT
year_id,NULL,NULL,SUM(sales_value)
FROM
sales_tab
GROUP BY
year_id
UNION
ALL
SELECT NULL,NULL,NULL,SUM(sales_value) FROM sales_tab
ROLLUP()函数
ROLLUP中的每一个参数就是需要分组的字段。
ROLLUP会将参数字段逐个递减并分组统计直至一个字段都没有,然后将这些分组统计的结果并在一个结果集显示
GROUP BY ROLLUP(a,b,c)
等价:
GROUP BY a,b,c
UNION ALL
GROUP BY a,b
UNION ALL
GROUP BY a
UNION ALL
全表
在一个结果集中看到每天,每月,每年以及总共的营业额?
SELECT
year_id,month_id,day_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
ROLLUP(year_id,month_id,day_id)
ORDER BY
year_id,month_id,day_id
CUBE()函数,将每个参数的每种组合都进行一次分组,然后将所有统计的结果并在一个结果集显示,所以CUBE分组次数为2的参数个数次方。
GROUP BY CUBE(a,b,c)
abc
ab
bc
ac
a
b
c
全表
SELECT
year_id,month_id,day_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
CUBE(year_id,month_id,day_id)
ORDER BY
year_id,month_id,day_id
GROUPING SETS()
GROUPING SETS的每一个参数是一种分组方式它会将这些分组统计的结果并在一个结果集显示。查看每天与每月营业额?
SELECT
year_id,month_id,day_id,SUM(sales_value)
FROM
sales_tab
GROUP BY
GROUPING SETS((year_id,month_id,day_id),(year_id,month_id))
ORDER BY
year_id,month_id,day_id
GROUP BY year_id,month_id,day_id
GROUP BY year_id,month_id
视图VIEW
视图是数据库对象之一,在SQL语句中体现的角色与表一致。但是视图并非一张真实存在的表,它只是一个查询语句对应的结果集。
CREATE
VIEW v_emp_10
AS
SELECT empno, ename, sal, deptno FROM emp
WHERE
deptno = 10
DESC v_emp_10
SELECT * FROM v_emp_10
视图对应的子查询中的字段可以指定别名,这样该视图对应的字段名就是这个别名。当一个字段是函数或者表达式,那么该字段
必须指定别名
CREATE
OR REPLACE VIEW v_emp_10
AS
SELECT empno id,ename name,sal salary,deptno
FROM
emp
WHERE
deptno=10
视图根据对应的子查询不同,分为简单视图和复杂视图
简单视图:对应的子查询不含有函数,表达式,分组,去重,关联查询。
除了简单视图就是复杂视图
简单视图可以进行DML操作,对该视图的操作就是对该视图数据来源的基础表进行的操作。
复杂视图不允许进行DML操作。
对简单视图进行DML操作也不能违反基础表的约束条件。
对视图进行DML操作,视图对基础表操作时,只能对视图可见的字段进行。
INSERT INTO
v_emp_10(id,name,salary,deptno)
VALUES
(1001,'JACK',3000,10)
SELECT * FROM v_emp_10
SELECT * FROM emp
UPDATE v_emp_10 SET salary=4000 WHERE id=1001
DELETE FROM v_emp_10 WHERE id=1001
对视图的不当DML操作会污染基表数据 即:对视图进行DML操作后,视图对基础表
对应数据进行该DML操作,但是操作后视图却对该记录不可见。
INSERT INTO v_emp_10(id,name,salary,deptno) VALUES(1001,'JACK',3000,20)
UPDATE v_emp_10 SET deptno=20
DELETE不会产生污染现象。
DELETE FROM v_emp_10 WHERE deptno=20
为视图添加检查选项,可以避免对视图操作而导致的对基表的数据污染。
WITH CHECK OPTION
该选项要求对视图进行DML操作后,该记录必须对视图可见。
CREATE OR REPLACE VIEW
v_emp_10
AS
SELECT empno id,ename name,sal salary,deptno
FROM
emp
WHERE
deptno=10
WITH CHECK OPTION
只读选项
WITH READ ONLY
只读选项要求对视图仅能进行查询操作不能进行任何DML操作。
CREATE OR REPLACE VIEW
v_emp_10
AS
SELECT empno id,ename name,sal salary,deptno
FROM
emp
WHERE
deptno=10
WITH READ ONLY
常用的数据库的数据字典
USER_OBJECTS:记录用户创建过的所有数据库对象
SELECT
object_name,object_type
FROM
user_objects
WHERE
object_type='VIEW' AND object_name LIKE '%FANCQ'
USER_VIEWS:专门记录曾经创建过的视图信息
SELECT view_name,text FROM user_views
USER_TABLES:专门记录曾经创建过的表的信息
SELECT table_name FROM user_tables
删除视图
DROP VIEW v_emp_10
创建复杂视图
创建一张视图,包含员工工资及相关部门信息包含:每个部门的平均工资,最大,最小,工资总和,以及对应的部门名称,部门编号。
CREATE OR REPLACE VIEW
v_emp_salinfo
AS
SELECT AVG(e.sal) avg_sal,MAX(e.sal) max_sal,MIN(e.sal) min_sal,SUM(e.sal) sum_sal,d.deptno,d.dname,d.loc
FROM
emp e,dept d
WHERE
e.deptno=d.deptno
GROUP BY
d.deptno,d.dname,d.loc
查看哪些员工的工资高于其所在部门平均工资?
SELECT
e.ename,e.sal,e.deptno
FROM
emp e,v_emp_salinfo v
WHERE
e.deptno=v.deptno AND e.sal>v.avg_sal
SELECT * FROM v_emp_salinfo
序列SEQUENCE
序列是数据库对象之一,作用是根据指定的规则生成一系列数字。通常使用序列生成的数字是为表中的主键字段提供值使用。
CREATE SEQUENCE seq_emp_id START WITH 1 INCREMENT BY 1
序列支持两个伪列:
NEXTVAL:获取序列的下一个数字,如果是新创建的序列,那么会从START WITH开始返回。之后则是用上次生成的数字加上步长来得到本次生成的数字返回。需要注意,序列是不能后退的。并且不受事务控制。
CURRVAL:获取序列最后生成的数字,新创建的序列至少调用NEXTVAL生成一个数字后才可以使用。CURRVAL不会导致序列步进。
SELECT seq_emp_id.NEXTVAL FROM dual
SELECT seq_emp_id.CURRVAL FROM dual
使用序列为EMP表主键字段提供值:
INSERT INTO emp(empno,ename,job,sal,deptno) VALUES(seq_emp_id.NEXTVAL,'JACK','CLERK',3000,10)
SELECT * FROM emp
删除一个序列
DROP SEQUENCE seq_emp_id
序列的数据字典
SELECT * FROM USER_SEQUENCES
索引INDEX
索引是数据库对象之一,作用是提高查询效率索引的创建时是数据库自行完成的,并且数据库会在适当的时候自动使用索引。
CREATE INDEX idx_emp_ename ON emp(ename)
经常出现在WHERE中和ORDER BY中的字段要添加索引。经常出现在DISTINCT后面的字段也可以添加索引。
需要注意,对于字符串类型字段,若在WHERE中使用LIKE进行过滤时,是不会用到索引的。
约束
唯一性约束
CREATE TABLE
employees2 (eid NUMBER(6) UNIQUE,name VARCHAR2(30),email VARCHAR2(50),salary NUMBER(7, 2),hiredate DATE,CONSTRAINT employees_email_uk UNIQUE(email))
INSERT INTO
employees2(eid,name,email)
VALUES(NULL,'jack',NULL)
SELECT * FROM employees2
主键约束
一张表只能有一个字段定义主键约束,主键约束要求该字段非空且唯一
CREATE TABLE employees3 (
eid NUMBER(6) PRIMARY KEY,
name VARCHAR2(30),
email VARCHAR2(50),
salary NUMBER(7, 2),
hiredate DATE
)
INSERT INTO employees3
(eid,name,email)
VALUES
(2,'jack','[email protected]')