Tuesday, April 28, 2009

ways to invoke procedure in Oracle

/*
Sample procedure:
create or replace procedure runbyparmeters (isal in emp.sal%type,
sname out varchar,sjob in out varchar)
2 as icount number;
3 begin
4 select count(*) into icount from emp where sal>isal and job=sjob;
5 if icount=1 then
6 ....
9 else
10 ....
12 end if;
13 exception
14 when too_many_rows then
15 DBMS_OUTPUT.PUT_LINE('返回值多于1行');
16 when others then
17 DBMS_OUTPUT.PUT_LINE('在RUNBYPARMETERS过程中出错!');
18 end;
*/
--call procedure in oracle
--1. first way
declare
realsal emp.sal%type;
realname varchar(40);
realjob varchar(40);
begin
realsal:=1100;
realname:='';
realjob:='CLERK';
runbyparmeters(realsal,realname,realjob); --必须按顺序
DBMS_OUTPUT.PUT_LINE(REALNAME||' '||REALJOB);
END;
--2. second way
declare
realsal emp.sal%type;
realname varchar(40);
realjob varchar(40);
begin
realsal:=1100;
realname:='';
realjob:='CLERK';
runbyparmeters(sname=>realname,isal=>realsal,sjob=>realjob); --指定值对应变量顺序可变
DBMS_OUTPUT.PUT_LINE(REALNAME||' '||REALJOB);
END;

Oracle数据字典表-1

权限安全的数据字典表有:

ALL_TAB_PRIVS

ALL_TAB_PRIVS_MADE

ALL_TAB_PRIVS_RECD

DBA_SYS_PRIVS

DBA_ROLES

DBA_ROLE_PRIVS

ROLE_ROLE_PRIVS

ROLE_SYS_PRIVS

ROLE_TAB_PRIVS

SESSION_PRIVS

SESSION_ROLES

USER_SYS_PRIVS

USER_TAB_PRIV

--check the number of index and type
select index_name,index_type,table_name from user_indexes where table_name=upper('&table_name');

--check the indexed column
select * from user_ind_columns where index_name=upper('&index_name');

-check the size of index
select sum(bytes)/(1024*1024) as "size(M)" from user_segments
where segment_name=upper('&index_name');

Wednesday, April 22, 2009

[oracle] to_date() 与 to_char() 日期和字符串转换

to_date("要转换的字符串","转换的格式") 两个参数的格式必须匹配,否则会报错。

即按照第二个参数的格式解释第一个参数。

to_char(日期,"转换格式" ) 即把给定的日期按照“转换格式”转换。

转换的格式:

表示year的:y 表示年的最后一位 yy 表示年的最后2位 yyy 表示年的最后3位 yyyy 用4位数表示年

表示month的:mm 用2位数字表示月;mon 用简写形式 比如11月或者nov ;month 用全称 比如11月或者november

表示day的:dd 表示当月第几天;ddd表示当年第几天;dy 当周第几天 简写 比如星期五或者fri;day当周第几天 全写

比如星期五或者friday。

表示hour的:hh 2位数表示小时 12进制; hh24 2位数表示小时 24小时

表示minute的:mi 2位数表示分钟

表示second的:ss 2位数表示秒 60进制

表示季度的:q 一位数 表示季度 (1-4)

另外还有ww 用来表示当年第几周 w用来表示当月第几周。

24小时制下的时间范围:00:00:00-23:59:59

12小时制下的时间范围:1:00:00-12:59:59

比如:

select to_char(sysdate,'yy-mm-dd hh24:mi:ss') from dual //显示:08-11-07 13:22:42

select to_date('2005-12-25,13:25:59','yyyy-mm-dd,hh24:mi:ss') from dual //显示:2005-12-25 13:25:59

而如果把上式写作:select to_date('2005-12-25,13:25:59','yyyy-mm-dd,hh:mi:ss') from dual,则会报错,因为小时hh是12进制,13为非法输入,不能匹配。

补充:

