7.27实习培训日志-Oracle SQL(三)

Oracle SQL(三)

视图

特性 简单视图 复杂视图
关联的表数量 1个 1个或多个
查询中包含函数
查询中包含分组数据
允许对视图进行DML操作
CREATE [OR REPLACE] [FORCE|NOFORCE] VIEW view
[(alias[, alias]...)]
AS subquery
[WITH CHECK OPTION [CONSTRAINT constraint]]
[WITH READ ONLY [CONSTRAINT constraint]];

CREATE VIEW viewname
(name, minsal, maxsal, avgsal)
AS SELECT d.department_name, MIN(e.salary),
MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;
--删除视图
DROP VIEW viewname;

--top n
SELECT [column_list], ROWNUM
FROM (SELECT [column_list]
FROM table
ORDER BY Top-N_column)
WHERE ROWNUM <= N;

--查询工资最低的三个人
SELECT salary
      ,last_name
      ,e_rownum
      ,rownum
  FROM (SELECT rownum e_rownum
              ,e.salary
              ,e.last_name
          FROM employees e
         ORDER BY e.salary)
 WHERE rownum <= 3;

序列,索引

序列

CREATE SEQUENCE sequence
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE n | NOCACHE}];

从序列取值: CURRVAL 取当前值, NEXTVAL

--更改序列
ALTER SEQUENCE sequencename
INCREMENT BY 20
MAXVALUE 999999
NOCACHE NOCYCLE;

--删除序列
DROP SEQUENCE sequencename;

索引

CREATE INDEX indexname ON tablename(columnsname);

适合创建索引:

查询条件中使用到这个列(或者这个列于其他列的组合),且这个列(或者与其他列的组合)上的数字量 范围跨度很大,而大多数情况下我们要获取的数据的量占整个表的数据总量 小于4%。

不适合创建索引:

被查询的表本身就很小,即是是全表扫描也非常快; ; 或者基于这张表的查询,大多数情况下需要获取的数据量都超过了总量的4% ;或者这张表需要频繁的被更新,建立索引的话会引起索引的频繁更新,从而反而降低数据库的整体效率。

函数索引:

当查询语句的Where 条件中,对于某些列使用了函数表达式时,必须创建函数索引。

SELECT * FROM departments WHERE UPPER(department_name) = 'SALES';
--对于上语句,需要建立函数索引
CREATE INDEX indexname ON departments(UPPER(department_name));

同义词

当数据库用户A 要访问数据库用户B 中的一张表Table1 的时候,需要加前缀Select * from B.table1

我们要通过DB-LINK 访问另一个数据库中的某张表的时候我们需要加@ 后缀Select * from table1@db-link-name

CREATE SYNONYM Table1 for B.Table1 -- 建立同义词
Select * from Table1 -- 同义词访问

集合

集合 功能
union 去除重复记录
union all 保留重复记录
intersect 取交集
minus 取差集(前面-交集)

用户权限

--过角色来简化管理
CREATE ROLE manager ;
GRANT create table, create view to manager;
GRANT manager to DEHAAN, KOCHHAR;

WITH GRANT OPTION;--有授权的权限

--让所有人拥有权限
GRANT select ON tablename TO PUBLIC;

对象权限:区别于系统权限,细化到某个具体的数据库对象上的权限访问控制

通过数据字典查询系统中的赋权情况:

数据字典视图 描述
ROLE_SYS_PRIVS 角色对应的系统权限
ROLE_TAB_PRIVS 角色对应的表权限
USER_ROLE_PRIVS 用户的角色分配表
USER_TAB_PRIVS_MADE 用户对象上赋权者与被赋者的历史赋权情况
USER_TAB_PRIVS_RECD 用户对象上拥有者与被赋者的历史赋权情况
USER_COL_PRIVS_MADE 用户对象列上赋权者与被赋者的历史赋权情况
USER_COL_PRIVS_RECD 用户对象列上拥有者与被赋者的历史赋权情况
USER_SYS_PRIVS 用户的系统权限
--收回权限
REVOKE {privilege [, privilege...]|ALL} ON object
FROM {user[, user...]|role|PUBLIC}

CREATE PUBLIC DATABASE LINK linkname USING username;
SELECT * FROM emp@linkname;

Group By 子句增强

rollup():Rollup 后面跟了n个字段,就将进行n+1 次分组,从右到左每次减少一个字段进行分组;然后进行union

cube:Cube 产生Rollup 结果集 + 多维度的交叉表数据源

