查詢空表,一列,select 2013 AS year from dual。
PLSQL輸出語句DBMS_OUTPUT.PUT_LINE(***)。
在output可以看到結(jié)果,相當(dāng)于java的system.out.println 和 c++的 cout
但是pl/sql的比較弱,不能實(shí)時(shí)展示結(jié)果,要運(yùn)行到end才會(huì)一次性顯示結(jié)果。
而且在一個(gè)存儲(chǔ)過程中不能使用太多次DBMS_OUTPUT.PUT_LINE,由于一次性輸出,所以在執(zhí)行到END之前,輸出函數(shù)都會(huì)將結(jié)果保存在緩存區(qū)。用太多次會(huì)導(dǎo)致緩沖區(qū)放不下,會(huì)報(bào)錯(cuò)噠。
case when ... then ... else ... end 作用類似于decode函數(shù)。
SELECT grade, COUNT (CASE WHEN sex = 1 THEN 1 /*sex 1為男生,2位女生*/
ELSE NULL END) 男生數(shù), COUNT (CASE WHEN sex = 2 THEN 1 ELSE NULL END) 女生數(shù) FROM students GROUP BY grade;
除此之外,在CASE WHEN 里面可以使用EXISTS關(guān)鍵字,例如:
CASE EXISTS(SELECT 1 FROM TABLE1 T1 WHERE T1.COL1=T2.COL1) THEN 1ELSE 0 END,....
select /*+parallel(a,4)*/ * from a 其中/*+parallel(a,4)*/表示多個(gè)線程并行執(zhí)行,能夠提高速度。
/*+提示信息*/ 用于SQL語句優(yōu)化。
sql中的游標(biāo)用在多行語句中,游標(biāo)類似于C++中的指針,或者java中的iterator能夠一行一行的迭代多行數(shù)據(jù)。
定義記錄類型相當(dāng)于定義一個(gè)含有多個(gè)返回值的類。
觸發(fā)器:當(dāng)事件被觸發(fā)時(shí)隱式的執(zhí)行,事件指update,insert,delete...
oracle執(zhí)行一條字符串sql語句的方法為:
declare
sql varchar2(100);
begin
sql := .....;
execute immediate command;
end;
WITH ... AS 用法
with
sql1 as (select to_char(a) s_name from test_tempa),
sql2 as (select to_char(b) s_name from test_tempb where not exists (select s_name from sql1 where rownum=1))
select * from sql1
union all
select * from sql2
union all
select 'no records' from dual
where not exists (select s_name from sql1 where rownum=1)
and not exists (select s_name from sql2 where rownum=1)
遇到長的sql多用with as 分開sql的各個(gè)部分也方便后期修改。
如果要加快數(shù)據(jù)庫查詢的速度,可以采用不寫日志和并發(fā)的方式執(zhí)行,具體方法可以上網(wǎng)找,因?yàn)閿?shù)據(jù)庫幾乎所有操作都會(huì)寫日志,所以不寫日志對(duì)于查詢數(shù)據(jù)過大的情況會(huì)加快很多。
如果不采用pl/sql直接進(jìn)入oracle服務(wù)器,可以采用指令對(duì)數(shù)據(jù)庫進(jìn)行操作。
PL\SQL在字符串中使用單引號(hào)“'”
在字符串中使用“''”,兩個(gè)連接單引號(hào)可以表示一個(gè)單引號(hào),第一個(gè)單引號(hào)表示“跳過”
例如:
select 'select * from table where name = ''yanghuanbin'' ' from dual;
輸出結(jié)果為:
select * from table where name = 'yanghuanbin'
特殊符號(hào)ascii定義
制表符 chr(9)
換行符 chr(10)
回車符 chr(13)
在存儲(chǔ)過程中返回多行需要用到游標(biāo):
DECLARE
query_sqlvarchar2(100);
queryresultvarchar2(50);
bizcursorSYS_REFCURSOR;
typemy_recordisrecord(
servidNUMBER(16),
custidNUMBER(16));
my_rec my_record;
BEGIN
query_sql:='select servid,custid from sys_servst where rownum<10';
OPENbizcursorFORquery_sql;
loop
fetchbizcursorintomy_rec;
--判讀是否提取到值,沒取到值就退出
--取到值c_job%notfound 是false
--取不到值c_job%notfound 是true
exitwhenbizcursor%notfound;
dbms_output.put_line(my_rec.servid||' '||my_rec.custid);
endloop;
--關(guān)閉游標(biāo)
closebizcursor;
END;
存儲(chǔ)過程中執(zhí)行動(dòng)態(tài)sql,可以使用
executeimmediate 如下例子(注意
executeimmediate 只可以使用在返回一行的sql中):
--執(zhí)行動(dòng)態(tài)sql
declare
v_sqlvarchar2(100) :='drop table test_'||'YF';
begin
executeimmediatev_sql;
end;
--execute immediate 還可以用在存儲(chǔ)過程的賦值中:
declare
l_cntvarchar2(20);
begin
executeimmediate'select count(1) from emp'
intol_cnt;
dbms_output.put_line(l_cnt);
end;
在pl/sql的函數(shù)中不能調(diào)用DDL語句,要使用DDL語句只能寫在存儲(chǔ)過程中。啟動(dòng)存儲(chǔ)過程的方式 call produce_name.定義無參函數(shù)和無參存儲(chǔ)過程的時(shí)候,函數(shù)名(存儲(chǔ)過程名)后面不要加括號(hào)。但是在調(diào)用的時(shí)候,無參函數(shù)或無參存儲(chǔ)過程后面的括號(hào)不能省略。
例如:
定義時(shí)
CREATEORREPLACEProceduretruncate_boCheckTable as begin ....調(diào)用時(shí)
calltruncate_boCheckTable();將一個(gè)表的數(shù)據(jù)插入到另一個(gè)表:
1.不新建表:
insert into table1 select col1,col2,col3 from table2;
要求插入select的字段在table1中有。
2.新建表:
create table1 as select col1,col2,col3 from table2;
創(chuàng)建的表和select出來的字段是同類型。如果多個(gè)表連接速度太慢,我們可以先連接出一個(gè)中間表,然后再連接大表。要把大表分開,不要放在一起連接。
exists和子查詢都比自然連接快得多。PL/SQL debug
選中存儲(chǔ)過程的名字右鍵單擊.選中"Add debug infomation"選項(xiàng).會(huì)彈出一個(gè)提示框,點(diǎn)擊"oK"即可
選中存儲(chǔ)過程的名字右鍵單擊.選中"Test"選項(xiàng),進(jìn)入存儲(chǔ)過程的測試頁面.如圖
按著Ctrl,鼠標(biāo)單擊.進(jìn)入"view"視圖.,找到自己要調(diào)試的行.單擊設(shè)置斷點(diǎn).然后進(jìn)入測試頁面.單擊"Start debugger"按鈕,或者是"F9",然后點(diǎn)擊"run"按鈕."step into"跳入."step over"跳過,"step out"跳出.慢慢調(diào)試即可
pl/sql order by 默認(rèn)升序排列dba_objects/all_objects/user_objects
在oracle數(shù)據(jù)庫中有dba/all/user三種范圍的視圖,其中dba表示整個(gè)數(shù)據(jù)庫,all表示當(dāng)前用戶可見的,user表示當(dāng)前用戶擁有的。所以有dba>=all>=user。具體使用有如下的例子(查數(shù)據(jù)庫中的所有表):
SELECT*FROMdba_objects tWHEREt.OBJECT_TYPE='TABLE';
dba/all/user下有很多的視圖,就像下面這樣:
可以用dba/all/user 加下劃線在pl/sql中直接查看有什么視圖,可以查詢什么內(nèi)容。
修改列對(duì)應(yīng)操作:
對(duì)字段操作 | 操作方法 |
更新字段名 | alter table TABLE_NAME rename column column_old to column_new; |
添加字段 | alter table TABLE_NAME add COLUMN_NAME varchar(10); |
刪除字段 | alter table TABLE_NAME drop column COLUMN_NAME; |
添加字段并附值 | alter table TABLE_NAME ADD COLUMN_NAME NUMBER(1) DEFAULT 1; |
修改字段值 | update TABLE_NAME set filedname=value where filedname=value; |
修改字段數(shù)據(jù)類型 | alter table tablename modify filedname varchar2(20); |
oracle表連接和優(yōu)化
如果在sql語句沒有聚集函數(shù)的情況下使用group by ,這個(gè)group by 的效果和distinct一樣purge關(guān)鍵字用法:
oracle在用drop刪除表之后,會(huì)把表放入類似回收站的地方,使用 drop table tableName purge; 這樣語句就能將表徹底刪除,不放入回收站,但是這樣刪除表格就不能還原了。在update語句中使用聚集函數(shù),會(huì)很慢。例如下面這句sql就執(zhí)行很慢
UPDATETMP.TMP_SALESPKG_NUMS_DG T1SETT1.TIMES=
(SELECTCOUNT(1)FROMNODS.TO_BIZ_SALESPKG_DG T2WHERET2.SERIALNO=T1.SERIALNOANDT2.SALESPKGID=T1.SALESPKGID);
可以先把需要的信息放在另一個(gè)新建表里,在關(guān)聯(lián)表存進(jìn)去。
把上面的變成下面這樣:
CREATETABLETMP.TMP_SERIPKG_TIMESAS
SELECTT1.SERIALNO,T1.SALESPKGID,COUNT(1) TIMES FROM NODS.TO_BIZ_SALESPKG_DG T1 WHERE
EXISTS(SELECT1FROMTMP.TMP_SALESPKG_NUMS_DG T2WHERET1.SERIALNO=T2.SERIALNOANDT1.SALESPKGID=T2.SALESPKGID)
GROUPBYT1.SERIALNO,T1.SALESPKGID;
UPDATETMP.TMP_SALESPKG_NUMS_DG T1SETT1.TIMES=
(SELECTT2.TIMESFROMTMP.TMP_SERIPKG_TIMES T2WHERET1.SERIALNO=T2.SERIALNOANDT1.SALESPKGID=T2.SALESPKGID);
COMMIT;
數(shù)據(jù)庫交、并、差集運(yùn)算
1.并集的運(yùn)算
select name from test1
union [all]
select name from test2;
使用union時(shí),默認(rèn)將對(duì)結(jié)果進(jìn)行排序,union all則不進(jìn)行排序操作,所以會(huì)消耗更少的資源;然而,union all將不進(jìn)行去重的操作~
2.交集的運(yùn)算
select name from test1
intersect
select name from test2;
Oracle不支持Intersect all關(guān)鍵字!
3.差的運(yùn)算
select name from test1
minus
select name from test2;
Oracle中差的運(yùn)算不同于SQL標(biāo)準(zhǔn),在SQL標(biāo)準(zhǔn)中,我們使用以下函數(shù)進(jìn)行差運(yùn)算
select name from test1
except [all]
select name from test2;
PL/SQL 三種參數(shù)類型,in/out/in outin參數(shù)在函數(shù)和存儲(chǔ)過程內(nèi)部不能被修改,也就是in參數(shù)不能放在:=左邊,
out參數(shù)在函數(shù)和存儲(chǔ)過程中只能被賦值,不能給其他參數(shù)賦值,也就是不能放在:=右邊,可以將結(jié)果帶出存儲(chǔ)過程或函數(shù)。
in out參數(shù)在函數(shù)和存儲(chǔ)過程中,能被賦值也能為別的參數(shù)賦值,綜合了兩者。
其中
in 是參數(shù)的
默認(rèn)模式。
例子如下:
/*以下存儲(chǔ)過程測試用,用來區(qū)分 in/out/in out 的用法
以下過程可以交換參數(shù) num3,num4; num1和num2參數(shù)只是用來測試。*/
createorreplaceprocedureswaptest(num1innumber,num2outnumber,num3inoutnumber,num4inoutnumber)
is
tmpnumnumber;
begin
/*以下legal 如果寫成 num1:=10 就會(huì)編譯失敗,in參數(shù)只能放在:=的右邊,
in參數(shù)就是常量,在存儲(chǔ)過程和函數(shù)這種不能修改。*/
tmpnum := num1;
DBMS_OUTPUT.PUT_LINE('tmpnum='||tmpnum);
/*以下legal,如果寫成tmpnum:=num2 就會(huì)編譯失敗,out參數(shù)只能放:=的左邊,
也就是說out 只能被賦值,而且賦值之后out參數(shù)還能帶回到函數(shù)或存儲(chǔ)過程外部*/
num2 := tmpnum;
DBMS_OUTPUT.PUT_LINE('num2='||num2);
/*以下實(shí)現(xiàn)num3和num4數(shù)字的交換,并且將交換結(jié)果傳遞到存儲(chǔ)過程外部,
inout參數(shù)可以在:=的左邊右邊都行*/
num3 := num3+num4;
num4 := num3-num4;
num3 := num3-num4;
end;
--注意,out和inout參數(shù)只能傳入變量作為參數(shù),所以以下調(diào)用會(huì)報(bào)錯(cuò):
callswaptest(1,2,3,4);
調(diào)用以上存儲(chǔ)過程例子:
declare
num2number:=20;
num3number:=30;
num4number:=40;
begin
swaptest(10,num2,num3,num4);
DBMS_OUTPUT.PUT_LINE('num2='||num2);
DBMS_OUTPUT.PUT_LINE('num3='||num3);
DBMS_OUTPUT.PUT_LINE('num4='||num4);
end;
結(jié)果如下:
%TYPE 使用%type給變量設(shè)置類型,可以動(dòng)態(tài)的綁定數(shù)據(jù)類型。
例如:
v_custid sys_cust.custid%type ;
表示將sys_cust表custid字段的類型,賦給v_custid。
復(fù)合數(shù)據(jù)類型:type type_name is {record|table|varray} 加上%rowtype一共4種方法。
record:可以將多個(gè)數(shù)據(jù)類型定義到一個(gè)type_name里。
TYPE record_type IS RECORD( var_name1 type [,var_name2 type…] );
table:建立一個(gè)索引數(shù)組。
varray:建立一個(gè)變長數(shù)組。
%rowtype類似%type:可以將一個(gè)復(fù)合數(shù)據(jù)類型或一個(gè)表的字段類型全部賦值給特定的type_name,
例如:v_cust sys_cust%rowtype就是將 sys_cust表的所有字段類型賦給v_cust類型。
exists與in對(duì)比一般來說exists比in快得多,優(yōu)化sql的時(shí)候建議用exists代替in。
( 如果子查詢得出的結(jié)果集記錄較少,主查詢中的表較大且又有索引時(shí)應(yīng)該用in,反之如果外層的主查詢記錄較少,子查詢中的表大,又有索引時(shí)使用exists。)
同義詞:私有同義詞,只能被當(dāng)前用戶使用:
Create[ORREPLACE]SYNONYM[schema.]synonym_nameFOR[schema.]object_name;
公有同義詞,可以被所有用戶使用:
CreatePUBLICSYNONYMsynonym_nameFOR[schema.]object_name;
=>操作符的作用:
=>操作符可以在使用存儲(chǔ)過程,函數(shù)的時(shí)候,指定參數(shù)名賦值,不按順序。和python 調(diào)用函數(shù)的時(shí)候,指定參數(shù)名進(jìn)行賦值的作用是一樣的。
例如,我創(chuàng)建一個(gè)存儲(chǔ)過程如下:
createorreplaceprocedureyhb_test(str1invarchar2,str2invarchar2)as
begin
dbms_output.put_line(str1);
dbms_output.put_line(str2);
end;
則,
callyhb_test('1111','22222');
輸出:
callyhb_test(str2=>'1111',str1=>'22222');
輸出:
defult關(guān)鍵字給參數(shù),表字段設(shè)置默認(rèn)值。
例如:
createorreplaceprocedureyhb_test(str1invarchar2default11111,str2invarchar2)as 。。。oracle exit與return區(qū)別。exit :退出循環(huán)。
return :退出函數(shù)或存儲(chǔ)過程。
oracle 解鎖:一些ORACLE中的進(jìn)程被殺掉后,狀態(tài)被置為"killed",但是鎖定的資源很長時(shí)間不釋放,
有時(shí)實(shí)在沒辦法,只好重啟數(shù)據(jù)庫。現(xiàn)在提供一種方法解決這種問題,那就是在ORACLE中殺不掉的,在OS一級(jí)再殺。1.下面的語句用來查詢哪些對(duì)象被鎖:
selectobject_name,machine,s.sid,s.serial#
fromv$locked_object l,dba_objects o ,v$session s
wherel.object_id = o.object_idandl.session_id=s.sid;
2.下面的語句用來殺死一個(gè)進(jìn)程:
--其中24,111分別是上面查詢出的sid,serial#
altersystemkillsession'24,111';
【注】以上兩步,可以通過Oracle的管理控制臺(tái)來執(zhí)行。3.如果利用上面的命令殺死一個(gè)進(jìn)程后,進(jìn)程狀態(tài)被置為"killed",但是鎖定的資源很長時(shí)間沒有被釋放,
那么可以在os一級(jí)再殺死相應(yīng)的進(jìn)程(線程),首先執(zhí)行下面的語句獲得進(jìn)程(線程)號(hào):
--24是上面的sid
selectspid, osuser, s.program
fromv$session s,v$process pwhere
s.paddr=p.addrands.sid=24
4.在OS上殺死這個(gè)進(jìn)程(線程):1)在unix上,用root身份執(zhí)行命令:#kill -9 12345(即第3步查詢出的spid)2)在windows(unix也適用)用orakill殺死線程,orakill是oracle提供的一個(gè)可執(zhí)行命令,語法為:orakill sid thread其中:sid:表示要?dú)⑺赖倪M(jìn)程屬于的實(shí)例名thread:是要?dú)⒌舻木€程號(hào),即第3步查詢出的spid。例:c:>orakill orcl 12345
oracle 遞歸createorreplacefunctionyhb_test(ninnumber)returnnumber
is
begin
ifn=0then
return1;
elsifn=1then
return1;
else
returnyhb_test(n-1)+yhb_test(n-2);
endif;
end;
SELECTyhb_test(5)fromdual;
左右連接:--table2是主表
fromtable1 t1rightjointable2 t2ont1.col1=t2.col1;
--table1是主表
fromtable1 t1leftjointable2 t2ont1.col1=t2.col1;
(+)在哪邊,哪邊就是小表,另一邊就是主表。
a(+)=b,b所在的表就是主表。
綁定變量:
例子:declare
l_sql varchar2(2000);
l_count number;
l_param1 varchar2(100);
l_param2 varchar2(100);
begin
l_param1:=’a';
l_param2:=’b';
l_sql:=’select count(*) into :x from table1 where col_1=:y and col_2=:z ’;
Execute Immediate l_sql into l_count using l_param1,l_param2;
dbms_output.put_line(l_count);
end;
/
:x,:y,:z相當(dāng)于占位符
綁定變量說明:變量綁定 是指在sql語句的條件中使用變量而不是常量。比如shared pool里有兩條sql語句,
select * from tab1 where col1=1;
select * from tab1 where col1=2;
對(duì)oracle數(shù)據(jù)庫來說,這是兩條完全不同的SQL,對(duì)這兩條語句都需要進(jìn)行hard parse。因?yàn)閛racle會(huì)根據(jù)sql語句的文本去計(jì)算每個(gè)字符在內(nèi)存里的hash值,因此雖然上述兩條SQL只有一個(gè)字符不一樣,oracle根據(jù)hash算法在內(nèi)存中得到的hash地址就不一樣,所以oracle就會(huì)認(rèn)為這是兩條完全不同的語句。而如果將上述SQL改寫成select * from tab1 where col1=:var1;,然后通過對(duì)變量var1的賦值去查詢,那么oracle對(duì)這條語句第一次會(huì)進(jìn)行hard parse,以后就只進(jìn)行soft parse。假設(shè)某條語句被重復(fù)執(zhí)行了幾十萬次,那么使用bind var帶來的好處是巨大的。一個(gè)應(yīng)用程序如果bind var使用不充分,那么幾乎一定會(huì)伴隨著嚴(yán)重的性能問題。
多次重復(fù)的sql就用綁定變量,這對(duì)數(shù)據(jù)庫性能有很大好處。
select...into...for update:Select…For Update語句的語法與select語句相同,只是在select語句的后面加FOR UPDATE [NOWAIT]子句。
該語句用來鎖定特定的行(如果有where子句,就是滿足where條件的那些行)。當(dāng)這些行被鎖定后,其他會(huì)話可以選擇這些行,但不能更改或刪除這些行,直到該語句的事務(wù)被commit語句或rollback語句結(jié)束為止。
例子:
SELECTtype,curid
INTOv_type,v_curid
FROMprv_serial
WHEREname= seq_nameFORUPDATE;
標(biāo)記符號(hào)<<>>:
plsql(oracle的編程語言)的標(biāo)記符號(hào),常用來跳出循環(huán)。使用goto可以跳到標(biāo)記<<outer>>的位置,舉例如下:for i in 1..100 loop if i > 10 then goto outer;
end if; end loop; <<outer>> dbms_output.put_line('loop 循環(huán)了10次提前結(jié)束了!' );