当前时间减去7分钟的时间
select sysdate,sysdate - interval '7' MINUTE from dual
当前时间减去7小时的时间
select sysdate - interval '7' hour from dual
当前时间减去7天的时间
select sysdate - interval ’7’ day from dual
当前时间减去7月的时间
select sysdate,sysdate - interval '7' month from dual
当前时间减去7年的时间
select sysdate,sysdate - interval '7' year from dual
时间间隔乘以一个数字
select sysdate,sysdate - 8*interval '7' hour from dual

Dual伪列

含义解释:

Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的select语句块中。

比如,我要获得系统时间,则用“select sysdate from dual” 则返回系统当前的时间:2008-11-07 9:32:49,不同系统可能返回日期的格式不一样。"select user from dual"则返回当前连接的用户。如果是"select 1+2 from dual",则返回结果:3

Wednesday, April 15, 2009

some oracle sql

1. select (case when s_mark <> 80 then '优异'
when s_mark <= 80 and s_mark >= 60 then '优秀'
when s_mark <= 59 and s_mark >= 40 then '良好'
when s_mark <>= 20 then '一般'
when s_mark <= 19 and s_mark > 0 then '较差' from student_scores
----------------------------------------
2. case和decode (P61)语句有什么区别?分别在什么场合使用?
SELECT CASE SIGN(5 - 5) WHEN 1 THEN 'Is Positive' WHEN -1 THEN 'Is Negative' ELSE 'Is Zero' END FROM DUAL;
select decode (条件,结果1,输出1,结果2,输出2)
SELECT DECODE(SIGN(5-9), 1, 'Is Positive', -1, 'Is Negative', 'Is Zero')FROM DUAL
--------------------------------------

Tuesday, April 14, 2009

link for Oracle

1. Oracle FAQ

使用Oracle游标

游标分为:静态游标和引用游标(动态游标)
静态游标:由用户定义(隐式游标、显示游标)结果集不变
引用游标游标:结果集变化
----------------
%NOTFOUND -- 执行行没有找到。

%FOUND --执行行找到

%ROWCOUNT --游标影响行数

%ISOPEN -- 当前游标是否打开
----------------------------------
例如:

DECLARE

v_FirstName students.first_name%TYPE;


通过使用%TYPE,v_FirstName变量将同students表的first_name列的类型相同(可以理解为将两者邦定起来)。

每次匿名块或命名块运行该语句块以及编译存储对象(过程、函数、包、对象类和触发器)时,就会确定该类型。

使用%TYPE是非常好的编程风格,因为它使得PL/SQL更加灵活,更加适应于对数据库定义的更新。
-------------------------
在PL/SQL中将一个记录声明为具有相同类型的数据库行的作法是很常见的。PL/SQL提供了%ROWTYPE运算符,使得这样的操作更为方便。

例如:

DECLARE

v_RoomRecord rooms%ROWTYPE;

将定义一个记录,该记录中的字段将与rooms表中的列相对应。

Monday, April 13, 2009

Oracle 临时表

oracle 的TEMPORARY TABLE有两种,一种是基Session的,即表中的数据在Session结束前数据都存在。另一种是基于transaction的数据在transaction Commit或Rollback后消失。默认值是基于transaction的。所以你"提交后被告知没有行可以选择"。

当会话退出或者用户提交commit和回滚rollback事务的时候,临时表的数据自动清空(truncate),但是临时表的结构以及元数据还存储在用户的数据字典中。你可以索引临时表和在临时表基础上建立视图.同样,建立在临时表上的索引也是临时的,也是只对当前会话或者事务有效. 临时表可以拥有触发器。

Temp Table 并非存放在用户的表空间中,而是存放在 Schema 所指定的临时表空间中, 你可以用下面的语句来检测:
SQL> Select Table_Name, Tablespace_Name
From User_Tables
Where Table_Name Like 'temp_%';

用户 SQLTRAINER 的临时表空间是 TEMP , 用户创建的临时表是存放在TEMP表空间中的。下面来证明

SQL> SELECT UserName, Default_Tablespace def_ts, Temporary_Tablespace temp_ts
FROM User_Users;

尽管对临时表的DML操作速度比较快,但同样也是要产生 Redo Log 的,只是同样的DML语句,比对 PERMANENT 的DML 产生的Redo Log 少。

如果你想数据在Session结束前数据都存在参考下面的例子,或看Oracle的帮助
/*******************************************************************************/
CREATE GLOBAL TEMPORARY TABLE flight_schedule (
startdate DATE,
enddate DATE,
cost NUMBER)
ON COMMIT PRESERVE ROWS;
/*******************************************************************************/

create global temporary table temp_table_name (....) on commit delete rows;
此为事务级临时表,你向里边插入的数据,在commit后就消失,当然rollback后也回滚即消失。
注意事务级临时表在同一会话的嵌套事务中跟一般表一样也可能发生阻塞。

create global temporary table temp_table_name (....) on commit preserve rows;
此为会话级临时表,你向里边插入的数据,在commit后保留不消失,而在整个会话结束后消失,当然rollback也会回滚。

Oracle tips

执行sql脚本
SQL >@a.sql

执行外部shell脚本
SQL>host test.sh
or
SQL>! cd ..
-----------------------
注释
1. --
2. /* 与*/
3. REM
------------------------
1. (+) --> left join
2. LEFT OUTER JOIN
3. RIGHT OUTER JOIN
------------------------
查询索引
SQL> select index_name,table_name from user_indexes;
-----------------------
查询当前所有的表
SQL> select * from tab;
SQL> select * from cat;
------------------------------
显示当前连接用户(库)
SQL> show user
----------------------------
改变连接用户(库)
SQL> conn 用户名/密码@主机字符串
-------------------------
查找一个连接
Sql>Select * from v$session;
-----------------------------
杀掉一个连接
Sql>alter system kill session ‘SID,SERIAL#’;
----------------------------
useful link:
2.

Oracle Select的默认排序规则

一般而言,表是堆表,所以是无序的
他是按照也即物理存放顺序来读取的
rowid 是自动随行生成的
---------------------
实际上oracle没有进行任何排序操作,rowid表示的是数据存放的数据块内部地址,如果没有要求排序,oracle会顺序的从数据块中读取符合条件的数据返回到客户端
--------------------
因为oracle是按块进行读取数据的
如果数据按顺序存储,则可能使读取出来的数据是按顺序的

Wednesday, April 8, 2009

Oracle中创建数组【转】

在Oracle中很容易构造数组:

SQL> SET SERVEROUT ON SIZE 100000
SQL> DECLARE
2 TYPE T_VARRAY IS VARRAY(5) OF NUMBER;
3 V_VAR T_VARRAY := T_VARRAY(1,2,3,4,5);
4 BEGIN
5 FOR I IN 1..V_VAR.COUNT LOOP
6 DBMS_OUTPUT.PUT_LINE(V_VAR(I));
7 END LOOP;
8 END;
9 /

PL/SQL 过程已成功完成。

对于二维数组也是很容易实现的:

SQL> DECLARE
2 TYPE T_VARRAY IS VARRAY(5) OF NUMBER;
3 TYPE T_VARRAY_VARRAY IS VARRAY(4) OF T_VARRAY;
4 V_VAR T_VARRAY_VARRAY := T_VARRAY_VARRAY
5 (
6 T_VARRAY(1,2,3,4,5),
7 T_VARRAY(1,2,3,4,5),
8 T_VARRAY(1,2,3,4,5),
9 T_VARRAY(1,2,3,4,5)
10 );
11 BEGIN
12 FOR I IN 1..V_VAR.COUNT LOOP
13 FOR J IN 1..V_VAR(I).COUNT LOOP
14 DBMS_OUTPUT.PUT_LINE(V_VAR(I)(J));
15 END LOOP;
16 END LOOP;
17 END;
18 /

PL/SQL 过程已成功完成。

Oracle除了数组类型VARRAY之外,还有嵌套表和索引表也都可以实现类似数组的功能,其中索引表的使用更加灵活,方便。

SQL> DECLARE
2 TYPE T_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 V_VAR T_TAB;
4 BEGIN
5 SELECT ROWNUM BULK COLLECT INTO V_VAR FROM USER_OBJECTS
6 WHERE ROWNUM <= 5;
7 FOR I IN 1..V_VAR.COUNT LOOP
8 DBMS_OUTPUT.PUT_LINE(V_VAR(I));
9 END LOOP;
10 END;
11 /

PL/SQL 过程已成功完成。

使用索引表定义数组,不需要指定数组的上限,数组的大小只与内存限制有关。

而且索引组织表定义是指定的索引项并一定要是数值,举个简单的例子:

SQL> DECLARE
2 TYPE T_TAB IS TABLE OF NUMBER INDEX BY VARCHAR2(30);
3 V_VAR T_TAB;
4 V_STR VARCHAR2(30);
5 BEGIN
6 FOR I IN (SELECT OWNER, COUNT(*) CN FROM DBA_TABLES GROUP BY OWNER) LOOP
7 V_VAR(I.OWNER) := I.CN;
8 END LOOP;
9 V_STR := V_VAR.FIRST;
10 WHILE (V_VAR.EXISTS(V_STR)) LOOP
11 DBMS_OUTPUT.PUT_LINE(RPAD(V_STR, 20, ' ') || ':' || V_VAR(V_STR));
12 V_STR := V_VAR.NEXT(V_STR);
13 END LOOP;
14 END;
15 /
CATA_LOG :37
CTXSYS :37
DBSNMP :21
DMSYS :2
EXFSYS :44
HR :7
IX :15
MDSYS :49
OE :12
OLAPSYS :126
ORDSYS :4
OUTLN :3
PM :2
SCOTT :4
SH :17
SYS :706
SYSMAN :337
SYSTEM :141
TSMSYS :1
WMSYS :40
XDB :11
YANGTK :6

PL/SQL 过程已成功完成。

如果构造二维以上的数组,且维度不全是数值,那么就需要注意了:

SQL> DECLARE
2 TYPE T_NUM_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 TYPE T_VAR_TAB IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
4 TYPE T_NUM_VAR IS TABLE OF T_NUM_TAB INDEX BY VARCHAR2(10);
5 TYPE T_VAR_NUM IS TABLE OF T_VAR_TAB INDEX BY BINARY_INTEGER;
6 V_NUM_VAR T_NUM_VAR;
7 V_VAR_NUM T_VAR_NUM;
8 BEGIN
9 V_NUM_VAR(5)('A') := 1;
10 V_VAR_NUM('A')(5) := 1;
11 END;
12 /
DECLARE
*第 1 行出现错误:
ORA-06502: PL/SQL: 数字或值错误 : 字符到数值的转换错误
ORA-06512: 在 line 9


SQL> DECLARE
2 TYPE T_NUM_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 TYPE T_VAR_TAB IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
4 TYPE T_NUM_VAR IS TABLE OF T_NUM_TAB INDEX BY VARCHAR2(10);
5 TYPE T_VAR_NUM IS TABLE OF T_VAR_TAB INDEX BY BINARY_INTEGER;
6 V_NUM_VAR T_NUM_VAR;
7 V_VAR_NUM T_VAR_NUM;
8 BEGIN
9 V_NUM_VAR('A')(5) := 1;
10 V_VAR_NUM('A')(5) := 1;
11 END;
12 /
DECLARE
*第 1 行出现错误:
ORA-06502: PL/SQL: 数字或值错误 : 字符到数值的转换错误
ORA-06512: 在 line 10


SQL> DECLARE
2 TYPE T_NUM_TAB IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
3 TYPE T_VAR_TAB IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
4 TYPE T_NUM_VAR IS TABLE OF T_NUM_TAB INDEX BY VARCHAR2(10);
5 TYPE T_VAR_NUM IS TABLE OF T_VAR_TAB INDEX BY BINARY_INTEGER;
6 V_NUM_VAR T_NUM_VAR;
7 V_VAR_NUM T_VAR_NUM;
8 BEGIN
9 V_NUM_VAR('A')(5) := 1;
10 V_VAR_NUM(5)('A') := 1;
11 END;
12 /

PL/SQL 过程已成功完成。

从这个例子可以看出,用索引表构造的数组和C语言中的数组是有区别的。

Tuesday, April 7, 2009

Oracle DB Link introduction [REF]

1。基本概念:
数据库连接串主要用于建立对远程数据库的访问方法,可以直接读取远程Oracle的数据,或者直接修改。数据库连接串可以是公用连接PUBLIC或者私有连接PRIVATE。这一点和同义词很相像。 其实dblink和数据库中的view差不多,建dblink的时候需要知道待读取数据库的ip地址,ssid以及数据库用户名和密码
1。创建语法:
CREATE DATABASE LINK TEST CONNECT TO USERNAME IDENTIFIED BY PASSWORD
USING 'CONNECT_STRING';
解释:TEST是数据库连接串的名字。以后就通过这个名字来进行调用远程数据库的内容。
USERNAME是用来连接到远程数据库的合法Oracle用户名。PASSWORD为该用户连接到Oracle时候的合法密码。
CONNECT_STRING为该Oracle数据库所在的主机上的tnsnames.ora文件里边定义的数据库连接串。
1) 已经配置本地服务
create public database link fwq12 connect to fzept identified by neu using 'fjept'
 CREATE DATABASE LINK数据库链接名CONNECT TO 用户名 IDENTIFIED BY 密码 USING ‘本地配置的数据的实例名’;