ROLLUP只对第一个参数的列进行统计,而CUBE都会进行统计。

Rollup(a,b,c): (a,b,c),(a,b),(a),(全表)

cube(a,b,c):(a,b,c),(a,b),(a,c),(b,c),(a),(b),(c),(全表)

Grouping 函数; 没有被Grouping 到返回1 ,否则返回0

SELECT department_id DEPTID, job_id JOB,
SUM(salary),
GROUPING(department_id) GRP_DEPT,
GROUPING(job_id) GRP_JOB
FROM employees
WHERE department_id < 50
GROUP BY ROLLUP(department_id, job_id);

使用Grouping Sets 来代替多次UNION.

GROUPING SETS的效果:1.只需要访问一次基表.2.不需要写很复杂的UNION语句.

子查询增强

子查询分标量子查询、表子查询。

标量子查询:子查询的返回值必须只有一行记录,而且只能有一个列。可以用在select语句的列表中、表达式中、where语句中等。

表子查询:列值子查询可以返回一个多行多列的结果集。表子查询可以看作一个临时表,表子查询可以用在select语句的from子句、insert语句、连接、in子句等。

非相关子查询:独立于外部查询的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询,并且它是优先于外部查询先执行的,他执行了再执行外部。(非相关子查询当作一张表使用)

相关子查询:执行依赖于外部查询的数据,外部查询执行一行,子查询就执行一次。并且是外部先查询一次,然后再执行一次内部查询。效率低。

--非相关子查询
SELECT a.last_name, a.salary, a.department_id, b.salavg
FROM employees a, (SELECT department_id,
AVG(salary) salavg
FROM employees
GROUP BY department_id) b
WHERE a.department_id = b.department_id
AND a.salary > b.salavg;
--相关子查询
SELECT last_name, salary, department_id
FROM employees outer
WHERE salary >
(SELECT AVG(salary)
FROM employees
WHERE department_id =outer.department_id) ;

Not In 里面 只要有一个NULL,结果就为null

in:只执行一次,它查出B表中的所有内容并缓存起来

exists:不缓存结果集,会执行多次

子查询结果集小,用IN,外表小,子查询表大,用EXISTS

连接查询不需要建立临时表,因此其速度比子查询快。

WITH

  1. 如果在后面多次使用则可以简化SQL
  2. 适当提高性能
--相当于建了个e临时表
with e as (select * from user)
select * from e;

--相当于建了e、d临时表
with
     e as (select * from user),
     d as (select * from role)
select * from e, d where e.id = d.uid;

递归查询

递归查询: 使用语句SQL 语句即可把整个递归树全部查询出来。

select … from tablename
start with 条件1
connect by 条件2
where 条件3;--过滤条件
--PRIOR表示上一条记录
-- CONNECT BY PRIOR org_id = parent_id;就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。

使用LEVEL 关键字和 LPAD 函数 :显示树形层次

lpad函数:将左边的字符串填充一些特定的字符

lpad( string1, padded_length, [ pad_string ] )
padded_length<string1.length --截断
padded_length>string1.length --左边加pad_string
lpad('tech', 8, '0'); --0000tech

Insert增强

Insert…Select :使用Insert Select实现同时向多个表插入记录

insert first:对于每一行数据,只插入到第一个when条件成立的表,不继续检查其他条件。

insert all :对于每一行数据,对每一个when条件都进行检查,如果满足条件就执行插入操作。

--一个来源插入多个目标表
INSERT ALL
INTO sal_history VALUES(EMPID,HIREDATE,SAL)
INTO mgr_history VALUES(EMPID,MGR,SAL)
SELECT employee_id EMPID, hire_date HIREDATE,
salary SAL, manager_id MGR
FROM employees
WHERE employee_id > 200;

INSERT ALL
WHEN condition THEN insert_into_clause values_clause
[WHEN condition THEN] [insert_into_clause values_clause]
……
[ELSE] [insert_into_clause values_clause]
Subquery;

--一个来源插入多个目标表(有条件,首次匹配即跳到下一条)
INSERT FIRST
WHEN SAL > 25000 THEN
INTO special_sal VALUES(DEPTID, SAL)
WHEN HIREDATE like ('%00%') THEN
INTO hiredate_history_00 VALUES(DEPTID,HIREDATE)
WHEN HIREDATE like ('%99%') THEN
INTO hiredate_history_99 VALUES(DEPTID, HIREDATE)
ELSE
INTO hiredate_history VALUES(DEPTID, HIREDATE)
SELECT department_id DEPTID, SUM(salary) SAL,
MAX(hire_date) HIREDATE
FROM employees
GROUP BY department_id;

