碎點篇—— oracle 語法和練習
阿新 • • 發佈:2020-02-01
--select from where having group by order by 的正確執行順序為: --from-->where-->group by-->having-->select-->order by -------------------------------------------------------- --1、去重:distinct 必須放在開頭,多欄位,每個欄位不一樣才去重 --2、條件比較: -- =,!=,<>,<,>,<=,>=,any,some,all -- is null,is not null -- between x and y -- in(list),not in (list) -- like _,%,escape '\' _\%escape '\' -- not,(and,or) and優先順序高 -- 按照單個列排序 -- order by col -- 降序排列:order by col desc -- 升序排列:order by col asc -- 按多個列排序:(優先順序) -- order by col1 desc(asc),col2 desc(asc) --1.全集:union all --2.並集:union (去重) --3.交集:intersect --4.差集:minus --5.不懂怎麼用,就選擇 (*) ----------------------------------------------------------- --基本查詢語句 select * from emp; select e.ename,e.sal from emp e where e.sal>1500; select distinct e.deptno,d.dname from emp e,dept d; --------------------------------------------------------- --組函式又被稱作集合函式,用於對多行資料進行操作,並返回一個單一的結果 --組函式僅用於選擇列表或查詢的having子句單行函式對單個數值進行操作,並 --返回一個值。 --concat(string2,string3)連線兩個字串 --initcap(string) string中每個單詞首字母大寫 --lower(string) string 中每個單詞首字母小寫 --lpad,rpad 填充字元型資料 --ltrim/rtrim (string2,string3) trim(A from B) --substr() 提取字串的一部分substr(string,1,2) --upper(string)以大寫形式返回string --instr() 字串出現的位置,instr(string,'A') --length() 字串長度 ------------------------------------------------------- --round(number,n):返回四捨五入的值 select round(23.434) from dual; select round(23.434,2) from dual; select round(23.436,2) from dual; select round(23.434,-1) from dual; --trunc(number,n): 返回擷取的值 select trunc(23.434) from dual; select trunc(23.434,2) from dual; select trunc(23.436,2) from dual; select trunc(23.434,-1) from dual; --mod(x,y):求餘數 select mod(13,5) from dual; --ceil(number):向上取整 select ceil (19.2) from dual; --floor(number):向下取整 select floor(19.2) from dual; --avg(): 返回某列的平均值 --min(): 返回某列的最小值 --max(): 返回某列的最大值 --sum(): 返回某列值的和 --count(): 返回某列的行數 --組函式僅在選擇列表和having子句中有效 --group by 子句 --group by 子句可以包含任意數目的列 --除組函式語句外,select 語句中的每個列都必須在 group by 子句中給出。 --如果分組列中具有null值,則null將作為一個分組返回。如果列中有多行null --值,他們將分為一組。 --group by 子句必須出現在where 子句之後,order by 子句之前。 --過濾分組(having子句) --where 過濾行, --having 過濾分組 --having 支援所有的where操作 --分組和排序 --一般在使用group by 子句時,應該給出 order by 子句 --資料來自於多張表,92表連線 --注意:明確引用同名的列,必須使用表名,或者別名區分 --1.笛卡爾積: -- select 欄位列表 from 表1,表2,表3.... --2.等值連線:取關係列相同的記錄 -- select 欄位列表 from 表1,表3.... -- where 表1.列 = 表2.列 and 表1.列 =表3.列 --3.非等值連線:取關係列不同的記錄 != > < >= <= between and -- select 欄位列表 from 表1,表3.... -- where 表1.列 != 表2.列 and 表1.列 != 表3.列 --4.自連線:(特殊的等值連線) 列來自於同一張表,不同角度看待表 -- select 欄位列表 from 表1 e,表2 d -- where e.列1 = d.列3 --5.外連線:在等值基礎上,確保一張表(主表) 的記錄都存在,從 -- 表滿足則匹配,不滿足補充null --右外:主表在右邊 --左外:主表在左邊 --sql1992:的語法規則暴露了這樣額缺點:語句過濾條件和表連線的條件 -- 都放到了where子句中。當條件過多時,聯結條件多,過濾條件 -- 多時,就容易造成混淆 --sql1999:修正了這個缺點,把聯結條件,過濾條件分開來,包括以下新的table -- join 的句法結構: --cross join --natural join --using 子句 --on 子句 --left outer join --right outer join --full outer join ------------------------------------------------------- --建立檢視 --with read only 表示只讀 create or replace view v_emp_dept_a as select e.deptno,e.ename,d.dname from emp e join dept d on e.deptno= d.deptno with read only ; select * from v_emp_dept_a; --當不再需要檢視的時候,用"drop view"撤銷。刪掉檢視不會導致資料的丟失 --因為檢視是基於資料庫的表之上的一個查詢定義 drop view v_emp_dept_a; --建立檢視必須要有主鍵,不然無法插入資料。 create or replace view v_emp_dept_b as select e.empno,e.sal,e.deptno from emp e; select * from v_emp_dept_b; --DML insert into v_emp_dept_b (empno,ename,sal) values(2000,'zhiyi',3554); update v_emp_dept_b set ename='weiwo',deptno=20 where ename='zhiyi'; delete from v_emp_dept_b where ename like 'weiwo' ----------------------------------------------------------------------- --我們要求平均薪水的等級最低的部門,它的部門名稱是什麼? --我們完全使用子查詢 --求部門的平均薪水 select e.deptno dt,avg(e.sal) avg_sal from emp e group by deptno; --建立子類檢視 create or replace view deptno_avg_sal_a as select e.deptno dt,avg(e.sal) avg_sal from emp e group by deptno; select * from deptno_avg_sal_a; --求部門薪水的等級 select t.dt dl,s.grade gr from deptno_avg_sal_a t join salgrade s on t.avg_sal between losal and hisal; --建立子類檢視 create or replace view dept_grade_a as select t.dt dl,s.grade gr from deptno_avg_sal_a t join salgrade s on t.avg_sal between losal and hisal; select * from dept_grade_a; --求出最低等級 select min(gr) from dept_grade_a; --求出部門名字 select d.dname from dept_grade_a de join dept d on de.dl = d.deptno where de.gr = (select min(gr) from dept_grade_a); select * from dept; --刪除檢視 drop view dept_grade_a; drop view deptno_avg_sal_a; drop view v_emp_dept_b; ---------------------------------------------------------------------- --建立表 create table temp as select *from emp where 1=2; ----where 1=2 建立的是空表單 select * from temp; create table temp2 as select *from emp where 1=1; select * from temp2; ----where 1=1 建立的是全部資料的表單 --插入資料 insert into temp select * from emp; --刪除表單 drop table temp; drop table temp2; --------------------------------------------------------------------- --number(x,y) : 數字型別,最長x x位,y y位小數 --varchar2(maxlength) : 變長字串,這個引數的上限是32767位元組。 -- 宣告方式如下 varchar2(L L),L L 為字串長度, -- 沒有預設值,作為變數最大32767個位元組 --char(max_length) : 定長字串 ,最大2000個位元組 --date : 日期型別(只能精確到秒) --timestamp : 時間戳(精確到微秒) --long : 長字串,最大 2GB --瞭解型別 --clob : 最大長度4G -->大物件很少使用:如果存在大物件,一般的解決方案 -- 存入檔案地址(地址為程式所在應用伺服器的相對路徑) --blob : 存二進位制檔案 --主鍵約束是資料庫中最重要的一種約束。在關係中,主鍵值不可為空,也不 --允許出現重複,即關係要滿足實體完整性規則。 --主鍵從功能上看相當於非空且唯一 --一個表中只允許一個主鍵 --主鍵是表中能夠唯一確定一個行資料的欄位 --主鍵欄位可以是單欄位或者多欄位的組合 --oracle為主鍵建立對應的唯一性索引。 ------------------------------------------------------------------- --procedural language和sql的結合體。通過增加變數、控制語句,使我們可以寫 -- 一些邏輯更復雜的資料庫操作。 --匿名塊由一下四部分組成: --declare (可選) --宣告各種變數或遊標的地方 --begin (必要) --開始執行語句 -- 單行註釋用兩個連在一起的‘-’表示。 /*多行註釋語句,可以換行*/ --exception (可選) --出錯後的處理 --end; (必要)(請注意end後面的分號) --1.變數必須在 declare 語句塊中宣告 -- 變數宣告的語法規則 --identifier [constant] datatype [not null] [:=| default expr]; --如: --變數名 型別 := 初始值; -- v_str varchar2(10) := 'abc'; --2.變數的命名規則 --變數名不能夠使用保留字,如from、select等 --變數名最多包含30個字元 --不要與資料庫的表或者列同名 --每一行只能宣告一個變數 --建議: --a).普通變數 v_ --b).常量 c_ --3.賦值語句: --a).PL/SQL中的賦值使用 := --b)."=" 被用作比較操作符 --c).賦值語句中有一些規則需要遵守 -- 字元型別必須使用單引號 -- 不可以使用group by -- 可以使用數學操作符或字串連線操作符 --常用變數型別: --普通變數 -- %type -- %rowtype -- varray -- table -- record --變數宣告規則 -- 變數名不能夠使用保留字,如from、select等 -- 第一個字元必須是字母 -- 變數名最多包含30個字元 -- 不要與資料庫的表或者列同名 -- 每行只能宣告一個變數 -- 普通變數的型別主要有: -- binary_integer : 整數,主要用來計數而不是用來表示欄位型別 -- number(x,y) : 數字型別,最長x位,y位小數 -- varchar2(maxlength) : 變長字串,這個引數的上限是32767位元組 -- 宣告方式如下 varchar2(L),L為字串長度, -- 沒有預設值,作為變數最大32767個位元組 --char(max_length) : 定長字串 --date : 日期 --boolean : 布林型別,可以取值為 true、false和null值 --table 義記錄表(或索引表) 資料型別 --先宣告table型別(宣告具體的table型別) --type table 型別的名稱 is table of data_type [index by binary_integer]; --1.單選擇語句: -- if 條件 then -- end if; --2.雙重選擇: -- if 條件 then -- else -- end if; --3.多選擇: -- if 條件 then -- elsif 條件 then -- elsif 條件 then -- else -- end if; --1.do-while 迴圈,先執行後判斷: -- loop -- exit when 條件 -- end loop; --2.while 迴圈,先判斷後執行: -- while 條件 loop -- end loop; --3.for 迴圈,能夠確定次數,不用宣告變數,增長變數 -- for index in[reverse] min..max loop -- end loop; -- index 不能手動改變值,內部自動維護 +1 或 -1 ------------------------------------------------------------------ --cursor 分類: -- |--顯式 cursor -- --靜態 cursor --| -- | |--隱式 cursor --cursor --| -- | |-- 強型別(限制),規定返回型別 -- |--動態 cursor --ref cursor --| -- |-- 弱型別(非限制),不規定返回型別 -- --可以獲取任何結果集 --隱式遊標: -- 可以使用名字sql來訪問,但要注意,通過sql遊標總是隻能訪問前一個處理 -- 操作或單行select操作的遊標屬性。所以通常在剛剛執行完操作之後,立即 -- 使用sql遊標來操作屬性。遊標的屬性有4種。分別是: -- sql %isopen,sql %found,sql %notfound,sql %rowcount --sql%isopen 返回的型別是布林型,判斷遊標是否被開啟,如果開啟 %ispen 等於 -- true,否則等於false,即執行過程中為真,結束後為假。 --sql%notfound 返回值為布林型,判斷遊標所在的行是否有效,如果有效,則 -- %found 等於true,否則等於false,即與%found 屬性返回值相反。 --sql%found 返回值的型別為布林值,值為true代表插入、刪除、更新或單行查詢 -- 操作成功。 --sql%rowcount 返回值型別為整形,返回當前位置為止遊標讀取的記錄行數,即成功 -- 執行的資料行數。 ------------------------------------------------------------------------ --顯式遊標: -- 主要是用於對查詢語句的處理,尤其是在查詢結果為多條記錄的情況下; --隱式遊標: -- 而對於非查詢語句,如修改、刪除操作,則由oracle系統自動地為這些操作設定 -- 操作設定遊標並建立其工作區,這些由系統隱含建立的遊標稱為:隱式遊標。 -- 隱式遊標的名字為sql,這是由 oracle 系統定義的。對於隱式遊標的操作,如 -- 定義、開啟、取值及關閉操作,都由 oracle 系統自動地完成,無需使用者進行 -- 處理。使用者只要通過隱式遊標的相關屬性,來完成相應的操作。在隱式遊標的 -- 工作區中,所存放的資料是與使用者自定義的遊標無關的、最新處理的一條sql -- 語句所包含的資料。 -- 格式呼叫為:sql% -- 注: insert,update,delete,select 語句中不必明確定義遊標。 --1.遊標:cursor -- 遊標就是指在某個結果集上的指標,通過這個指標的移動,我們得以遍歷整個結果集 --2.遊標的使用步驟(標準) -- 1).宣告遊標 -- 2).開啟遊標 -- 3).處理遊標中的資料 -- 4).關閉遊標 --ref 遊標:動態遊標 -- 1).在執行時使不同的語句與之關聯 -- 2).ref遊標可以使用遊標變數 --屬性引用型別的一種 ,在執行時動態 的改變遊標的指向。for迴圈中不能使用 --ref遊標,因為for自動開啟遊標 -- 1).弱型別遊標: -- 沒有返回型別的遊標變數,有動態關聯sql字串 -- type refempcur is ref cursor; -- 2).強型別遊標 -- 有返回型別的遊標變數,不能關聯sql字串,只能關聯sql命令 -- type refempcur is ref cursor return emp%rowtype; --- 遊標僅能開啟emp表的資料。 -- open 遊標名: for select_statement ------------------------------------------------------------------ --建立儲存過程 create [or replace] procedure procedure_name ([arg1 [in | out | in out]] type1 [default value1],[arg2 [in | out | in out]] type2 [default value2],--..... [argn [in | out | in out]] typen [default valuen]) [authid definer | current_user] {is | as} --<宣告部分> begin --<執行部分> exception --<可選的異常錯誤處理程式> end; ---------------------------------------------------------------------- --觸發器 -- 觸發器是資料庫發生某個操作時自動執行的一類的程式 -- 用於保持資料的完整性或記錄資料庫操作資訊方面 -- 觸發器不能夠被直接呼叫,只能夠在某些事件發生時觸發,也就是系統自動呼叫 --觸發器的構建語法: -- create [or replace] trigger trigger_name -- before | after -- event1 [or event2 or event3 ....] -- on table_name [for each row] -- begin -- statement; -- ... -- end; --event通常是 insert 、delete 或 update 等DML操作 --觸發器分為語句級觸發器和行級觸發器 --語句級觸發器是指每執行一條DML語句,該觸發器就執行一次 --行級觸發器是指每個DML操作影響幾條記錄,就會觸發幾次 (for each row) --行級觸發器中由於涉及到了每條記錄的資料變動,所以對於每條記錄的資料來說 --就有新值和舊值之分。 --用關鍵字 :new 和 :old 來代表新的記錄和舊的記錄。 --jdbc 呼叫 儲存過程: public class Test{ public static void main(String[] args){ try{ Class.forName("oracle.jdbc.driver.OracleDriver"); String url = "jdbc:oracle:thin:@localhost:1521:orcl"; Connection conn = DriverManager.getConnection(url,"scott","tiger"); System.out.println(conn.isClosed()); CallableStatement cs = conn.prepareCall("{call delRepeat(?,?,?)}"); cs.setString(1,"emp"); cs.setString(2,"ename"); cs.registerOutParameter(3,OracleTypes.NUMBER); cs.executeQuery(); System.out.println(cs.getObject(3)); conn.close(); } catch (Exception e) { e.printStackTrace(); } } } ----------------------------------------------------------------------------- --外傳: --case when 方法 --decode 方法 --為所有人漲工資,標準是:10部門漲10%;20%部門漲15%;30部門漲20%; --其他部門漲18%。 select * from emp; select ename,(case deptno when 10 then sal*1.1 when 20 then sal*1.15 when 30 then sal*1.2 else sal*1.18 end) v_sal from emp e; --等價於下面的: select ename,decode(deptno,10,sal*1.1,20,sal*1.15,30,sal*1.2,sal*1.18) v_sal from emp e; ------------------------------------------------------------------ ------------------------------------------------------------------ select * from emp e where sal in (800,2000,3000,5000); select * from emp e where ename in ('KING','JONES','FORD','MARTIN'); select *from emp e where sal between 1200 and 4000; select * from emp e where e.deptno not in (20); select * from emp e where e.deptno != 20; select * from emp e where (e.deptno = 10 or e.deptno = 30) and e.sal > 1500; select * from emp e where e.deptno in (10,30) and e.sal >1500; select * from emp e where e.hiredate > to_date('1981-02-05','yyyy-mm-dd'); ----------------------------------------------------------------------- --1、查詢部門編號為10的員工資訊 select * from emp where deptno = 10; --2、查詢年薪大於3萬的人員的姓名與部門編號 select * from emp e where (e.sal+nvl(comm,0))*12 > 30000; --3、查詢佣金為null的人員姓名與工資 select * from emp e where comm is null; --4、查詢工資大於1500 且 and 含有佣金的人員姓名 select * from emp e where e.sal > 1500 and comm is not null; --5、查詢工資大於1500 或 or含有佣金的人員姓名 select * from emp e where e.sal > 1500 or comm is not null; --6、查詢姓名裡面含有 S 員工資訊 工資、名稱 select * from emp e where e.ename like '%S%'; --7、求姓名以J開頭第二個字元O的員工姓名的與工資 select * from emp e where e.ename like 'JO%'; --8、求包含%的僱員姓名 select * from emp e where e.ename like '%A%%' escape 'A'; --9、使用in查詢部門名稱為 SALES 和 RESEARCH 的僱員姓名、工資、部門編號 -- 用 distinct去重 select * from emp; select distinct e.ename,e.deptno from emp e,dept d where d.dname in ('SALES','RESEARCH') and e.deptno = d.deptno; --10、使用exists查詢部門名稱為SALES和RESEARCH 的僱員姓名、工資、部門編號。 -- exists是判斷exits後面的sql語句是否為真,若為真則整個sql句子成立,-- 否則沒有任何記錄。語法如下: -- ** select * from a where exists (select g from b where a.id = b.id); select distinct e.ename,e.deptno from emp e where exists (select * from emp e,dept d where d.dname in ('SALES','RESEARCH') and d.deptno = e.deptno); --------------------------------------------------------------------- select * from emp e order by e.sal desc,e.ename asc; select e.ename || ' is a ' || e.job from emp e; --------------------------------------------------------------------- --1、使用基本查詢語句. --(1)查詢DEPT表顯示所有部門名稱. select d.dname from dept d; --(2)查詢EMP表顯示所有僱員名及其全年收入(月收入=工資+補助),--處理NULL行,並指定列別名 --為"年收入"。(NVL(comm,0) comm取空值時用0替代) select e.ename,(e.sal+nvl(comm,0))*12 sal_all from emp e; --(3)查詢顯示不存在僱員的所有部門號。 select d.deptno from dept d where d.deptno not in (select distinct e.deptno from emp e where d.deptno = e.deptno); --2、限制查詢資料 --(1)查詢EMP表顯示工資超過2850的僱員姓名和工資。 select e.ename,e.sal from emp e where e.sal >2850; --(2)查詢EMP表顯示工資不在1500~2850之間的所有僱員及工資。 select e.ename,e.sal from emp e where e.sal not in (1500,2850); --(3)查詢EMP表顯示程式碼為7566的僱員姓名及所在部門程式碼。 select e.ename,e.deptno from emp e where e.empno = 7566; --(4)查詢EMP表顯示部門10和30中工資超過1500的僱員名及工資。 select e.ename,e.sal from emp e where e.deptno in (10,30) and e.sal >1500; --(5)查詢EMP表顯示第2個字元為"A"的所有僱員名其工資。 select e.ename,e.sal from emp e where e.ename like '_A%'; --(6)查詢EMP表顯示補助非空的所有僱員名及其補助。 select e.ename,e.comm from emp e where comm is not null; --3、排序資料 --(1)查詢EMP表顯示所有僱員名、工資、僱傭日期,並以僱員名的升序進行排序。 select e.ename,e.hiredate from emp e order by e.ename asc; --(2)查詢EMP表顯示在1981年2月1日到1981年5月1日之間僱傭的僱員名、 -- 崗位及僱傭日期,並以僱傭日期進行排序。 select e.ename,e.job,e.hiredate from emp e where e.hiredate >= to_date('1981-02-01','yyyy-mm-dd') and e.hiredate <= to_date('1981-05-01','yyyy-mm-dd') order by e.hiredate desc; --或 select e.ename,'yyyy-mm-dd') order by e.hiredate asc; --(3)查詢EMP表顯示獲得補助的所有僱員名、工資及補助,並以工資升序和 --補助降序排序。 select e.ename,e.comm from emp e where (e.comm is not null and e.comm != 0) order by e.sal,e.comm desc; ----------------------------------------------------------------------------- select lower(ename) from emp e ; select upper(lower(ename)) from emp select substrb('流aa川abc',4) from dual; select ename,substr(ename,2) from emp e; select ename,length(ename) from emp select ename,lpad(ename,'6','*') from emp; select ename,rpad(ename,instr(ename,'A') from emp; select ename,ename) from emp; select ename,replace(ename,'A','-') from emp; select rtrim('xxgao lao shixxx','x') text from dual; select trim(both 'x' from 'xxxgao lao shixxx') from dual; select ceil(19.2) from dual; select floor(19.2) from dual; select mod(19,2) from dual; select trunc(23.653) from dual; select trunc(23.653,2) from dual; select trunc(23.653,-1) from dual; select round(23.653) from dual; select round(23.653,2) from dual; select round(23.653,-1) from dual; select sysdate from dual; select current_date from dual; select add_months(sysdate,3) from dual; select months_between(sysdate,add_months(sysdate,3)) from dual; select sysdate-2 from dual; select sysdate+2 from dual; select ename,round((sysdate-hiredate)/7) weeks from emp e where e.deptno = 10; select * from emp where empno = to_number('7369'); select * from emp e where hiredate = '20-2月-1981'; select * from emp e where hiredate = to_date('1981-02-20','yyyy-mm-dd'); select '199'-90 from dual; select to_char(sysdate,'yyyy-mm-dd hh24 : mi : ss') from dual; select ename,hiredate,to_char(hiredate,'yyyy-mm-dd hh24:mi:ss') from emp; select to_char(sal,'$99,999.9999') salary from emp where ename = 'ALLEN'; select to_char(sal,'$00,000.0000') salary from emp where ename = 'ALLEN'; select to_char(sal,'L00,000.0000') salary from emp where ename = 'ALLEN'; select to_date('04,05,19,23,40','yy,mm,dd,hh24,mi,ss') from dual; select to_date('2004-09-19','yyyy-mm-dd') from dual; select to_number('$39343.783','$99990.000') from dual; select to_number('11.231','999.999') from dual; select e.*,nvl(to_char(mgr),'boss') mgr from emp e where mgr is null; select to_char(next_day(add_months(hiredate,6),'星期五'),'yyyy-mm-dd') dat from emp e order by hiredate; --------------------------------------------------------------------- --1、查詢82年員工 select * from emp e where to_char(e.hiredate,'yy') like '82'; --2、查詢36年工齡的人員 select * from emp e where (sysdate - to_date(hiredate))/365 > 36; --3、顯示員工僱傭期 6 個月後下一個星期一的日期 select e.ename,to_char(next_day(add_months(hiredate,'星期一'),'yyyy-mm-dd') from emp e order by hiredate asc; --4、找沒有上級的員工,把mgr的欄位資訊輸出為 "boss" select ename,'boss') from emp e where mgr is null; --5、為所有人長工資,標準是:10部門長10%;20部門長15%;30 --部門長20%其他部門長18% --case when 方法: select e.ename,(case deptno when 10 then e.sal*1.1 when 20 then e.sal*1.15 when 30 then e.sal*1.2 else e.sal*1.18 end) v_sal from emp e; --decode 方法: select e.ename,e.sal*1.1,e.sal*1.15,e.sal*1.2,e.sal*1.18) v_sal from emp e; ---------------------------------------------------------------- select sum(e.sal),avg(e.sal),min(sal),max(e.sal) from emp e; select min(hiredate),max(hiredate) from emp e; select count(1) from emp e ; select count(*) from emp e ; select count(comm) from emp ; select count(mgr) from emp; select count(distinct deptno) from emp; select avg(nvl(comm,0)) from emp e ; select deptno,avg(sal) from emp group by deptno; select deptno,avg(sal) from emp group by deptno having avg(sal) > 2000; --• 求部門下僱員的平均工資>2000 人數 select deptno,count(1) from emp group by deptno having deptno in (select deptno from emp e group by deptno having avg(sal) > 2000); --部門薪水最高 select deptno,max(sal) max_sal from emp e group by deptno; select max(e.max_sal) from (select max(sal) max_sal from emp e group by deptno) e select max(sal),deptno,job from emp group by deptno,job; select avg(sal) from emp where sal > 1200 group by deptno having avg(sal) > 1500 order by avg(sal) asc; -- 部門裡面 工齡最小和最大的人找出來 --找出部門裡面最大和最小工齡 select deptno,max(hiredate) min_date,min(hiredate) max_date from emp e group by deptno; --找出工齡對應的名字 select e.deptno,e.ename eename,e.hiredate from emp e join (select deptno dt,min(hiredate) max_date from emp e group by deptno) t on (e.hiredate = t.min_date or e.hiredate = t.max_date) and e.deptno = t.dt order by e.deptno; --------------------------------------------------------------------- --1、查詢10號部門中編號最新入職的員工,工齡最長的員工的個人資訊。 select e.* from emp e join (select deptno dt,min(hiredate) max_date from emp e group by deptno) t on (e.hiredate = t.min_date or e.hiredate = t.max_date) and e.deptno = 10; --2、從“software”找到‘f’的位置,用‘*’左或右填充到15位,去除其中的‘a’。 --–Instr()字串出現的位置,instr( string ,’A‘) --–lpad,rpad 填充字元型資料 --–ltrim/rtrim (string1,string2) select instr('software','f'),lpad('software',15,'*'),rpad('software',replace('software','a','') from dual; --3、查詢員工的獎金,如果獎金不為NULL顯示‘有獎金’,為null則顯示無獎金 select e.ename,nvl2(comm,'有獎金','無獎金') from emp e; select e.ename,decode(comm,null,'無獎金','有獎金') from emp e; --4、寫一個查詢顯示當前日期,列標題顯示為Date。再顯示六個月後的日期, --下一個星期日的日期,該月最後一天的日期。 select sysdate dat,next_day(sysdate,'星期日'),last_day(sysdate) from dual; --5、查詢EMP表按管理者編號升序排列,如果管理者編號為空則把為空的在最前顯 --示 select * from emp order by mgr nulls first; --6、求部門平均薪水 select deptno,avg(sal) from emp e group by deptno; --7、按部門求出工資大於1300人員的 部門編號、平均工資、最小佣金、 --最大佣金,並且最大佣金大於100 select deptno,avg(sal),min(comm),max(comm) from emp e where sal > 1500 group by deptno having max(comm)>100; --8、找出每個部門的平均、最小、最大薪水 select deptno,max(sal) from emp e group by deptno; --9、查詢出僱員名,僱員所在部門名稱, 工資等級 select e.ename,d.deptno,s.grade from emp e,dept d,salgrade s where sal between losal and hisal and e.deptno = d.deptno; select * from emp,salgrade where sal between losal and hisal; select e.empno,d.loc from emp e,dept d where e.deptno = d.deptno and e.ename like 'JAMES'; select e.empno,d.dname,d.loc,d.deptno from emp e,dept d where e.deptno = d.deptno and e.deptno = 10; select * from emp e,salgrade s where sal between losal and hisal; select e.ename,e.deptno,dept d where e.deptno = d.deptno(+); select e.ename,dept d where e.deptno(+) = d.deptno; ----------------------------------------------------------------- --99語法 select e.empno,dept d where e.deptno = d.deptno; select e.empno,d.loc from emp e cross join dept d where e.deptno = d.deptno; select * from emp e natural join dept d where deptno = 10; select e.empno,d.loc from emp e join dept d using(deptno) where deptno = 10; select e.ename,s.grade from emp e join dept d on e.deptno = d.deptno join salgrade s on e.sal between losal and hisal; select * from emp e right outer join dept d on e.deptno = d.deptno; select * from emp e left outer join dept d on e.deptno = d.deptno; select * from emp e right join dept d on e.deptno = d.deptno; select * from emp e inner join dept d on e.deptno = d.deptno; select * from emp e join dept d on e.deptno = d.deptno; select * from emp e join dept d using(deptno); --查詢那些薪水在整個僱員平均薪水之上的人 select * from emp e where (e.sal+nvl(comm,0)) > (select avg(sal+nvl(comm,0)) from emp); --找出所有的經理人 select distinct e.ename from emp e,emp em where e.empno = em.mgr; select *from emp e where empno in (select distinct mgr from emp); --找出部門20最高收入的職員 select e.ename,e.comm from emp e join (select deptno,max(sal+nvl(comm,0)) max_sal from emp group by deptno) em on e.deptno = 20 and e.sal = em.max_sal; select e.ename,e.comm from emp e where (e.sal+nvl(comm,0)) >= all(select (sal+nvl(comm,0)) from emp where deptno =20) and deptno = 20; --求每個部門平均薪水的平均水平 --求部門平均薪水 select deptno dt,avg(sal) avg_sal from emp e group by e.deptno; --求等級 select t.dt,t.avg_sal,s.grade from (select deptno dt,avg(sal) avg_sal from emp e group by e.deptno) t join salgrade s on t.avg_sal between losal and hisal; --------------------------------------------------------------------- --1、求平均薪水最高的部門的部門編號 --求部門的平均薪水 select deptno,avg(sal+nvl(comm,0)) from emp group by deptno ; --求出最大值 select max(max_avg) from (select deptno dt,0)) max_avg from emp group by deptno) t --求出部門編號 select k.dt,k.sal_avg from (select e.deptno dt,0)) sal_avg from emp e group by deptno) k where k.sal_avg = (select max(max_avg) from (select deptno dt,0)) max_avg from emp group by deptno) t ) --2、求部門平均薪水的等級 select k.dt,k.avg_sal,s.grade from (select e.deptno dt,avg(sal) avg_sal from emp e group by deptno) k join salgrade s on k.avg_sal between losal and hisal; --3、求部門平均的薪水等級 --求部門的薪水等級 select e.deptno dt,e.sal sl,s.grade gd from emp e join salgrade s on e.sal between losal and hisal; --求平均值 select k.dt,avg(k.sl),avg(k.gd) from (select e.deptno dt,s.grade gd from emp e join salgrade s on e.sal between losal and hisal) k group by k.dt; --4、求薪水最高的前5名僱員 --先排列薪水 select * from emp e order by e.sal desc; --擷取前五名 select t.*,rownum rm from (select * from emp e order by e.sal desc) t where rownum <= 5; --5、求薪水最高的第6到10名僱員 select k.* from (select t.*,rownum rm from (select * from emp e order by e.sal desc) t where rownum <= 10) k where k.rm >= 6; --------------------------------------------------------------------- --------------------------------------------------------------------- declare type tb_mytable is table of dept.deptno%type index by binary_integer; v_tb_mytable tb_mytable; begin dbms_output.put_line('hello world'); end; --do while 迴圈: declare v_num number(3,0) := 0; begin loop dbms_output.put_line(v_num); v_num := v_num + 2; exit when v_num = 100; end loop; end; --while 迴圈 declare v_num number(3,0) := 0; begin while v_num != 100 loop dbms_output.put_line(v_num); v_num := v_num + 2; end loop; end; --while迴圈: declare type t is table of number(3) index by varchar2(3); hash_t t; l_row varchar2(3); begin hash_t('a') := 10; hash_t('b') := 20; l_row := hash_t.first; while(l_row is not null) loop dbms_output.put_line(hash_t(l_row)); l_row := hash_t.next(l_row); end loop; end; --for迴圈: declare type t is table of number(3) index by pls_integer; hash_t t; l_row varchar2(3); begin hash_t(1) := 10; hash_t(2) := 20; for i in hash_t.first..hash_t.last loop dbms_output.put_line(hash_t(i)); end loop; end; --if條件句: declare i integer; b01 boolean := true; begin if b01 then dbms_output.put_line('test'); end if; end; declare v_name varchar2(20); begin select ename into v_name from emp e where e.deptno = 20 and e.empno = &empno; dbms_output.put_line(v_name); exception when others then dbms_output.put_line('資料未找到'); rollback; end; select * from emp; declare v_empno emp.empno%type := &empno; v_comm emp.comm%type; begin select comm into v_comm from emp e where e.empno = v_empno; if(v_comm is null) then dbms_output.put_line('無獎金'); else dbms_output.put_line('有獎金'); end if; exception when others then dbms_output.put_line(sqlcode||'-----'||sqlerrm); rollback; end; declare v_empno emp.empno%type := &empno; v_comm emp.comm%type; begin select comm into v_comm from emp e where e.empno = v_empno; if(v_comm is null) then dbms_output.put_line('無獎金'); elsif(v_comm > 0 and v_comm < 800) then dbms_output.put_line('獎金少的可憐'); else dbms_output.put_line('獎金可觀'); end if; exception when others then dbms_output.put_line(sqlcode||'----'||sqlerrm); rollback; end; ----------------------------------------------------------- ------------------------------------------------------------- --建立表 create table v_temp02( vno number(2),vname varchar2(20),vage number(3) ); --增 insert into v_temp02 values(10,'王哥',18); insert into v_temp02 values(11,'楊哥',19); insert into v_temp02 values(12,'張哥',17); insert into v_temp02 values(13,'黃哥',20); insert into v_temp02 values(14,'文哥',21); --commit提交事務,可加可不加,加了之後,就直接提交,而沒機會回滾了 commit; --查 select * from v_temp02; --修改資料 begin update v_temp02 set vname = '忠哥',vage = 18 where vno = 12; if sql%found then dbms_output.put_line('更新了'||sql%rowcount||'記錄'); end if; commit; if not sql%isopen then dbms_output.put_line('自動關閉遊標'); end if; end; --刪除資料 delete from v_temp02 where vno = 11; commit; --刪除表 drop table v_temp02; ----------------------------------------------------------------- --遊標 --如抓取一條資料 declare cursor my_cursor is select * from dept; --宣告遊標(定義的遊標不能有into句子) v_dept dept%rowtype; --定義變數 begin open my_cursor; --開啟遊標 fetch my_cursor into v_dept; --使用遊標 dbms_output.put_line(v_dept.deptno||'----'||v_dept.dname|| '---'||v_dept.loc); close my_cursor; --關閉遊標 end; --loop迴圈(do-while)遍歷遊標,利用loop迴圈和%notfound屬性實現遊標遍歷 declare cursor my_cursor is select * from dept; --宣告遊標 v_dept dept%rowtype; --定義變數 begin open my_cursor; --開啟遊標 loop --開啟loop(do-while)迴圈 fetch my_cursor into v_dept; --使用遊標 exit when my_cursor%notfound; --定義遊標停止條件 dbms_output.put_line(v_dept.deptno||'---'|| v_dept.dname||'---'||v_dept.loc); end loop; --關閉loop迴圈 close my_cursor; --關閉遊標 exception --一次 when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; end; --while迴圈遍歷遊標,利用while迴圈配合%found屬性實現遊標遍歷。 declare cursor my_cursor is select * from dept; --宣告遊標 v_dept my_cursor%rowtype; --定義變數 begin open my_cursor; --開啟遊標 fetch my_cursor into v_dept; --使用遊標 while my_cursor%found loop --開啟while迴圈 dbms_output.put_line(v_dept.deptno||'---'|| v_dept.dname||'---'||v_dept.loc); fetch my_cursor into v_dept; --使用遊標 end loop; --關閉迴圈 close my_cursor; --關閉遊標 exception --異常 when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; --回滾 end; --for迴圈遍歷遊標,利用for迴圈遍歷遊標,不需要開啟遊標,也不需要關閉遊標 --甚至不用宣告迴圈變數,不用抓取,最簡單。推薦使用 declare cursor my_cursor is select * from dept; v_dept dept%rowtype; begin for v_dept in my_cursor loop dbms_output.put_line(v_dept.deptno||'---'||v_dept.dname|| '---'||v_dept.loc); end loop; exception when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; end; ------------------------------------------------------------------- --使用遊標,更新狀態資料,如果年薪 < 5000 低 [5000,8000] 中 >= 8000 高 --複製表 create table copy_emp02 as select * from emp where 1=1; select * from copy_emp02; --加入狀態列 alter table copy_emp02 add status varchar2(20); --帶引數的遊標 declare cursor my_cursor(v_no dept.deptno%type) is select * from dept d where deptno = v_no; v_dept dept%rowtype; begin for v_dept in my_cursor(&v_no) loop dbms_output.put_line('第'||my_cursor%rowcount||'行,資料為:'|| v_dept.deptno||'---'||v_dept.dname||'---'||v_dept.loc); end loop; end; --引數01 declare cursor my_cursor(v_sal number) is select * from emp e where e.sal > v_sal; v_emp emp%rowtype; begin for v_emp in my_cursor(1500) loop --sal大於1500的僱員 dbms_output.put_line(v_emp.ename||'---'||v_emp.sal); end loop; end; --引數02 declare cursor my_cursor(v_sal number default 2000) is select * from emp e where e.sal > v_sal; --預設值為2000,即sal > 2000的僱員 v_emp emp%rowtype; begin for v_emp in my_cursor(v_sal => 1500) loop dbms_output.put_line(v_emp.ename||'---'||v_emp.sal); end loop; exception when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; end; --引數03 declare cursor my_cursor(v_sal number default 2000) is select * from emp e where e.sal > v_sal; --預設值為2000,即sal > 2000的僱員 v_emp emp%rowtype; begin for v_emp in my_cursor loop --帶預設值的引數 ,可不加括號和引數 dbms_output.put_line(v_emp.ename||'---'||v_emp.sal); end loop; end; ------------------------------------------------------------------- --宣告遊標,有引數有返回值 select * from emp where deptno = 10; declare type emp_record is record( v_ename emp.ename%type,v_hiredate emp.hiredate%type ); v_record emp_record; cursor my_cursor(v_deptno number,v_job varchar2) return emp_record is select ename,hiredate from emp where deptno = v_deptno and job = v_job; v_emp emp%rowtype; begin open my_cursor(10,'CLERK'); loop fetch my_cursor into v_record; if my_cursor%found then dbms_output.put_line(v_record.v_ename||'的僱傭日期是'||v_record.v_hiredate); else dbms_output.put_line('已經處理結束了'); exit; end if; end loop; close my_cursor; exception when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; end; --基於遊標定義記錄變數,比宣告記錄型別變數要方便 declare cursor my_cursor(v_deptno number,v_job varchar2) is select ename,hiredate from emp e where e.deptno = v_deptno and e.job = v_job; v_cursor my_cursor%rowtype; v_emp emp%rowtype; begin open my_cursor(10,'CLERK'); loop fetch my_cursor into v_cursor; if my_cursor%found then dbms_output.put_line(v_cursor.ename||'的僱傭日期是'||v_cursor.hiredate); else dbms_output.put_line('已經處理完畢'); exit; end if; end loop; close my_cursor; end; --更新或刪除 create table emp2 as select * from emp ; --建立新版,不影響舊錶 select * from emp2; --在這個例子中,我們同個select語句後面新增 for update --來提示oracle鎖定記錄以便進行更新,然後用 where current of --來指明操作時新增在當前遊標所指向的記錄上 declare cursor my_cursor is select * from emp2 for update; v_temp my_cursor%rowtype; begin for v_emp in my_cursor loop if (v_emp.sal < 2000) then update emp2 set sal = sal * 2 where current of my_cursor; elsif(v_emp.sal = 1500) then delete from emp2 where current of my_cursor; end if; end loop; commit; end; --刪除表emp2 drop table emp2; ------------------------------------------------------------------- --動態遊標:弱型別遊標 declare type RefEmpCur is ref cursor; mycur RefEmpCur; v_emp emp%rowtype; begin open mycur for select * from emp; loop fetch mycur into v_emp; exit when mycur%notfound; dbms_output.put_line(v_emp.deptno||'---'||v_emp.ename||'---'|| v_emp.sal); end loop; close mycur; end; --多語句 declare type RefEmpCur is ref cursor; mycur RefEmpCur; v_emp emp%rowtype; v_dept dept%rowtype; begin open mycur for select * from emp; loop fetch mycur into v_emp; exit when mycur%notfound; dbms_output.put_line(v_emp.deptno||'---'||v_emp.ename||'---'|| v_emp.sal); end loop; close mycur; open mycur for select * from dept; loop fetch mycur into v_dept; exit when mycur%notfound; dbms_output.put_line(v_dept.deptno||'---'||v_dept.dname||'---'|| v_dept.loc); end loop; close mycur; end; --sys_refcursor declare --type ref_cursor is ref cursor; --cur01 ref_cursor; cur01 sys_refcursor; v_emp emp%rowtype; v_sql varchar2(100); begin v_sql := 'select * from emp'; open cur01 for v_sql; loop fetch cur01 into v_emp; exit when (cur01%notfound); dbms_output.put_line(v_emp.ename); end loop; close cur01; end; ------------------------------------------------------------------- select * from student_score; --建立儲存過程 ------------------------------------------------------------------- --實現一個函式判斷資料是時間格式型別 create or replace function isDate(in_date in varchar2) return number is v_result number(2); v_date date; begin v_date := to_date(in_date,'yyyy-mm-dd'); v_result := case when v_date is not null then 1 else 0 end; return v_result; exception when others then dbms_output.put_line(sqlcode||'---'||sqlerrm); rollback; end; select isDate('1982-02-10') from dual; --trigger 觸發器例子 create or replace trigger trig_temp after update on dept for each row begin update emp set deptno =: new.deptno where deptno =: old.deptno; end; --如果沒有觸發器,是不能直接更新的 update dept set deptno = 90 where deptno = 30 select * from dept;