2) 未配置本地服务
create database link linkfwq
   connect to fzept identified by neu
   using '(DESCRIPTION =
   (ADDRESS_LIST =
   (ADDRESS = (PROTOCOL = TCP)(HOST = 10.142.202.12)(PORT = 1521))
   )
   (CONNECT_DATA =
   (SERVICE_NAME = fjept)
   )
   )';

  host=数据库的ip地址,service_name=数据库的ssid。
  其实两种方法配置dblink是差不多的,感觉还是第二种方法比较好,这样不受本地服务的影响。数据库连接字符串可以用NET8 EASY CONFIG或者直接修改TNSNAMES.ORA里定义.

  数据库参数global_name=true时要求数据库链接名称跟远端数据库名称一样
  数据库全局名称可以用以下命令查出
  SELECT * FROM GLOBAL_NAME;
  查询远端数据库里的表
  SELECT …… FROM 表名@数据库链接名;

  查询、删除和插入数据和操作本地的数据库是一样的,只不过表名需要写成“表名@dblink服务器”而已。

  附带说下同义词创建:
  CREATE SYNONYM同义词名FOR 表名;
  CREATE SYNONYM同义词名FOR 表名@数据库链接名;
  删除dblink:DROP PUBLIC DATABASE LINK linkfwq。
  如果创建全局dblink,必须使用systm或sys用户,在database前加public。
