connect by prior start with 经常会被用到一个表中存在递归关系的时候。比如我们经常会将一个比较复杂的目录树存储到一个表中。或者将一些部门存储到一个表中,而这些部门互相有隶属关系。这个时候你就会用到connect by prior start with。 典型的使用方法就是:
select * from table connect by prior cur_id=parent_id start with cur_id=??? 例如: a b 1 0 2 1 3 1 4 2 5 3
如果想查找a=2及其下面的所有数据,则: select * from table connect by prior a=b start with a=2 a b 2 1 4 2 例如1﹕
看成兩個集合 START WITH 為條件 select * from dv_boms
WHERE artic_code = '315066-001-00' AND PART_NO='00051' START WITH artic_code = '315066-001-00' and bom_ver =1 AND ITEM_NO = 60 and item_no_pa is null CONNECT BY
//以下條件為父主鍵=子主鍵
PRIOR artic_code = artic_code and PRIOR bom_ver = bom_ver and PRIOR item_no = item_no_pa;
SELECT PART_NO,ITEM_NO,ITEM_NO_PA FROM DV_BOMS
WHERE Artic_code = '315066-001-00' and bom_ver =1; AND PART_NO='00051'; 從那項開始找到底部關系圖 select * from dv_boms
START WITH artic_code = '315066-001-00' and bom_ver =1 and item_no_pa ='60'
CONNECT BY
PRIOR artic_code = artic_code and PRIOR bom_ver = bom_ver AND PRIOR ITEM_NO=ITEM_NO_PA; 例如2﹕
select distinct artic_code,(case when level = 1 then part_no when level = 2 then ' '||part_no when level = 3 then ' '||part_no end ) part_no
此句也可select artic_code, lpad(' ',4*(level-1))||part_no part_no ,item_no,item_no_pa from dv_boms //where artic_code = '313324-002-00' connect by prior artic_code = artic_code and prior bom_ver = bom_ver and prior item_no = item_no_pa start with artic_code = '315066-001-00' and bom_ver =1 and PART_NO='00051'
and item_no = 60 ---从某一节点开始 ORDER BY part_no desc 例3﹕
SELECT lpad(' ',3 * level - 2) ,PART_ID ,level FROM BOM_DETAIL_NEW
WHERE PRODUCT_ID = :ls_proc_id
START WITH PARENT_PART_ID IS NULL
CONNECT BY PRIOR PART_ID = PARENT_PART_ID; 例3﹕
Oracle中使用connect by 来实现树状查询,其中可以使用level这个伪列来实现分层查询。 具体使用如下:
一张表menu记录菜单的层级情况。表结构如下: menu_id number, parent_id number, menu_name nvarchar2(20)
首先select * from menu connect by menu_id = parent_id start with menu_id = 1;
这样可以看到Oracle以树状结构产生结果。某些时候如果我只想要第2层的菜单项如何做呢。 select * from
(select level,menu_id,parent_id,menu_name from menu
conncet by menu_id = parent_id
start with menu_id = 1 )
where level = 2
这样就可以得到层级为第二层的菜单项。这样的SQL写法同样适合rownum伪列,Oracle中实现TOP n查询就是如此写的。
二﹑1.查询语句的使用
使用 select语句和子查询(subquery)可以从一个或多个表,视图,实体试图中返回数据.
1.1相关子查询
可以将子查询(as subquery)或in或exists当成where的一个条件的一部分,这样的查询称为子查询
.where中可以包含一个select语句的子查询
.where中可以包含in,exists语句
.最多可以嵌套16层
.层次过多会影响性能
[例]简单子查询实例
查询是否有的专家既以研究所的名义来申请基金项目,又以大学系为单位申请项目
(按规定只能以一个单位来申请)
SQL> create table univ_subject 2 (
3 name varchar2(12) not null, 4 per_id number not null, 5 dept_name varchar2(20) 6 );
SQL> insert into univ_subject values('gaoqianjing',1001,'信息工程系'); SQL> insert into univ_subject values('wangbing',1002,'物理系');
SQL> insert into univ_subject values('liming',1003,'化学系'); ===============
SQL> create table colle_subject 2 (
3 colle_name varchar2(20), 4 per_id number 5 );
SQL> insert into colle_subject values('电子研究所',1001); SQL> insert into colle_subject values('物理研究所',1005); ================
SQL> select name,per_id,dept_name from univ_subject where per_id in 2 (select per_id from colle_subject);
NAME PER_ID DEPT_NAME ------------ --------- -------------------- gaoqianjing 1001 信息工程系
1.2外连接
[例]外连接实例
招生中所有学生的信息放在students表中,而部分有特长的学生在另一个表中stuent_skill中同样有该学生的信息。现在要全部列出所有学生,如果某个学生在表student_skill中就有其特长信息,并显示特长信息,如果某个学生没有特长就显示特长问空.
SQL> create table students 2 (
3 st_id varchar2(20), 4 name varchar2(10), 5 age number(2), 6 tol_score number(3) 7 ) ;
SQL> insert into students values('973231','wangbindu',22,501); SQL> insert into students values('973232','zhuzhijing',21,538); SQL> insert into students values('973233','gaojing',21,576); ===================
SQL> create table student_skill
2 (
3 st_id varchar2(20), 4 skill varchar2(20) 5 );
SQL> insert into student_skill values('973231','篮球'); SQL> insert into student_skill(st_id) values('973232'); SQL> insert into student_skill values('973233','足球'); ===================
SQL> select a.* , b.skill from students a,student_skill b where a.st_id=b.st_id(+) order by a.st_id;
ST_ID NAME AGE TOL_SCORE SKILL -------------------- ---------- --------- --------- ----------
973231 wangbindu 22 501 篮球 973232 zhuzhijing 21 538
973233 gaojing 21 576 足球
1.3自我连接
自我连接是在同一个表或视图内进行条件连接.
[例]自我连接实例
查询每个雇员的名字和该雇员的经理的名字:
SQL> select e1.ename||' work for '||e2.ename \"Employees and their Managers\"
2 from scott.emp e1,scott.emp e2 where e1.mgr=e2.empno;
Employees and their Managers ------------------------------------------------- SMITH work for FORD ALLEN work for BLAKE WARD work for BLAKE JONES work for KING MARTIN work for BLAKE BLAKE work for KING
CLARK work for KING SCOTT work for JONES TURNER work for BLAKE ADAMS work for SCOTT JAMES work for BLAKE FORD work for JONES MILLER work for CLARK
1.4UNION , INTERSECT及 MINUS
UNION: 可以将两个以上的表的相类似的查询结果放在一起 (union all则表示返回所有的行)
具体语法: select ... union[all] select... ==========
INTERSECT: 返回两个表中相同的信息 具体语法: select ... intersect select... ==========
MINUS : 返回一个表中出现的信息 具体语法: select ... minus select...
[例1]UNION操作实例
SQL> select st_id from students 2 union
3 select st_id from student_skill; ST_ID
-------------------- 973231 973232 973233
[例2]INTERSECT操作实例
列出有特长的学生的学号
SQL> select st_id from students 2 intersect
3 select st_id from student_skill; ST_ID -------------------- 973231 973233
[例3]MINUS操作实例
列出没有特长学生的学号
select st_id from students minus
select st_id from student_skill; ST_ID -------------------- 973232
2.创建复杂的视图
许多应用系统有统计等功能,建议最好把这些复杂语句写成视图.下面是几个常用的视图.
2.1分组视图
[例1]简单的分组视图
SQL> create or replace view dept_tot as
2 select a.dname dept,sum(b.sal) total_sal from scott.dept a,scott.emp b
3 where a.deptno=b.deptno group by a.dname;
查看已建立。
SQL> select * from dept_tot;
DEPT TOTAL_SAL -------------- --------- ACCOUNTING 8750 RESEARCH 10875 SALES 9400
[例2]带复杂函数视图
SQL> create or replace view itemtot as
2 select persion,sum(amount) itemtot from ledger 3 where actiondate between
4 to_date('01-MAR-1901','dd-mon-yyyy') and 5 to_date('31-MAR-1901','dd-mon-yyyy') 6 and action in('bought','raid') group by persion;
2.2合计视图
[例]合计函数视图实例
SQL> create or replace view emp_no1 as
2 select deptno,sum(sal) 工资和,sum(comm) 总和 3 from scott.emp group by deptno; SQL> select * from emp_no1; DEPTNO 工资和 总和 -------- --------- --------- 10 8750 20 10875
30 9400 2200
2.3组合视图
[例]带组合函数的视图
SQL> create or replace view byitem as
2 select l.persion persion.item, amount, 100*amount/item bypersion,100*amount/total bytotal 3 from ledgent l,itemtotal i,total where l.persion=i.persion where l.persion=i.persion 4 and actiondate between
5 to_date('01-MAR-1901','dd-mon-yyyy') and 6 to_date('31-MAR-1901','dd-mon-yyyy') 7 and action in('bought','raid') ; 3.家族树 语法:
select column from table_name start with column=value connect by prior 父主键=子主键
3.1排除单一性和分枝
以ORACLE中的EMP表为例
[例]从顶到底列出各雇员的信息
SQL> select lpad(' ',4*(level-1))||ename name,empno,mgr from emp start with mgr is null 2 connect by prior empno=mgr;
NAME EMPNO MGR --------- --------- --------- KING 7839
JONES 7566 7839 SCOTT 7788 7566 ADAMS 7876 7788
3.2遍历至根
[例1]现在要从某个雇员开始向他的上级列出该雇员的层次结构
SQL> col ename for a30;
SQL> select lpad(' ',4*(level-1))||ename ename,mgr,empno from scott.emp 2 start with mgr=7788 connect by prior mgr=empno;
ENAME MGR EMPNO -------------------------- --------- ---------
ADAMS 7788 7876 SCOTT 7566 7788 JONES 7839 7566 KING 7839
[例2]列出所有雇员的层次结构
SQL> select lpad(' ',4*(level-1))||ename ename,empno,mgr from scott.emp 2 start with mgr is not null 3 connect by empno=prior mgr;
ENAME EMPNO MGR ------------------ --------- ---------
SMITH 7369 7902 FORD 7902 7566 JONES 7566 7839 KING 7839
ALLEN 7499 7698 BLAKE 7698 7839 KING 7839
WARD 7521 7698 BLAKE 7698 7839 KING 7839
JONES 7566 7839 KING 7839
MARTIN 7654 7698 BLAKE 7698 7839 KING 7839
BLAKE 7698 7839 KING 7839
CLARK 7782 7839 KING 7839
SCOTT 7788 7566 JONES 7566 7839
以往的查询SQL:
Select area,month,sum(money) from SaleOrder group by area,month 然后广州,深圳的合计和所有地区合计都需要在程序里自行累计
1.其实可以使用如下SQL:
Select area,month,sum(total_sale) from SaleOrder group by rollup(area,month) 就能产生和报表一模一样的纪录
2.如果year不想累加,可以写成
Select year,month,area,sum(total_sale) from SaleOrder group by year, rollup(month,area) 另外Oracle 9i还支持如下语法:
Select year,month,area,sum(total_sale) from SaleOrder group by rollup((year,month),area)
3.如果使用Cube(area,month)而不是RollUp(area,month),除了获得每个地区的合计之外,还将获得每个月份的合计,在报表最后显示。
4.Grouping让合计列更好读
RollUp在显示广州合计时,月份列为NULL,但更好的做法应该是显示为\"所有月份\"
Grouping就是用来判断当前Column是否是一个合计列,1为yes,然后用Decode把它转为\"所有月份\"
Select Decode(Grouping(area),1,'所有地区',area) area, Decode(Grouping(month),1,'所有月份',month),
sum(money)
From SaleOrder
Group by RollUp(area,month);
2.对多级层次查询的start with.....connect by
比如人员组织,产品类别,Oracle提供了很经典的方法 SELECT LEVEL, name, emp_id,manager_emp_id FROM employee
START WITH manager_emp_id is null
CONNECT BY PRIOR emp_id = manager_emp_id;
上面的语句demo了全部的应用,start with指明从哪里开始遍历树,如果从根开始,那么它的manager应该是Null,如果从某个职员开始,可以写成emp_id='11' CONNECT BY 就是指明父子关系,注意PRIOR位置 另外还有一个LEVEL列,显示节点的层次
3.更多报表/分析决策功能 3.1 分析功能的基本结构
分析功能() over( partion子句,order by子句,窗口子句) 概念上很难讲清楚,还是用例子说话比较好.
3.2 Row_Number 和 Rank, DENSE_Rank 用于选出Top 3 sales这样的报表
当两个业务员可能有相同业绩时,就要使用Rank和Dense_Rank 比如
金额 RowNum Rank Dense_Rank 张三 4000元 1 1 1 李四 3000元 2 2 2 钱五 2000元 3 3 3 孙六 2000元 4 3 3 丁七 1000元 5 5 4
这时,应该把并列第三的钱五和孙六都选进去,所以用Ranking功能比RowNumber保险.至于Desnse还是Ranking就看具体情况了。 SELECT salesperson_id, SUM(tot_sales) sp_sales,
RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rank FROM orders
GROUP BY salesperson_id
3.3 NTILE 把纪录帄分成甲乙丙丁四等
比如我想取得前25%的纪录,或者把25%的纪录当作同一个level帄等对待,把另25%当作另一个Level帄等对待
SELECT cust_nbr, SUM(tot_sales) cust_sales,
NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartile FROM orders GROUP BY cust_nbr ORDER BY 3,2 DESC;
NTITLE(4)把纪录以 SUM(tot_sales)排序分成4份.
3.4 辅助分析列和Windows Function
报表除了基本事实数据外,总希望旁边多些全年总销量,到目前为止的累计销量,前后三个月的帄均销量这样的列来参考.
这种前后三个月的帄均和到目前为止的累计销量就叫windows function,是SQL2003的针对OLAP的新函数, 见下例
SELECT month, SUM(tot_sales) monthly_sales, SUM(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding FROM orders GROUP BY month ORDER BY month;
SELECT month, SUM(tot_sales) monthly_sales, AVG(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg FROM orders GROUP BY month ORDER BY month;
Windows Function的关键就是Windows子句的几个取值 1 PRECEDING 之前的一条记录 1 FOLLOWING 之后的一条记录
UNBOUNDED PRECEDING 之前的所有记录 CURRENT ROW 当前纪录
4.SubQuery总结
SubQuery天天用了,理论上总结一下.SubQuery 分三种 1.Noncorrelated 子查询 最普通的样式.
2.Correlated Subqueries 把父查询的列拉到子查询里面去,头一回cyt教我的时候理解了半天. 3.Inline View 也被当成最普通的样式用了.
然后Noncorrelated 子查询又有三种情况
1.返回一行一列 where price < (select max(price) from goods )
2.返回多行一列 where price>= ALL (select price from goods where type=2)
or where NOT price< ANY(select price from goods where type=2)
最常用的IN其实就是=ANY()
3.返回多行多列 一次返回多列当然就节省了查询时间 UPDATE monthly_orders SET (tot_orders, max_order_amt) =
(SELECT COUNT(*), MAX(sale_price) FROM cust_order)
DELETE FROM line_item WHERE (order_nbr, part_nbr) IN
(SELECT order_nbr, part_nbr FROM cust_order c)
层次结构查询(Querying Hierarchies)
层次结构在现实生活中是很常见的,因此早期的数据库是层次数据库,如实的反映了这种关系。后来层次数据库被证实是非常笨重的,因此关系数据库取得了成功。但是层次结构依然存在,而在关系数据库中层次并不能得到很好的体现。ORACLE提供了强大的层次结构查询来解决这个问题。
一、 固定和可变层数
层次结构关系大致可分为两种。
一种是层级固定,例如美国分为各个州,州下分县,县下又分镇区和城市。这种情况如果在一张表中用递归来实现并不是很好的选择,将其保存在主从结构的三张表中更容易查询和操作。 另一种是层级可变。如图所示的组件清单:
可构造层次表如下:
二、 ORACLE的层次查询
ORACLE提供了SELECT查询语句的START WITH和CONNECT BY子句,来实现层次查询。要进行层次查询,必须明了两件事情:识别根记录的条件和子记录中指向其父亲的列名。 看我们的例子,parent_assembly列决定该记录的父亲。由于根记录Airplane没有父亲,因此列parent_assembly为空,而其他记录的该列不为空,凭此可识别根记录。两个条件均已满足,构造查询语句如下:
SELECT assembly_id, assembly_name, parent_assembly FROM bill_of_materials
START WITH parent_assembly IS NULL
CONNECT BY parent_assembly = PRIOR assembly_id; 三、 解析CONNECT BY子句
从一定角度看,CONNECT BY可以看作是一种连接的规范。实现递归连接,也可以使用标准sql语句,将BILL_OF_MATERIAL与自身连接起来并返回每行的父记录。 SELECT bom1.assembly_id, bom1.assembly_name, bom2.assembly_id parent FROM bill_of_materials bom1 LEFT OUTER JOIN bill_of_materials bom2 ON bom1.parent_assembly = bom2.assembly_id;
这个sql语句返回的记录和上面那个语句是同样的。唯一的区别是行的顺序不一样。当然行的顺序是非常重要的,自连接的sql语句返回记录的顺序不能反映父子关系。
很多问题并不能通过自连接解决,例如你不能使用自连接查询选出刚好组成一架飞机的组件。但是CONNECT BY可以解决所有父子结构方面的问题。 四、 如何使用WHERE子句
要过滤记录,有两种途径。首先,从查询的根节点方面着手,使用START WITH子句来限制查询特定节点。例如我们可以使用如下语句,只查询飞机上两个座位及其部件的信息: SELECT assembly_id, assembly_name, PRIOR assembly_id parent FROM bill_of_materials
START WITH assembly_id IN (205,206)
CONNECT BY parent_assembly = PRIOR assembly_id;
但是有时需要其他条件,比如part_number is not null,这时就需要引入WHERE子句。 SELECT assembly_id, assembly_name, PRIOR assembly_id parent FROM bill_of_materials
WHERE PART_NUMBER IS NOT NULL START WITH assembly_id IN (205,206)
CONNECT BY parent_assembly = PRIOR assembly_id;
上面语句中的过滤条件是在CONNECT BY语句处理完成后才发生作用。当树已经生成,过滤条件才开始影响查询所返回的记录。 五、 层次连接
要写好层次查询,必须了解ORACLE如何处理这样的查询。 首先实现连接
其次CONNECT BY处理应用在连接所返回的记录行上。
再次WHERE子句定义的过滤条件应用在CONNECT BY操作返回的记录行上。 知道了上述顺序,让我们来看一个查询:
SELECT assembly_id id, parent_assembly parent, assembly_name name, bom.part_number part, current_inventory inventory FROM bill_of_materials bom, part p
WHERE bom.part_number = p.part_number START WITH assembly_id = 200
CONNECT BY parent_assembly = PRIOR assembly_id;
上面的查询中,首先处理的是连接——bom.part_number = p.part_number。
而在bill_of_materials表中只有最低层次的节点(叶节点)其part_number列才不为空。两者连接后,将bill_of_materials表中part_number为空的列剔除了,而那些列又是叶节点的父级。所以下一步进行CONNECT BY操作时,由于找不到查询的根节点——assembly_id = 200,查询不会返回任何记录。注意:没有根就意味着没有输出。
解决办法是使用外连接(+),这样CONNECT BY操作才会成功。
SELECT assembly_id id, parent_assembly parent, assembly_name name, bom.part_number part, current_inventory inventory FROM bill_of_materials bom, part p
WHERE bom.part_number = p.part_number(+) START WITH assembly_id = 200
CONNECT BY parent_assembly = PRIOR assembly_id;
WHERE子句里的连接条件是首先被处理的,而WHERE子句里的过滤条件是在CONNECT BY处理完成后才起作用的。
如下述查询选出备件所有存货量小于500的记录:
SELECT assembly_id id, parent_assembly parent, assembly_name name, bom.part_number part, current_inventory inventory FROM bill_of_materials bom, part p
WHERE bom.part_number = p.part_number (+) AND p.current_inventory < 500 START WITH assembly_id = 200
CONNECT BY parent_assembly = PRIOR assembly_id; AND p.current_inventory < 500属于过滤条件,最后处理。
你也许注意到上面的查询都是用的老版本的连接,很不幸的,Oracle 9i数据库在CONNNECT BY查询和新的JOIN子句之间存在bug。上述语句用新JOIN子句写出: SELECT assembly_id id, parent_assembly parent, assembly_name name, bom.part_number part, current_inventory inventory FROM bill_of_materials bom LEFT OUTER JOIN part p ON bom.part_number = p.part_number WHERE p.current_inventory < 500 START WITH assembly_id = 200
CONNECT BY parent_assembly = PRIOR assembly_id;
这个语句将不会返回任何值,因为根节点被过早的过滤掉了。
当然ORACLE已经清楚这个bug,正在修复。 六、 层级
我们经常希望得知树中给定记录的层级,oracle提供LEVEL伪列来实现。LEVEL可出现在SQL语句的任何部分,并且对于根节点返回1,根节点的孩子返回2,孙子返回3…。 通常使用LEVEL来实现记录的缩排,以便更清楚的表现树状结构。 七、 节点路径
Oracle 9i提供了新函数SYS_CONNECT_BY_PATH,可以给出从根节点到指定节点的全路径。该函数有两个参数:列名和分隔符,而且列名并不局限于CONNECT BY列。 例如:
SELECT SYS_CONNECT_BY_PATH(assembly_name,'/') name_path FROM bill_of_materials WHERE part_number = 1019
START WITH parent_assembly IS NULL
CONNECT BY parent_assembly = PRIOR assembly_id; 八、 排序
想对结果进行排序,当然可以使用标准的ORDER BY子句,但是它会破坏父子结构,一般不建议使用。
Oracle 9i也提供了一个ORDER BY子句的关键字SIBLINGS,允许对层次数据以有意义的方式进行分类,同时保留层次结构。 如:
SELECT RPAD(' ', 2*(LEVEL-1)) || assembly_name assembly_name FROM bill_of_materials START WITH assembly_id = 200
CONNECT BY parent_assembly = PRIOR assembly_id ORDER SIBLINGS BY assembly_name;
表示在每个层级(LEVEL)上按字母表顺序进行排序,这对生成树状报表非常有用。 用connect by及start with建立树结构的报表并不难,但必须遵守下列规则: .使用connect by时子句的顺序是 select from where start with connect by order by
.prior使报表从树根到树叶(如果prior列是父母),或从树叶至树根(如果prior列是孩子)。 .where子句将从树中去掉单个节点,但保留她它们的后代(或祖先,假设PRIOR在等号的右边)。 .connect by中的限定(尤其是不等时)将去掉单个节点及其后代(或祖先,取决于浏览树的方向)。 .connect by不能用在where子句的连接表(table join)中。
Oracle数据库中分区表的操作方法 Oracle数据库中分区表的操作方法
在大型的企业应用或企业级的数据库应用中,要处理的数据量通常可以达到几十到几百GB,有的甚至可以到TB级。虽然存储介质和数据处理技术的发展也很快,但是仍然不能满足用户的需求,为了使用户的大量的数据在读写操作和查询中速度更快,Oracle提供了对表和索引进行分区的技术,以改善大型应用系统的性能。
使用分区的优点:
·增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;
·维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;
·均衡I/O:可以把不同的分区映射到磁盘以帄衡I/O,改善整个系统性能;
·改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。
Oracle数据库提供对表或索引的分区方法有三种:
·范围分区
·Hash分区(散列分区)
·复合分区
下面将以实例的方式分别对这三种分区方法来说明分区表的使用。为了测试方便,我们先建三个表空间。
create tablespace dinya_space01 datafile ’/test/demo/oracle/demodata/dinya01.dnf’ size 50M create tablespace dinya_space01 datafile ’/test/demo/oracle/demodata/dinya02.dnf’ size 50M create tablespace dinya_space01 datafile ’/test/demo/oracle/demodata/dinya03.dnf’ size 50M
1.1. 分区表的创建
1.1.1. 范围分区
范围分区就是对数据表中的某个值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上。如根据序号分区,根据业务记录的创建日期进行分区等。
需求描述:有一个物料交易表,表名:material_transactions。该表将来可能有千万级的数据记录数。要求在建该表的时候使用分区表。这时候我们可以使用序号分区三个区,每个区中预计存储三千万的数据,也可以使用日期分区,如每五年的数据存储在一个分区上。
根据交易记录的序号分区建表:
SQL> create table dinya_test 2 ( 3 transaction_id number primary key, 4 item_id number(8) not null, 5 item_description varchar2(300), 6 transaction_date date not null 7 ) 8 partition by range (transaction_id) 9 ( 10 partition part_01 values less than(30000000) tablespace dinya_space01, 11 partition part_02 values less than(60000000) tablespace dinya_space02, 12 partition part_03 values less than(maxvalue) tablespace dinya_space03 13 ); Table created.
建表成功,根据交易的序号,交易ID在三千万以下的记录将存储在第一个表空间dinya_space01中,分区名为:par_01,在三千万到六千万之间的记录存储在第二个表空间:
dinya_space02中,分区名为:par_02,而交易ID在六千万以上的记录存储在第三个表空间dinya_space03中,分区名为par_03.
根据交易日期分区建表:
SQL> create table dinya_test 2 ( 3 transaction_id number primary key, 4 item_id number(8) not null, 5 item_description varchar2(300), 6 transaction_date date not null 7 ) 8 partition by range (transaction_date) 9 ( 10 partition part_01 values less than(to_date(’2006-01-01’,’yyyy-mm-dd’)) tablespace dinya_space01, 11 partition part_02 values less than(to_date(’2010-01-01’,’yyyy-mm-dd’)) tablespace dinya_space02, 12 partition part_03 values less than(maxvalue) tablespace dinya_space03 13 ); Table created.
这样我们就分别建了以交易序号和交易日期来分区的分区表。每次插入数据的时候,系统将根据指定的字段的值来自动将记录存储到制定的分区(表空间)中。
当然,我们还可以根据需求,使用两个字段的范围分布来分区,如partition by range ( transaction_id ,transaction_date), 分区条件中的值也做相应的改变,请读者自行测试。
1.1.2. Hash分区(散列分区)
散列分区为通过指定分区编号来均匀分布数据的一种分区类型,因为通过在I/O设备上进行散列分区,使得这些分区大小一致。如将物料交易表的数据根据交易ID散列地存放在指定的三个表空间中:
SQL> create table dinya_test 2 ( 3 transaction_id number primary key, 4 item_id number(8) not null, 5 item_description varchar2(300), 6 transaction_date date 7 ) 8 partition by hash(transaction_id) 9 ( 10 partition part_01 tablespace dinya_space01, 11 partition part_02 tablespace dinya_space02, 12 partition part_03 tablespace dinya_space03 13 ); Table created.
建表成功,此时插入数据,系统将按transaction_id将记录散列地插入三个分区中,这里也就是三个不同的表空间中。
1.1.3. 复合分区
有时候我们需要根据范围分区后,每个分区内的数据再散列地分布在几个表空间中,这样我们就要使用复合分区。复合分区是先使用范围分区,然后在每个分区内再使用散列分区的一种分区方法,如将物料交易的记录按时间分区,然后每个分区中的数据分三个子分区,将数据散列地存储在三个指定的表空间中:
SQL> create table dinya_test 2 ( 3 transaction_id number primary key, 4 item_id number(8) not null, 5 item_description varchar2(300), 6 transaction_date date 7 ) 8 partition by range(transaction_date)subpartition by hash(transaction_id) 9 subpartitions 3 store in (dinya_space01,dinya_space02,dinya_space03) 10 ( 11 partition part_01 values less than(to_date(’2006-01-01’,’yyyy-mm-dd’)), 12 partition part_02 values less than(to_date(’2010-01-01’,’yyyy-mm-dd’)), 13 partition part_03 values less than(maxvalue) 14 ); Table created.
该例中,先是根据交易日期进行范围分区,然后根据交易的ID将记录散列地存储在三个表空间中。 1.2. 分区表操作
以上了解了三种分区表的建表方法,下面将使用实际的数据并针对按日期的范围分区来测试分区表的数据记录的操作。
1.2.1. 插入记录:
SQL> insert into dinya_test values(1,12,’BOOKS’,sysdate); 1 row created. SQL> insert into dinya_test values(2,12, ’BOOKS’,sysdate+30); 1 row created. SQL> insert into dinya_test values(3,12, ’BOOKS’,to_date(’2006-05-30’,’yyyy-mm-dd’)); 1 row created. SQL> insert into dinya_test values(4,12, ’BOOKS’,to_date(’2007-06-23’,’yyyy-mm-dd’)); 1 row created. SQL> insert into dinya_test values(5,12, ’BOOKS’,to_date(’2011-02-26’,’yyyy-mm-dd’)); 1 row created. SQL> insert into dinya_test values(6,12, ’BOOKS’,to_date(’2011-04-30’,’yyyy-mm-dd’)); 1 row created. SQL> commit; Commit complete. SQL>
按上面的建表结果,2006年前的数据将存储在第一个分区part_01上,而2006年到2010年的交易数据将存储在第二个分区part_02上,2010年以后的记录存储在第三个分区part_03上。
1.2.2. 查询分区表记录:
SQL> select * from dinya_test partition(part_01); TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE -------------------------------------------------------------------------------- 1 12 BOOKS 2005-1-14 14:19: 2 12 BOOKS 2005-2-13 14:19: SQL> SQL> select * from dinya_test partition(part_02); TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE -------------------------------------------------------------------------------- 3 12 BOOKS 2006-5-30 4 12 BOOKS 2007-6-23 SQL> SQL> select * from dinya_test partition(part_03); TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE -------------------------------------------------------------------------------- 5 12 BOOKS 2011-2-26 6 12 BOOKS 2011-4-30 SQL>
从查询的结果可以看出,插入的数据已经根据交易时间范围存储在不同的分区中。这里是指定了分区的查询,当然也可以不指定分区,直接执行select * from dinya_test查询全部记录。
在也检索的数据量很大的时候,指定分区会大大提高检索速度。
1.2.3. 更新分区表的记录:
SQL> update dinya_test partition(part_01) t set t.item_description=’DESK’ where t.transaction_id=1; 1 row updated. SQL> commit; Commit complete. SQL>
这里将第一个分区中的交易ID=1的记录中的item_description字段更新为“DESK”,可以看到已经成功更新了一条记录。但是当更新的时候指定了分区,而根据查询的记录不在该分区中时,将不会更新数据,请看下面的例子:
SQL> update dinya_test partition(part_01) t set t.item_description=’DESK’ where t.transaction_id=6; 0 rows updated. SQL> commit; Commit complete. SQL>
指定了在第一个分区中更新记录,但是条件中限制交易ID为6,而查询全表,交易ID为6的记录在第三个分区中,这样该条语句将不会更新记录。
1.2.4. 删除分区表记录:
SQL> delete from dinya_test partition(part_02) t where t.transaction_id=4; 1 row deleted. SQL> commit; Commit complete. SQL>
上面例子删除了第二个分区part_02中的交易记录ID为4的一条记录,和更新数据相同,如果指定了分区,而条件中的数据又不在该分区中时,将不会删除任何数据。
1.3. 分区表索引的使用:
分区表和一般表一样可以建立索引,分区表可以创建局部索引和全局索引。当分区中出现许多事务并且要保证所有分区中的数据记录的唯一性时采用全局索引。
1.3.1. 局部索引分区的建立:
SQL> create index dinya_idx_t on dinya_test(item_id) 2 local 3 ( 4 partition idx_1 tablespace dinya_space01, 5 partition idx_2 tablespace dinya_space02, 6 partition idx_3 tablespace dinya_space03 7 ); Index created. SQL>
看查询的执行计划,从下面的执行计划可以看出,系统已经使用了索引:
SQL> select * from dinya_test partition(part_01) t where t.item_id=12; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=187) 1 0 TABLE ACCESS (BY LOCAL INDEX ROWID) OF ’DINYA_TEST’ (Cost= 2 Card=1 Bytes=187) 2 1 INDEX (RANGE SCAN) OF ’DINYA_IDX_T’ (NON-UNIQUE) (Cost=1 Card=1) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 334 bytes sent via SQL*Net to client 309 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 2 rows processed SQL>
1.3.2. 全局索引分区的建立
全局索引建立时global 子句允许指定索引的范围值,这个范围值为索引字段的范围值:
SQL> create index dinya_idx_t on dinya_test(item_id) 2 global partition by range(item_id) 3 ( 4 partition idx_1 values less than (1000) tablespace dinya_space01, 5 partition idx_2 values less than (10000) tablespace dinya_space02, 6 partition idx_3 values less than (maxvalue) tablespace dinya_space03 7 ); Index created. SQL>
本例中对表的item_id字段建立索引分区,当然也可以不指定索引分区名直接对整个表建立索引,如:
SQL> create index dinya_idx_t on dinya_test(item_id); Index created. SQL>
同样的,对全局索引根据执行计划可以看出索引已经可以使用:
SQL> select * from dinya_test t where t.item_id=12; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=3 Bytes=561) 1 0 TABLE ACCESS (BY GLOBAL INDEX ROWID) OF ’DINYA_TEST’ (Cost =2 Card=3 Bytes=561) 2 1 INDEX (RANGE SCAN) OF ’DINYA_IDX_T’ (NON-UNIQUE) (Cost=1 Card=3) Statistics ---------------------------------------------------------- 5 recursive calls 0 db block gets 10 consistent gets 0 physical reads 0 redo size 420 bytes sent via SQL*Net to client 309 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 3 sorts (memory) 0 sorts (disk) 5 rows processed SQL>
1.4. 分区表的维护:
了解了分区表的建立、索引的建立、表和索引的使用后,在应用的还要经常对分区进行维护和管理。日常维护和管理的内容包括:增加一个分区,合并一个分区及删除分区等等。下面以范围分区为例说明增加、合并、删除分区的一般操作:
1.4.1. 增加一个分区:
SQL> alter table dinya_test 2 add partition part_04 values less than(to_date(’2012-01-01’,’yyyy-mm-dd’)) tablespace dinya_spa ce03; Table altered. SQL>
增加一个分区的时候,增加的分区的条件必须大于现有分区的最大值,否则系统将提示ORA-14074 partition bound must collate higher than that of the last partition 错误。
1.4.2. 合并一个分区:
SQL> alter table dinya_test merge partitions part_01,part_02 into partition part_02; Table altered. SQL>
在本例中将原有的表的part_01分区和part_02分区进行了合并,合并后的分区为part_02,如果在合并的时候把合并后的分区定为part_01的时候,系统将提示ORA-14275 cannot reuse lower-bound partition as resulting partition 错误。
1.4.3. 删除分区:
SQL> alter table dinya_test drop partition part_01; Table altered. SQL>
删除分区表的一个分区后,查询该表的数据时显示,该分区中的数据已全部丢失,所以执行删除分区动作时要慎重,确保先备份数据后再执行,或将分区合并。
一﹑手工创建数据库的全部脚本及说明
手工创建数据库的全部脚本及说明 系统环境:
1、操作系统:Windows 2000 Server,机器内存128M 2、数据库: Oracle 8i R2 (8.1.6) for NT 企业版 3、安装路径:D:\\ORACLE 建库步骤:
1、手工创建相关目录 D:\\Oracle\\admin\est D:\\Oracle\\admin\est\\adhoc D:\\Oracle\\admin\est\\bdump D:\\Oracle\\admin\est\\cdump D:\\Oracle\\admin\est\\create D:\\Oracle\\admin\est\\exp D:\\Oracle\\admin\est\\pfile D:\\Oracle\\admin\est\ D:\\Oracle\\oradata\est D:\\Oracle\\oradata\est\\archive
2、手工创建初始化启动参数文件:D:\\Oracle\\admin\est\\pfile\\inittest.ora,内容: 3、手工创建D:\\Oracle\\Ora81\\DATABASE\\inittest.ora文件, 内容:IFILE='D:\\Oracle\\admin\est\\pfile\\inittest.ora'
4、使用orapwd.exe命令,创建D:\\Oracle\\Ora81\\DATABASE\\PWDtest.ora
命令:D:\\Oracle\\Ora81\\bin\\orapwd file=D:\\Oracle\\Ora81\\DATABASE\\PWDtest.ora password=ORACLE entries=5
5、通过oradim.exe命令,在服务里生成一个新的实例管理服务,启动方式为手工 set ORACLE_SID=test
D:\\Oracle\\Ora81\\bin\\oradim -new -sid test -startmode manual -pfile \"D:\\Oracle\\admin\est\\pfile\\inittest.ora\" 6、生成各种数据库对象 D:\\>svrmgrl --创建数据库
connect INTERNAL/oracle
startup nomount pfile=\"D:\\Oracle\\admin\est\\pfile\\inittest.ora\" CREATE DATABASE test
LOGFILE 'D:\\Oracle\\oradata\est\\redo01.log' SIZE 2048K, 'D:\\Oracle\\oradata\est\\redo02.log' SIZE 2048K, 'D:\\Oracle\\oradata\est\\redo03.log' SIZE 2048K MAXLOGFILES 32 MAXLOGMEMBERS 2 MAXLOGHISTORY 1
DATAFILE 'D:\\Oracle\\oradata\est\\system01.dbf' SIZE 58M REUSE AUTOEXTEND ON NEXT 640K MAXDATAFILES 254 MAXINSTANCES 1
CHARACTER SET ZHS16GBK
NATIONAL CHARACTER SET ZHS16GBK; 控制文件、日志文件在上面语句执行时生成
connect INTERNAL/oracle --修改系统表空间
ALTER TABLESPACE SYSTEM DEFAULT STORAGE ( INITIAL 64K NEXT 64K MINEXTENTS 1 MAXEXTENTS UNLIMITED PCTINCREASE 50); ALTER TABLESPACE SYSTEM MINIMUM EXTENT 64K; --创建回滚表空间
CREATE TABLESPACE RBS DATAFILE 'D:\\Oracle\\oradata\est\\rbs01.dbf' SIZE 256M REUSE AUTOEXTEND ON NEXT 5120K MINIMUM EXTENT 512K
DEFAULT STORAGE ( INITIAL 512K NEXT 512K MINEXTENTS 8 MAXEXTENTS 4096); CREATE PUBLIC ROLLBACK SEGMENT RBS13 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS14 TABLESPACE RBS STORAGE ( OPTIMAL 4096K );
CREATE PUBLIC ROLLBACK SEGMENT RBS15 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS16 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS17 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS18 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS19 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS20 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS21 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS22 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); CREATE PUBLIC ROLLBACK SEGMENT RBS23 TABLESPACE RBS STORAGE ( OPTIMAL 4096K );
CREATE PUBLIC ROLLBACK SEGMENT RBS24 TABLESPACE RBS STORAGE ( OPTIMAL 4096K ); --使回滚段在线
ALTER ROLLBACK SEGMENT \"RBS0\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS1\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS2\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS3\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS4\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS5\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS6\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS7\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS8\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS9\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS10\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS11\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS12\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS13\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS14\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS15\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS16\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS17\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS18\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS19\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS20\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS21\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS22\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS23\" ONLINE; ALTER ROLLBACK SEGMENT \"RBS24\" ONLINE; --修改sys用户的临时表空间为TEMP
alter user sys temporary tablespace TEMP; --创建数据字典表
@D:\\Oracle\\Ora81\\Rdbms\\admin\\catalog.sql; @D:\\Oracle\\Ora81\\Rdbms\\admin\\catexp7.sql @D:\\Oracle\\Ora81\\Rdbms\\admin\\catproc.sql @D:\\Oracle\\Ora81\\Rdbms\\admin\\caths.sql connect system/manager
@D:\\Oracle\\Ora81\\sqlplus\\admin\\pupbld.sql connect internal/oracle
@D:\\Oracle\\Ora81\\Rdbms\\admin\\catrep.sql exit
--生成SQL*Plus帮助系统 sqlplus SYSTEM/manager
@D:\\Oracle\\Ora81\\sqlplus\\admin\\help\\helpbld.sql helpus.sql exit
--修改system用户默认表空间和临时表空间 svrmgrl
connect internal/oracle
alter user system default tablespace TOOLS; alter user system temporary tablespace TEMP; exit
7、将test实例启动服务设置成自动启动方式 D:\\Oracle\\Ora81\\bin\\oradim -edit -sid test -startmode auto
----------------init.ora 内容-------------------------- db_name = \"test\" instance_name = test service_names = test db_files = 1024
control_files = (\"D:\\Oracle\\oradata\est\\control01.ctl\\"D:\\Oracle\\oradata\est\\control03.ctl\") open_cursors = 200 max_enabled_roles = 30
db_file_multiblock_read_count = 8 db_block_buffers = 4096 shared_pool_size = 52428800 large_pool_size = 78643200 java_pool_size = 20971520
log_checkpoint_interval = 10000 log_checkpoint_timeout = 1800 processes = 115 parallel_max_servers = 5 log_buffer = 32768 max_dump_file_size = 10240 global_names = true
oracle_trace_collection_name = \"\"
background_dump_dest = D:\\Oracle\\admin\est\\bdump user_dump_dest = D:\\Oracle\\admin\est\ db_block_size = 16384
remote_login_passwordfile = exclusive os_authent_prefix = \"\" job_queue_processes = 4 job_queue_interval = 60 open_links = 4
distributed_transactions = 10
mts_dispatchers = \"(PROTOCOL=TCP)(PRE=oracle.aurora.server.SGiopServer)\" mts_dispatchers = \"(protocol=TCP)\"
二﹑Oracle数据字典
以下表格中收集了Oracle数据字典中几乎所有的视图或别名,至于每个视图或别名的字段请用‘Describe’语句来查询。 命名说明:
Oracle数据字典中,对象名称多数以\"USER.\",\"ALL.\",\"DBA.\"为前缀\"USER.\"视图中记录通常记录执行查询的帐户所拥有的对象的信息,\"ALL.\"视图中记录包括\"USER\"记录和授权至PUBLIC或用户的对象的信息,\"DBA.\"视图包含所有数据库对象,而不管其所有者。 使用举例:
select * from dba_data_files
查询表空间的信息(当前用户必须拥有DBA角色)
select owner , object_name ,object_type from all_objects 查询某一用户下的所有表、过程、函数等信息
因篇幅问题不能全部显示,请点此查看更多更全内容