SQL进阶

over分析函数

sum(sal) over (partition by deptno) 按部门求薪酬总和
um(sal) over (partition by deptno order by sal) 按部门累计薪酬
部门编号 员工姓名 员工编码 薪酬 按部门求薪酬总和 按部门累计薪酬
7934 MILLER 10 1300 8750 1300
7782 CLARK 10 2450 8750 3750
7839 KING 10 5000 8750 8750
  1. rank()是跳跃排序,有两个第二名时接下来就是第四名
  2. dense_rank()l是连续排序,有两个第二名时仍然跟着第三名
SELECT d.department_name,
e.last_name,
e.salary,
rank() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank1,
dense_rank() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank2,
row_number() over(PARTITION BY d.department_name ORDER BY e.salary DESC) dept_salary_rank3
FROM employees e, departments d
WHERE 1 = 1
AND e.department_id = d.department_id;

oracle的分析函数over(Partition by…) 及开窗函数

查询之前一段时间内修改行原先的值

闪回的时效是有限制的,具体能闪回到多久之前的数据和数据库的设置有关系

SELECT * FROM departments AS OF TIMESTAMP SYSDATE-5/(24*60)
WHERE department_name = 'Finance';

全局临时表global

基于会话

CREATE GLOBAL TEMPORARY TABLE temp_table_session (…) ON COMMIT PRESERVE ROWS;

基于会话的临时表,在会话断开之前,或者通过一个delete 或truncate 物理地删除行之前 ,这些行会一直存在于这个临时表中。只有我的会话能看到这些行,即使我已经提交,其他会话也无法看到我的行。

基于事务

CREATE GLOBAL TEMPORARY TABLE temp_table_session (…) ON COMMIT DELETE ROWS;

基于事务的临时表,我的会话提交时,临时表中的行就不见了。只需把分配给这个表的临时区段交回,这些 行就会消失,在临时表的自动清除过程中不存在开销。

物化视图(materialized)

物化 视图使用的也比较普遍,是一种特殊的物理表,有别于普通的数据视图。在一段时间内保存固定的数据,提供自动刷新和手动刷新的机制

CREATE MATERIALIZED VIEW materialized_view_name
BUILD [IMMEDIATE|DEFERRED] --1. 创建方式
REFRESH [COMPLETE|FAST|FORCE|NEVER] --2. 物化视图刷新方式
ON [COMMIT|DEMAND] --3. 刷新触发方式
START WITH (start_date) --4. 开始时间
NEXT (interval_date) --5. 间隔时间
WITH [PRIMARY KEY|ROWID] --6. 默认 primary key
ENABLE QUERY REWRITE --7. 是否启用查询重写
AS --8. 关键字
SELECT STATEMENT; --9. 基表选取数据的 select 语句
  1. build immediate是在创建物化视图的时候就生成数据。
  2. build deferred则在创建时不生成数据,以后根据需要在生成数据。

刷新触发方式

  1. on demand 顾名思义,仅在该物化视图“需要”被刷新了,才进行刷新(REFRESH).默认
  2. on commit 提交触发,一旦基表有了commit,即事务提交,则立刻刷新.速度慢

物化视图刷新方式

  1. 完全刷新(COMPLETE): 会删除表中所有的记录(如果是单表刷新,可能会采用TRUNCATE的方式),然后根据物化视图中查询语句的定义重新生成物化视图。
  2. 快速刷新(FAST): 采用增量刷新的机制,只将自上次刷新以后对基表进行的所有操作刷新到物化视图中去。FAST必须创建基于主表的视图日志。对于增量刷新选项,如果在子查询中存在分析函数,则物化视图不起作用。
  3. FORCE方式:这是默认的数据刷新方式。Oracle会自动判断是否满足快速刷新的条件,如果满足则进行快速刷新,否则进行完全刷新。

Oracle物化视图的一般使用

length是字符个数,lengthb 指的是字节数。

substr值是按字来取值,substrb按字节取值。

VPD 全称Virtual Private Database:提供了对 数据库信息的细粒度访问控制,通过策略函数来实现的具体的控制。

通过查询数据字典,确认数据库对象上是否有策略函数:
SELECT * FROM dba_policies t WHERE t.object_name = 'EMPLOYEES';

发表评论

电子邮件地址不会被公开。 必填项已用*标注