2。使用方法:
SELECT COUNT(*) FROM TABLE_NAME@DB_LINK WHERE WHERE_CLAUSE;//查阅远程数据库的内容。

UPDATE TEST.TEST@DB_LINK SET SO_NBR=NEW_SO_NBR
WHERE WHERE_CLAUSE;//修改远程数据库的内容。
在实际使用过程中,还可以通过为这个远程表建立一个同义词来进一步增加透明性,使该数据库连接串对于程序和开发人员来讲完全透明。
CREATE SYNONYM TABLE_NAME FOR TABLE_NAME@DB_LINK;
3。数据库连接的管理:
1) 如何知道当前用户、当前系统中有哪些数据库连接串?
SELECT * FROM USER_DB_LINKS;
这个查询会给出当前用户的数据库联接的名字、联接用户名、联接密码、要连接的主机以及创建时期。
2) SELECT * FROM DBA_DB_LINKS;
这个查询会给出当前系统中所有的数据库联接的创建用户、联接用户名、要连接的主机以及创建时期。
3) SELECT * FROM V$DBLINK;
这个查询会给出当前打开的数据库联接。
4) 删除数据库连接
先从第2)步中查看数据库连接,取得其db_link的名称
sql>drop public database link TEST.US.ORACLE.COM
数据库连接巳丢弃

