ORACLE之常用FAQ V1.0,已经停止更新,准备出chm版本 为便于大家阅读.此帖置顶.请不要在后面跟上一些"好","顶"之类的帖子,如果真的要感谢Piner,请多多提交FAQ.谢谢合作 --by Fenng-----------------------------------------------------------------------------------------------------------------第一部分、SQL&PL/SQL[Q]怎么样查询特殊字符,如通配符%与_[A]select * from table where name like 'A/_%' escape '/'[Q]如何插入单引号到数据库表中[A]可以用ASCII码处理,其它特殊字符如&也一样,如 insert into t values('i'||chr(39)||'m'); -- chr(39)代表字符'或者用两个单引号表示一个or insert into t values('I''m'); -- 两个''可以表示一个'[Q]怎样设置事务一致性[A]set transaction [isolation level] read committed; 默认语句级一致性set transaction [isolation level] serializable;read only; 事务级一致性[Q]怎么样利用游标更新数据[A]cursor c1 is select * from tablename where name is null for update [of column]……update tablename set column = ……where current of c1;[Q]怎样自定义异常[A] pragma_exception_init(exception_name,error_number);如果立即抛出异常raise_application_error(error_number,error_msg,true|false);其中number从-20000到-20999,错误信息最大2048B异常变量SQLCODE 错误代码SQLERRM 错误信息[Q]十进制与十六进制的转换[A]8i以上版本:to_char(100,'XX')to_number('4D','XX')8i以下的进制之间的转换参考如下脚本create or replace function to_base( p_dec in number, p_base in number ) return varchar2 is l_str varchar2(255) default NULL; l_num number default p_dec; l_hex varchar2(16) default '0123456789ABCDEF'; begin if ( p_dec is null or p_base is null ) then return null; end if; if ( trunc(p_dec) <> p_dec OR p_dec < 0 ) then raise PROGRAM_ERROR; end if; loop l_str := substr( l_hex, mod(l_num,p_base)+1, 1 ) || l_str; l_num := trunc( l_num/p_base ); exit when ( l_num = 0 ); end loop; return l_str; end to_base; / create or replace function to_dec ( p_str in varchar2, p_from_base in number default 16 ) return number is l_num number default 0; l_hex varchar2(16) default '0123456789ABCDEF'; begin if ( p_str is null or p_from_base is null ) then return null; end if; for i in 1 .. length(p_str) loop l_num := l_num * p_from_base + instr(l_hex,upper(substr(p_str,i,1)))-1; end loop; return l_num; end to_dec; / [Q]能不能介绍SYS_CONTEXT的详细用法[A]利用以下的查询,你就明白了selectSYS_CONTEXT('USERENV','TERMINAL') terminal,SYS_CONTEXT('USERENV','LANGUAGE') language,SYS_CONTEXT('USERENV','SESSIONID') sessionid,SYS_CONTEXT('USERENV','INSTANCE') instance,SYS_CONTEXT('USERENV','ENTRYID') entryid,SYS_CONTEXT('USERENV','ISDBA') isdba,SYS_CONTEXT('USERENV','NLS_TERRITORY') nls_territory,SYS_CONTEXT('USERENV','NLS_CURRENCY') nls_currency,SYS_CONTEXT('USERENV','NLS_CALENDAR') nls_calendar,SYS_CONTEXT('USERENV','NLS_DATE_formAT') nls_date_format,SYS_CONTEXT('USERENV','NLS_DATE_LANGUAGE') nls_date_language,SYS_CONTEXT('USERENV','NLS_SORT') nls_sort,SYS_CONTEXT('USERENV','CURRENT_USER') current_user,SYS_CONTEXT('USERENV','CURRENT_USERID') current_userid,SYS_CONTEXT('USERENV','SESSION_USER') session_user,SYS_CONTEXT('USERENV','SESSION_USERID') session_userid,SYS_CONTEXT('USERENV','PROXY_USER') proxy_user,SYS_CONTEXT('USERENV','PROXY_USERID') proxy_userid,SYS_CONTEXT('USERENV','DB_DOMAIN') db_domain,SYS_CONTEXT('USERENV','DB_NAME') db_name,SYS_CONTEXT('USERENV','HOST') host,SYS_CONTEXT('USERENV','OS_USER') os_user,SYS_CONTEXT('USERENV','EXTERNAL_NAME') external_name,SYS_CONTEXT('USERENV','IP_ADDRESS') ip_address,SYS_CONTEXT('USERENV','NETWORK_PROTOCOL') network_protocol,SYS_CONTEXT('USERENV','BG_JOB_ID') bg_job_id,SYS_CONTEXT('USERENV','FG_JOB_ID') fg_job_id,SYS_CONTEXT('USERENV','AUTHENTICATION_TYPE') authentication_type,SYS_CONTEXT('USERENV','AUTHENTICATION_DATA') authentication_datafrom dual[Q]怎么获得今天是星期几,还关于其它日期函数用法[A]可以用to_char来解决,如 select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day') from dual; 在获取之前可以设置日期语言,如ALTER SESSION SET NLS_DATE_LANGUAGE='AMERICAN';还可以在函数中指定select to_char(to_date('2002-08-26','yyyy-mm-dd'),'day','NLS_DATE_LANGUAGE = American') from dual; 其它更多用法,可以参考to_char与to_date函数如获得完整的时间格式select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;随便介绍几个其它函数的用法:本月的天数SELECT to_char(last_day(SYSDATE),'dd') days FROM dual今年的天数 select add_months(trunc(sysdate,'year'), 12) - trunc(sysdate,'year') from dual下个星期一的日期SELECT Next_day(SYSDATE,'monday') FROM dual[Q]随机抽取前N条记录的问题[A]8i以上版本select * from (select * from tablename order by sys_guid()) where rownum < N;select * from (select * from tablename order by dbms_random.value) where rownum< N;注:dbms_random包需要手工安装,位于$ORACLE_HOME/rdbms/admin/dbmsrand.sqldbms_random.value(100,200)可以产生100到200范围的随机数[Q]抽取从N行到M行的记录,如从20行到30行的记录[A]select * from (select rownum id,t.* from table where …… and rownum <= 30) where id > 20;[Q]怎么样抽取重复记录[A]select * from table t1 where where t1.rowed !=(select max(rowed) from table t2 where t1.id=t2.id and t1.name=t2.name)或者select count(*), t.col_a,t.col_b from table tgroup by col_a,col_bhaving count(*)>1如果想删除重复记录,可以把第一个语句的select替换为delete[Q]怎么样设置自治事务[A]8i以上版本,不影响主事务pragma autonomous_transaction;……commit|rollback;[Q]怎么样在过程中暂停指定时间[A]DBMS_LOCK包的sleep过程如:dbms_lock.sleep(5);表示暂停5秒。[Q]怎么样快速计算事务的时间与日志量[A]可以采用类似如下的脚本DECLARE start_time NUMBER;end_time NUMBER;start_redo_size NUMBER;end_redo_size NUMBER;BEGINstart_time := dbms_utility.get_time;SELECT value INTO start_redo_size FROM v$mystat m,v$statname s WHERE m.STATISTIC#=s.STATISTIC#AND s.NAME='redo size';--transaction startINSERT INTO t1 SELECT * FROM All_Objects; --other dml statementCOMMIT;end_time := dbms_utility.get_time;SELECT value INTO end_redo_size FROM v$mystat m,v$statname s WHERE m.STATISTIC#=s.STATISTIC#AND s.NAME='redo size';dbms_output.put_line('Escape Time:'||to_char(end_time-start_time)||' centiseconds');dbms_output.put_line('Redo Size:'||to_char(end_redo_size-start_redo_size)||' bytes');END;[Q]怎样创建临时表[A]8i以上版本create global temporary tablename(column list)on commit preserve rows; --提交保留数据 会话临时表on commit delete rows; --提交删除数据 事务临时表临时表是相对于会话的,别的会话看不到该会话的数据。[Q]怎么样在PL/SQL中执行DDL语句[A]1、8i以下版本dbms_sql包2、8i以上版本还可以用execute immediate sql;dbms_utility.exec_ddl_statement('sql');[Q]怎么样获取IP地址[A]服务器(817以上):utl_inaddr.get_host_address客户端:sys_context('userenv','ip_address')[Q]怎么样加密存储过程[A]用wrap命令,如(假定你的存储过程保存为a.sql)wrap iname=a.sqlPL/SQL Wrapper: Release 8.1.7.0.0 - Production on Tue Nov 27 22:26:48 2001Copyright (c) Oracle Corporation 1993, 2000. All Rights Reserved.Processing a.sql to a.plb提示a.sql转换为a.plb,这就是加密了的脚本,执行a.plb即可生成加密了的存储过程[Q]怎么样在ORACLE中定时运行存储过程[A]可以利用dbms_job包来定时运行作业,如执行存储过程,一个简单的例子,提交一个作业:VARIABLE jobno number;BEGINDBMS_JOB.SUBMIT(:jobno, 'ur_procedure;',SYSDATE,'SYSDATE + 1');commit;END;之后,就可以用以下语句查询已经提交的作业select * from user_jobs;[Q]怎么样从数据库中获得毫秒[A]9i以上版本,有一个timestamp类型获得毫秒,如SQL>select to_char(systimestamp,'yyyy-mm-dd hh24:mi:ssxff') time1, to_char(current_timestamp) time2 from dual;TIME1 TIME2----------------------------- ----------------------------------------------------------------2003-10-24 10:48:45.656000 24-OCT-03 10.48.45.656000 AM +08:00可以看到,毫秒在to_char中对应的是FF。8i以上版本可以创建一个如下的java函数SQL>create or replace and compile java sourcenamed "MyTimestamp"asimport java.lang.String;import java.sql.Timestamp;public class MyTimestamp{public static String getTimestamp(){return(new Timestamp(System.currentTimeMillis())).toString();}};SQL>java created.注:注意java的语法,注意大小写SQL>create or replace function my_timestamp return varchar2as language javaname 'MyTimestamp.getTimestamp() return java.lang.String';/SQL>function created.SQL>select my_timestamp,to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') ORACLE_TIME from dual;MY_TIMESTAMP ORACLE_TIME------------------------ -------------------2003-03-17 19:15:59.688 2003-03-17 19:15:59 如果只想获得1/100秒(hsecs),还可以利用dbms_utility.get_time[Q]如果存在就更新,不存在就插入可以用一个语句实现吗[A]9i已经支持了,是Merge,但是只支持select子查询,如果是单条数据记录,可以写作select …… from dual的子查询。语法为:MERGE INTO tableUSING data_sourceON (condition)WHEN MATCHED THEN update_clauseWHEN NOT MATCHED THEN insert_clause;如MERGE INTO course cUSING (SELECT course_name, period,course_hoursFROM course_updates) cuON (c.course_name = cu.course_nameAND c.period = cu.period)WHEN MATCHED THENUPDATESET c.course_hours = cu.course_hoursWHEN NOT MATCHED THENINSERT (c.course_name, c.period,c.course_hours)valueS (cu.course_name, cu.period,cu.course_hours);[Q]怎么实现左联,右联与外联[A]在9i以前可以这么写:左联:select a.id,a.name,b.address from a,b where a.id=b.id(+)右联:select a.id,a.name,b.address from a,b where a.id(+)=b.id外联SELECT a.id,a.name,b.addressFROM a,bWHERE a.id = b.id(+)UNIONSELECT b.id,'' name,b.addressFROM bWHERE NOT EXISTS (SELECT * FROM aWHERE a.id = b.id);在9i以上,已经开始支持SQL99标准,所以,以上语句可以写成:默认内部联结:select a.id,a.name,b.address,c.subjectfrom (a inner join b on a.id=b.id) inner join c on b.name = c.namewhere other_clause左联select a.id,a.name,b.addressfrom a left outer join b on a.id=b.id where other_clause右联select a.id,a.name,b.addressfrom a right outer join b on a.id=b.id where other_clause外联select a.id,a.name,b.addressfrom a full outer join b on a.id=b.id where other_clauseorselect a.id,a.name,b.addressfrom a full outer join b using (id)where other_clause[Q]怎么实现一条记录根据条件多表插入[A]9i以上可以通过Insert all语句完成,仅仅是一个语句,如:INSERT ALLWHEN (id=1) THENINTO table_1 (id, name)values(id,name)WHEN (id=2) THENINTO table_2 (id, name)values(id,name)ELSEINTO table_other (id, name)values(id, name)SELECT id,nameFROM a;如果没有条件的话,则完成每个表的插入,如INSERT ALLINTO table_1 (id, name)values(id,name)INTO table_2 (id, name)values(id,name)INTO table_other (id, name)values(id, name)SELECT id,nameFROM a;[Q]如何实现行列转换[A]1、固定列数的行列转换如student subject grade---------------------------student1 语文 80student1 数学 70student1 英语 60student2 语文 90student2 数学 80student2 英语 100……转换为 语文 数学 英语student1 80 70 60student2 90 80 100……语句如下:select student,sum(decode(subject,'语文', grade,null)) "语文",sum(decode(subject,'数学', grade,null)) "数学",sum(decode(subject,'英语', grade,null)) "英语"from tablegroup by student2、不定列行列转换如c1 c2--------------1 我1 是1 谁2 知2 道3 不……转换为1 我是谁2 知道3 不这一类型的转换必须借助于PL/SQL来完成,这里给一个例子CREATE OR REPLACE FUNCTION get_c2(tmp_c1 NUMBER) RETURN VARCHAR2 IS Col_c2 VARCHAR2(4000); BEGINFOR cur IN (SELECT c2 FROM t WHERE c1=tmp_c1) LOOP Col_c2 := Col_c2||cur.c2; END LOOP; Col_c2 := rtrim(Col_c2,1);RETURN Col_c2; END;/SQL> select distinct c1 ,get_c2(c1) cc2 from table;即可[Q]怎么样实现分组取前N条记录[A]8i以上版本,利用分析函数如获取每个部门薪水前三名的员工或每个班成绩前三名的学生。Select * from (select depno,ename,sal,row_number() over (partition by depnoorder by sal desc) rn from emp)where rn<=3[Q]怎么样把相邻记录合并到一条记录[A]8i以上版本,分析函数lag与lead可以提取后一条或前一天记录到本记录。Select deptno,ename,hiredate,lag(hiredate,1,null) over(partition by deptno order by hiredate,ename) last_hirefrom emporder by depno,hiredate[Q]如何取得一列中第N大的值?[A]select * from (select t.*,dense_rank() over (order by t2 desc) rank from t) where rank = &N;[Q]怎么样把查询内容输出到文本[A]用spool如如sqlplus –s " / as sysdba" <<EOFset heading offset feedback offspool temp.txt select * from tab;dbms_output.put_line(‘test’);spool offexitEOF[Q] 如何在SQL*PLUS环境中执行OS命令?[A] 比如进入了SQLPLUS,启动了数据库,忽然想起监听还没有启动,此时不用退出SQLPLUS,也不用另外起一个命令行窗口,直接输入: SQL> host lsntctl start 或者unix/linux平台下SQL>!<OS command>windows平台下SQL>$<OS command>总结:HOST <OS command>可以直接执行OS命令。 备注:cd命令无法正确执行。[Q]怎么设置存储过程的调用者权限[A]普通存储过程都是所有者权限,如果想设置调用者权限,请参考如下语句create or replaceprocedure ……()AUTHID CURRENT_USERAsbegin……end;[Q]怎么快速获得用户下每个表或表分区的记录数[A]可以分析该用户,然后查询user_tables字典,或者采用如下脚本即可SET SERVEROUTPUT ON SIZE 20000DECLAREmiCount INTEGER;BEGINFOR c_tab IN (SELECT table_name FROM user_tables) LOOPEXECUTE IMMEDIATE 'select count(*) from "' || c_tab.table_name || '"' into miCount;dbms_output.put_line(rpad(c_tab.table_name,30,'.') || lpad(miCount,10,'.'));--if it is partition tableSELECT COUNT(*) INTO miCount FROM User_Part_Tables WHERE table_name = c_tab.table_name;IF miCount >0 THENFOR c_part IN (SELECT partition_name FROM user_tab_partitions WHERE table_name = c_tab.table_name) LOOPEXECUTE IMMEDIATE 'select count(*) from ' || c_tab.table_name || ' partition (' || c_part.partition_name || ')' INTO miCount;dbms_output.put_line(' '||rpad(c_part.partition_name,30,'.') || lpad(miCount, 10,'.'));END LOOP;END IF;END LOOP;END;[A]怎么在Oracle中发邮件[Q]可以利用utl_smtp包发邮件,以下是一个发送简单邮件的例子程序/****************************************************************************parameter: Rcpter in varchar2 接收者邮箱Mail_Content in Varchar2 邮件内容desc: ·发送邮件到指定邮箱·只能指定一个邮箱,如果需要发送到多个邮箱,需要另外的辅助程序****************************************************************************/CREATE OR REPLACE PROCEDURE sp_send_mail( rcpter IN VARCHAR2,mail_content IN VARCHAR2)IS conn utl_smtp.connection;--write titlePROCEDURE send_header(NAME IN VARCHAR2, HEADER IN VARCHAR2) ASBEGINutl_smtp.write_data(conn, NAME||': '|| HEADER||utl_tcp.CRLF);END;BEGIN--opne connectconn := utl_smtp.open_connection('smtp.com');utl_smtp.helo(conn, 'oracle');utl_smtp.mail(conn, 'oracle info');utl_smtp.rcpt(conn, Rcpter);utl_smtp.open_data(conn);--write titlesend_header('From', 'Oracle Database');send_header('To', '"Recipient" <'||rcpter||'>');send_header('Subject', 'DB Info');--write mail contentutl_smtp.write_data(conn, utl_tcp.crlf || mail_content);--close connect utl_smtp.close_data(conn);utl_smtp.quit(conn);EXCEPTIONWHEN utl_smtp.transient_error OR utl_smtp.permanent_error THENBEGINutl_smtp.quit(conn);EXCEPTIONWHEN OTHERS THENNULL;END;WHEN OTHERS THENNULL;END sp_send_mail;[A]怎么样在Oracle中写操作系统文件,如写日志[Q]可以利用utl_file包,但是,在此之前,要注意设置好Utl_file_dir初始化参数/**************************************************************************parameter:textContext in varchar2 日志内容desc: ·写日志,把内容记到服务器指定目录下·必须配置Utl_file_dir初始化参数,并保证日志路径与Utl_file_dir路径一致或者是其中一个****************************************************************************/ CREATE OR REPLACE PROCEDURE sp_Write_log(text_context VARCHAR2)ISfile_handle utl_file.file_type;Write_content VARCHAR2(1024);Write_file_name VARCHAR2(50);BEGIN--open filewrite_file_name := 'db_alert.log';file_handle := utl_file.fopen('/u01/logs',write_file_name,'a');write_content := to_char(SYSDATE,'yyyy-mm-dd hh24:mi:ss')||'||'||text_context;--write fileIF utl_file.is_open(file_handle) THENutl_file.put_line(file_handle,write_content);END IF;--close fileutl_file.fclose(file_handle);EXCEPTIONWHEN OTHERS THENBEGINIF utl_file.is_open(file_handle) THENutl_file.fclose(file_handle);END IF;EXCEPTIONWHEN OTHERS THENNULL;END;END sp_Write_log;
转载请注明原文地址: https://ibbs.8miu.com/read-4150.html