Thursday, April 2, 2009

使用集合 - Oracle

使用集合

  象记录一样,集合可以在两个层面上使用:

   . 操作整个集合

   . 访问集合中的单个元素

  第一种情况使用集合名,第二种情况使用下标:

   collection(subscript)

  index_by表的下标是两为的整数,可以为正也可以为负,范围是:-2147483647--2147483647。嵌套表和VARRAY表示元素在集合中的位置,用户很难灵活设计下标,这是因为:

   . 嵌套表开始是紧密的(相对于疏松)

   . VARRAY始终保持紧密

   . 这两种集合的下标都由1开始

  初始化、删除、引用集合

  使用集合之前必须要初始化,对于Index_by表初始化是自动进行的,但是对于嵌套表和VARRAY就必须使用内建的构造函数。如果重新调用,嵌套表和VARRAY自动置NULL,这不只是元素置NULL,而是整个集合置NULL。给集合内的元素赋值需要使用下标符号。将一个集合的值赋给另一个集合,只需要简单的使用赋值操作符。

  Index_by集合初始化是最简单的,只要涉及其中的一个元素集合就被初始化了。

  例: 


DECLARE

TYPE symbol_tab_typ IS TABLE OF VARCHAR2(5) INDEX BY BINARY_INTEGER;
TYPE account_tab_typ IS TABLE OF account%ROWTYPE INDEX BY BINARY_INTEGER;
symbol_tab symbol_tab_typ;
account_tab account_tab_typ;
new_acct_tab account_tab_typ;

BEGIN
--初始化集合元素147和-3
SELECT * INTO account_tab(147)
FROM accounts WHERE account_nbr=147;

SELECT * INTO account_tab(-3)
FROM accounts WHERE account_nbr=3003;

IF account_tab(147).balance<500 THEN
chang_maintenance_fee(147);
END IF

new_acct_tab:=account_tab;
symbol_tab(1):="ORCL";
symbol_tab(2):="CSCO";
symbol_tab(3):="SUNM";

publish_portfolio(symbol_tab);

  嵌套表和VARRAY由构造函数初始化,构造函数和集合的名字相同,同时有一组参数,每个参数对应一个元素,如果参数为NULL,那么对应的元素就被初始化为NULL,如果创建了元素,但没有填充数据,那么元素将保持null值,可以被引用,但不能保持数据。如果元素没有初始化,那么就不能引用该元素。

  例:


DECLARE

TYPE stock_list IS TABLE OF stock.symbol%TYPE;
TYPE top10_list IS VARRAY (10) OF stocks.symbol%TYPE;
biotech_stocks stock_list;
tech_10 top10_list;

BEGIN
--非法,集合未初始化。
biotech_stocks(1):='AMGN';
IF biotech_stocks IS NULL THEN
--初始化集合
biotech_stocks:=('AMGN','BGEN',IMCL','GERN',CRA');
END IF;
tech_10:=top10_list('ORCL',CSCO','MSFT','INTC','SUNW','IBM',NULL,NULL);
IF tech_10(7) IS NULL THEN
tech_10(7):='CPQ';
END
tech_10(8):='DELL';


  在这个例子中,嵌套表BIOTECH_STOCKS初始化有5个元素,VARRAY tech_10集合最多能有10 个元素,但构造函数只创建了8个元素,其中还有两个元素是NULL值,并程序中给他们赋值。

  初始化基于记录的集合,就必须将记录传递给构造函数,注意不能只是简单的将记录的域传递给构造函数。

  例:


DECLARE

TYPE stock_quote_rec IS RECORD
(symbol stock.symbol%TYPE
,bid NUMBER(10,4)
,ask NUMBER(10,4)
,volume NUMBER NOT NULL:=0
);
TYPE stock_tab_typ IS TABLE OF stock_quote_rec;
quote_list stock_tab_typ;
single_quote stock_quote_rec;

BEGIN
single_quote.symbol:='OPCL';
single_quote.bid:=100;
single_quote.ask:=101;
single_quote.volume:=25000;
--合法
quote_list:=stock_tab_typ(single_quote);
--不合法
quote_list:=stock_tab_typ('CSCO',75,76,3210000);
DBMS_OUTPUT.LINE(quote_list(1).bid);