天天看點

最全的ORACLE-SQL筆記 最全的ORACLE-SQL筆記

最全的ORACLE-SQL筆記

時間:2013-08-05 17:20 來源:www.chengxuyuans.com

-- 首先,以超級管理者的身份登入oracle  
     sqlplus sys/bjsxt as sysdba  
   
 --然後,解除對scott使用者的鎖  
     alter user scott account unlock;  
 --那麼這個使用者名就能使用了。  
 --(預設全局資料庫名orcl)  
   
 1、select ename, sal * 12 from emp; --計算年薪  
 2、select 2*3 from dual;  --計算一個比較純的資料用dual表 
 3、select sysdate from dual;  --檢視目前的系統時間  
 4、select ename, sal*12 anuual_sal from emp; --給搜尋字段更改名稱(雙引号 keepFormat 别名有特殊字元,要加雙引号)。  
 5、--任何含有空值的數學表達式,最後的計算結果都是空值。  
 6、select ename||sal from emp;  --(将sal的查詢結果轉化為字元串,與ename連接配接到一起,相當于Java中的字元串連接配接)  
 7、select ename||'afasjkj' from emp;   --字元串的連接配接  
 8、select distinct deptno from emp;   --消除deptno字段重複的值  
 9、select distinct deptno , job from emp; --将與這兩個字段都重複的值去掉  
 10、select * from emp where deptno=10;   --(條件過濾查詢)               
 11、select * from emp where empno > 10;  --大于 過濾判斷  
 12、select * from emp where empno <> 10  --不等于  過濾判斷  
 13、select * from emp where ename > 'cba';  --字元串比較,實際上比較的是每個字元的AscII值,與在Java中字元串的比較是一樣的  
 14、select ename, sal from emp where sal between 800 and 1500;  --(between and過濾,包含800 1500)  
 15、select ename, sal, comm from emp where comm is null;  --(選擇comm字段為null的資料)  
 16、select ename, sal, comm from emp where comm is not null;  --(選擇comm字段不為null的資料)  
 17、select ename, sal, comm from emp where sal in (800, 1500,2000);  --(in 表範圍)  
 18、select ename, sal, hiredate from emp where hiredate > '02-2月-1981'; --(隻能按照規定的格式寫)  
 19、select ename, sal from emp where deptno =10 or sal >1000;  
 20、select ename, sal from emp where deptno =10 and sal >1000;  
 21、select ename, sal, comm from emp where sal not in (800, 1500,2000);  --(可以對in指定的條件進行取反)  
 22、select ename from emp where ename like '%ALL%';   --(模糊查詢)  
 23、select ename from emp where ename like '_A%';    --(取第二個字母是A的所有字段)  
 24、select ename from emp where ename like '%/%%';   --(用轉義字元/查詢字段中本身就帶%字段的)  
 25、select ename from emp where ename like '%$%%' escape '$';   --(用轉義字元/查詢字段中本身就帶%字段的)  
 26、select * from dept order by deptno desc; (使用order by  desc字段 對資料進行降序排列 預設為升序asc);  
 27、select * from dept where deptno <>10 order by deptno asc;   --(我們可以将過濾以後的資料再進行排序)    
 28、select ename, sal, deptno from emp order by deptno asc, ename desc;   --(按照多個字段排序 首先按照deptno升序排列,當detpno相同時,内部再按照ename的降序排列)  
 29、select lower(ename) from emp;  --(函數lower() 将ename搜尋出來後全部轉化為小寫);  
 30、select ename from emp where lower(ename) like '_a%';  --(首先将所搜尋字段轉化為小寫,然後判斷第二個字母是不是a)  
 31、select substr(ename, 2, 3) from emp;    --(使用函數substr() 将搜素出來的ename字段從第二個字母開始截,一共截3個字元)  
 32、select chr(65) from dual;  --(函數chr() 将數字轉化為AscII中相對應的字元)   
 33、select ascii('A') from dual;  --(函數ascii()與32中的chr()函數是相反的 将相應的字元轉化為相應的Ascii編碼)                                                                                                                                                                                                                                                                                                                                             )  
 34、select round(23.232) from dual;  --(函數round() 進行四舍五入操作)  
 35、select round(23.232, 2) from dual;  --(四舍五入後保留的小數位數 0 個位 -1 十位)  
 36、select to_char(sal, '$99,999.9999')from emp;  --(加$符号加入千位分隔符,保留四位小數,沒有的補零)  
 37、select to_char(sal, 'L99,999.9999')from emp;  --(L 将貨币轉化為本地币種此處将顯示¥人民币)  
 38、select to_char(sal, 'L00,000.0000')from emp;  --(補零位數不一樣,可到資料庫執行檢視)  
 39、select to_char(hiredate, 'yyyy-MM-DD HH:MI:SS') from emp;  --(改變日期預設的顯示格式)  
 40、select to_char(sysdate, 'yyyy-MM-DD HH:MI:SS') from dual;  --(用12小時制顯示目前的系統時間)  
 41、select to_char(sysdate, 'yyyy-MM-DD HH24:MI:SS') from dual;  --(用24小時制顯示目前的系統時間)  
 42、select ename, hiredate from emp where hiredate > to_date('1981-2-20 12:24:45','YYYY-MM-DD HH24:MI:SS');   --(函數to-date 查詢公司在所給時間以後入職的人員)  
 43、select sal from emp where sal > to_number('$1,250.00', '$9,999.99');   --(函數to_number()求出這種薪水裡帶有特殊符号的)  
 44、select ename, sal*12 +  nvl(comm,0) from emp;   --(函數nvl() 求出員工的"年薪 + 提成(或獎金)問題")  
 45、select max(sal) from emp;  -- (函數max() 求出emp表中sal字段的最大值)  
 46、select min(sal) from emp;  -- (函數max() 求出emp表中sal字段的最小值)  
 47、select avg(sal) from emp;  --(avg()求平均薪水);  
 48、select to_char(avg(sal), '999999.99') from emp;   --(将求出來的平均薪水隻保留2位小數)  
 49、select round(avg(sal), 2) from emp;  --(将平均薪水四舍五入到小數點後2位)  
 50、select sum(sal) from emp;  --(求出每個月要支付的總薪水)  
   
 ------------------------/組函數(共5個):将多個條件組合到一起最後隻産生一個資料------min() max() avg() sum() count()----------------------------/  
 51、select count(*) from emp;  --求出表中一共有多少條記錄  
 52、select count(*) from emp where deptno=10;  --再要求一共有多少條記錄的時候,還可以在後面跟上限定條件  
 53、select count(distinct deptno) from emp;   --統計部門編号前提是去掉重複的值  
 ------------------------聚組函數group by() --------------------------------------  
 54、select deptno, avg(sal) from emp group by deptno;  --按照deptno分組,檢視每個部門的平均工資  
 55、select max(sal) from emp group by deptno, job; --分組的時候,還可以按照多個字段進行分組,兩個字段不相同的為一組  
 56、select ename from emp where sal = (select max(sal) from emp); --求出  
 57、select deptno, max(sal) from emp group by deptno; --搜素這個部門中薪水最高的的值  
 --------------------------------------------------having函數對于group by函數的過濾 不能用where--------------------------------------  
 58、select deptno, avg(sal) from emp group by deptno having avg(sal) >2000; (order by )--求出每個部門的平均值,并且要 > 2000  
 59、select avg(sal) from emp where sal >1200 group by deptno having avg(sal) >1500 order by avg(sal) desc;--求出sal>1200的平均值按照deptno分組,平均值要>1500最後按照sal的倒序排列  
 60、select ename,sal from emp where sal > (select avg(sal) from emp);  --求那些人的薪水是在平均薪水之上的。  
 61、select ename, sal from emp join (select max(sal) max_sal ,deptno from emp group by deptno) t on (emp.sal = t.max_sal and emp.deptno=t.deptno);  --查詢每個部門中工資最高的那個人  
 ------------------------------/等值連接配接--------------------------------------  
 62、select e1.ename, e2.ename from emp e1, emp e2 where e1.mgr = e2.empno;  --自連接配接,把一張表當成兩張表來用  
 63、select ename, dname from emp, dept;  --92年文法 兩張表的連接配接 笛卡爾積。  
 64、select ename, dname from emp cross join dept; --99年文法 兩張表的連接配接用cross join  
 65、select ename, dname from emp, dept where emp.deptno = dept.deptno; -- 92年文法 表連接配接 + 條件連接配接  
 66、select ename, dname from emp join dept on(emp.deptno = dept.deptno); -- 新文法  
 67、select ename,dname from emp join dept using(deptno); --與66題的寫法是一樣的,但是不推薦使用using : 假設條件太多  
 --------------------------------------/非等值連接配接------------------------------------------/  
 68、select ename,grade from emp e join salgrade s on(e.sal between s.losal and s.hisal); --兩張表的連接配接 此種寫法比用where更清晰  
 69、select ename, dname, grade from emp e  
     join dept d on(e.deptno = d.deptno)  
     join salgrade s on (e.sal between s.losal and s.hisal)  
     where ename not like '_A%';  --三張表的連接配接  
 70、select e1.ename, e2.ename from emp e1 join emp e2 on(e1.mgr = e2.empno); --自連接配接第二種寫法,同62  
 71、select e1.ename, e2.ename from emp e1 left join emp e2 on(e1.mgr = e2.empno); --左外連接配接 把左邊沒有滿足條件的資料也取出來  
 72、select ename, dname from emp e right join dept d on(e.deptno = d.deptno); --右外連接配接  
 73、select deptno, avg_sal, grade from (select deptno, avg(sal) avg_sal from emp group by deptno) t join salgrade s  on    (t.avg_sal between s.losal and s.hisal);--求每個部門平均薪水的等級  
 74、select ename from emp where empno in (select mgr from emp); -- 在表中搜尋那些人是經理  
 75、select sal from emp where sal not in(select distinct e1.sal from emp e1 join emp e2 on(e1.sal < e2.sal)); -- 面試題 不用組函數max()求薪水的最大值  
 76、select deptno, max_sal from  
     (select avg(sal) max_sal,deptno from emp group by deptno)  
         where max_sal =  
         (select max(max_sal) from  
          (select avg(sal) max_sal,deptno from emp group by deptno)  
     );--求平均薪水最高的部門名稱和編号。  
 77、select t1.deptno, grade, avg_sal from  
       (select deptno, grade, avg_sal from  
     (select deptno, avg(sal) avg_sal from emp group by deptno) t  
         join salgrade s on(t.avg_sal between s.losal and s.hisal)  
       ) t1  
     join dept on (t1.deptno = dept.deptno)  
     where t1.grade =   
       (  
         select min(grade) from  
           (select deptno, grade, avg_sal from  
     (select deptno, avg(sal) avg_sal from emp group by deptno) t  
     join salgrade s on(t.avg_sal between s.losal and s.hisal)  
      )  
    )--求平均薪水等級最低的部門的名稱 哈哈 确實比較麻煩  
 78、create view v$_dept_avg_sal_info as  
     select deptno, grade, avg_sal from  
        (select deptno, avg(sal) avg_sal from emp group by deptno) t  
     join salgrade s on(t.avg_sal between s.losal and s.hisal);  
     --視圖的建立,一般以v$開頭,但不是固定的  
   
   
 79、select t1.deptno, grade, avg_sal from v$_dept_avg_sal_info t1  
     join dept on (t1.deptno = dept.deptno)  
     where t1.grade =   
       (  
         select min(grade) from  
          v$_dept_avg_sal_info t1  
      )  
    )--求平均薪水等級最低的部門的名稱 用視圖,能簡單一些,相當于Java中方法的封裝  
   
 80、---建立視圖出現權限不足時候的解決辦法:  
     conn sys/admin as sysdba;  
         --顯示:連接配接成功 Connected  
     grant create table, create view to scott;  
        -- 顯示: 授權成功 Grant succeeded  
 81、-------求比普通員工最高薪水還要高的經理人的名稱 -------  
     select ename, sal from emp where empno in  
        (select distinct mgr from emp where mgr is not null)  
     and sal >  
     (  
        select max(sal) from emp where empno not in  
          (select distinct mgr from emp where mgr is not null)  
     )  
 82、---面試題:比較效率  
        select * from emp where deptno = 10 and ename like '%A%';--好,将過濾力度大的放在前面  
        select * from emp where ename like '%A%' and deptno = 10;  
 83、-----表的備份  
        create table dept2 as select * from dept;  
 84、-----插入資料  
         insert into dept2 values(50,'game','beijing');  
       ----隻對某個字段插入資料  
         insert into dept2(deptno,dname) values(60,'game2');  
 85、-----将一個表中的資料完全插入另一個表中(表結構必須一樣)  
     insert into dept2 select * from dept;  
 86、-----求前五名員工的編号和名稱(使用虛字段rownum 隻能使用 < 或 = 要使用 > 必須使用子查詢)  
     select empno,ename from emp where rownum <= 5;  
 86、----求10名雇員以後的雇員名稱--------  
     select ename from (select rownum r,ename from emp) where r > 10;  
 87、----求薪水最高的前5個人的薪水和名字---------  
     select ename, sal from (select ename, sal from emp order by sal desc) where rownum <=5;    
 88、----求按薪水倒序排列後的第6名到第10名的員工的名字和薪水--------  
     select ename, sal from  
            (select ename, sal, rownum r from  
               (select ename, sal from emp order by sal desc)  
            )  
         where r>=6 and r<=10  
 89、----------------建立新使用者---------------  
     1、backup scott--備份  
         exp--導出  
     2、create user  
         create user guohailong identified(認證) by guohailong  default tablespace users quota(配額) 10M on users  
         grant create session(給它登入到伺服器的權限),create table, create view to guohailong  
     3、import data  
         imp  
 90、-----------事務回退語句--------  
     rollback;  
       
 91、-----------事務确認語句--------  
     commit;--此時再執行rollback無效  
   
 92、--當正常斷開連接配接的時候例如exit,事務自動送出。  當非正常斷開連接配接,例如直接關閉dos視窗或關機,事務自動送出  
 93、/*有3個表S,C,SC   
     S(SNO,SNAME)代表(學号,姓名)   
     C(CNO,CNAME,CTEACHER)代表(課号,課名,教師)   
     SC(SNO,CNO,SCGRADE)代表(學号,課号成績)   
     問題:   
     1,找出沒選過“黎明”老師的所有學生姓名。   
     2,列出2門以上(含2門)不及格學生姓名及平均成績。   
     3,即學過1号課程有學過2号課所有學生的姓名。  
     */答案:  
     1、  
         select sname from s join sc on(s.sno = sc.sno) join c on (sc.cno = c.cno) where cteacher <> '黎明';  
     2、  
         select sname where sno in (select sno from sc where scgrade < 60 group by sno having count(*) >=2);  
     3、  
         select sname from s where sno in (select sno, from sc where cno=1 and cno in  
                             (select distinct sno from sc where cno = 2);  
                          )  
   
 94、--------------建立表--------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4),  
     email varchar2(50) unique  
     );  
 95、--------------給name字段加入 非空 限制,并給限制一個名字,若不取,系統預設取一個-------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4),  
     email varchar2(50)  
     );  
 96、--------------給nameemail字段加入 唯一 限制 兩個 null值 不為重複-------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4),  
     email varchar2(50) unique  
     );  
 97、--------------兩個字段的組合不能重複 限制:表級限制-------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4),  
     email varchar2(50),  
     constraint stu_name_email_uni unique(email, name)  
     );  
 98、--------------主鍵限制-------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4),  
     email varchar2(50),  
     constraint stu_id_pk primary key (id),  
     constraint stu_name_email_uni unique(email, name)  
     );  
   99、--------------外鍵限制   被參考字段必須是主鍵 -------------  
        create table stu  
     (  
     id number(6),  
     name varchar2(20) constraint stu_name_mm not null,  
     sex number(1),  
     age number(3),  
     sdate date,  
     grade number(2) default 1,  
     class number(4) references class(id),  
     email varchar2(50),  
     constraint stu_class_fk foreign key (class) references class(id),  
     constraint stu_id_pk primary key (id),  
     constraint stu_name_email_uni unique(email, name)  
     );  
       
     create table class   
     (  
     id number(4) primary key,  
     name varchar2(20) not null  
     );  
 100、---------------修改表結構,添加字段------------------  
     alter table stu add(addr varchar2(29));  
 101、---------------删除字段--------------------------  
     alter table stu drop (addr);  
 102、---------------修改表字段的長度------------------  
     alter table  stu modify (addr varchar2(50));--更改後的長度必須要能容納原先的資料  
 103、----------------删除限制條件----------------  
     alter table stu drop constraint  限制名  
 104、-----------修改表結構添加限制條件---------------  
     alter table  stu add constraint stu_class_fk foreign key (class) references class (id);  
 105、---------------資料字典表----------------  
      desc dictionary;  
      --資料字典表共有兩個字段 table_name comments  
      --table_name主要存放資料字典表的名字  
      --comments主要是對這張資料字典表的描述  
        
 105、---------------檢視目前使用者下面所有的表、視圖、限制-----資料字典表user_tables---  
     select table_name from user_tables;  
     select view_name from user_views;  
     select constraint_name from user-constraints;  
 106、-------------索引------------------  
     create index idx_stu_email on stu (email);-- 在stu這張表的email字段上建立一個索引:idx_stu_email  
 107、---------- 删除索引 ------------------  
     drop index index_stu_email;  
 108、---------檢視所有的索引----------------  
     select index_name from user_indexes;  
 109、---------建立視圖-------------------  
     create view v$stu as selesct id,name,age from stu;  
      視圖的作用: 簡化查詢 保護我們的一些私有資料,通過視圖也可以用來更新資料,但是我們一般不這麼用 缺點:要對視圖進行維護  
   
 110、-----------建立序列------------  
     create sequence seq;--建立序列  
     select seq.nextval from dual;-- 檢視seq序列的下一個值  
     drop sequence seq;--删除序列  
 111、------------資料庫的三範式--------------  
     (1)、要有主鍵,列不可分  
     (2)、不能存在部分依賴:當有多個字段聯合起來作為主鍵的時候,不是主鍵的字段不能部分依賴于主鍵中的某個字段  
     (3)、不能存在傳遞依賴   
 ==============================================PL/SQL==========================  
 112、-------------------在用戶端輸出helloworld-------------------------------  
     set serveroutput on;--預設是off,設成on是讓Oracle可以在用戶端輸出資料  
 113、begin  
     dbms_output.put_line('helloworld');  
     end;  
     /  
 114、----------------pl/sql變量的指派與輸出----  
     declare  
         v_name varchar2(20);--聲明變量v_name變量的聲明以v_開頭  
     begin  
         v_name := 'myname';  
         dbms_output.put_line(v_name);  
     end;  
     /  
 115、-----------pl/sql對于異常的處理(除數為0)-------------  
     declare  
         v_num number := 0;  
     begin  
         v_num := 2/v_num;  
         dbms_output.put_line(v_num);  
     exception  
         when others then  
         dbms_output.put_line('error');  
     end;  
     /  
 116、----------變量的聲明----------  
     binary_integer:整數,主要用來計數而不是用來表示字段類型   比number效率高  
     number:數字類型  
     char:定長字元串  
     varchar2:變長字元串  
     date:日期  
     long:字元串,最長2GB  
     boolean:布爾類型,可以取值true,false,null--最好給一初值  
 117、----------變量的聲明,使用 '%type'屬性  
     declare  
         v_empno number(4);  
         v_empno2 emp.empno%type;  
         v_empno3 v_empno2%type;  
     begin  
         dbms_output.put_line('Test');  
     end;  
     /  
     --使用%type屬性,可以使變量的聲明根據表字段的類型自動變換,省去了維護的麻煩,而且%type屬性,可以用于變量身上  
 118、---------------Table變量類型(table表示的是一個數組)-------------------  
     declare  
         type type_table_emp_empno is table of emp.empno%type index by binary_integer;  
             v_empnos type_table type_table_empno;  
     begin  
         v_empnos(0) := 7345;  
         v_empnos(-1) :=9999;  
         dbms_output.put_line(v_empnos(-1));  
     end;  
 119、-----------------Record變量類型  
     declare  
         type type_record_dept is record  
         (  
             deptno dept.deptno%type,  
             dname dept.dname%type,  
             loc dept.loc%type  
         );  
     begin  
         v_temp.deptno:=50;  
         v_temp.dname:='aaaa';  
         v_temp.loc:='bj';  
         dbms_output.put_line(v temp.deptno || ' ' || v temp.dname);  
     end;  
 120、-----------使用 %rowtype聲明record變量  
     declare  
         v_temp dept%rowtype;  
     begin  
         v_temp.deptno:=50;  
         v_temp.dname:='aaaa';  
         v_temp.loc:='bj';  
     dbms_output.put_line(v temp.deptno || '' || v temp.dname)             
     end;  
       
 121、--------------sql%count 統計上一條sql語句更新的記錄條數   
 122、--------------sql語句的運用  
     declare  
         v_ename emp.ename%type;  
         v_sal emp.sal%type;  
     begin  
         select ename,sal into v_ename,v_sal from emp where empno = 7369;  
         dbms_output.put_line(v_ename || '' || v_sal);  
     end;  
   
 123、  -------- pl/sql語句的應用  
     declare  
         v_emp emp%rowtype;  
     begin  
         select * into v_emp from emp where empno=7369;  
         dbms_output_line(v_emp.ename);  
     end;  
 124、-------------pl/sql語句的應用   
     declare  
         v_deptno dept.deptno%type := 50;  
         v_dname dept.dname%type :='aaa';  
         v_loc dept.loc%type := 'bj';  
     begin  
         insert into dept2 values(v_deptno,v_dname,v_loc);  
     commit;  
     end;  
 125、-----------------ddl語言,資料定義語言  
     begin  
         execute immediate 'create table T (nnn varchar(30) default ''a'')';  
     end;  
 126、------------------if else的運用  
      declare  
         v_sal emp.sal%type;  
      begin  
         select sal into v_sal from emp where empno = 7369;  
     if(v_sal < 2000) then  
         dbms_output.put_line('low');  
     elsif(v_sal > 2000) then  
         dbms_output.put_line('middle');  
     else   
         dbms_output.put_line('height');  
         end if;  
       end;  
 127、-------------------循環 =====do while  
     declare  
         i binary_integer := 1;  
     begin  
         loop  
                 dbms_output.put_line(i);  
                 i := i + 1;  
             exit when (i>=11);  
         end loop;  
     end;  
 128、---------------------while   
     declare  
         j binary_integer := 1;  
     begin  
         while j < 11 loop  
             dbms_output.put_line(j);  
         j:=j+1;  
         end loop;  
     end;  
 129、---------------------for  
     begin  
         for k in 1..10 loop  
             dbms_output.put_line(k);  
         end loop;  
         for k in reverse 1..10 loop  
             dbms_output.put_line(k);  
         end loop;  
     end;  
 130、-----------------------異常(1)  
     declare  
         v_temp number(4);  
     begin  
         select empno into v_temp from emp where empno = 10;  
     exception  
         when too_many_rows then  
             dbms_output.put_line('太多記錄了');  
         when others then  
             dbms_output.put_line('error');    
     end;  
 131、-----------------------異常(2)  
     declare  
         v_temp number(4);  
     begin  
         select empno into v_temp from emp where empno = 2222;  
     exception  
         when no_data_found then  
             dbms_output.put_line('太多記錄了');  
     end;  
 132、----------------------建立序列  
     create sequence seq_errorlog_id start with 1 increment by 1;  
 133、-----------------------錯誤處理(用表記錄:将系統日志存到資料庫便于以後檢視)  
   
   
    -- 建立日志表:  
     create table errorlog  
     (  
     id number primary key,  
     errcode number,  
     errmsg varchar2(1024),  
     errdate date  
     );  
   
   
       
     declare  
         v_deptno dept.deptno%type := 10;  
         v_errcode  number;  
         v_errmsg varchar2(1024);  
     begin  
         delete from dept where deptno = v_deptno;  
        commit;  
     exception  
         when others then  
             rollback;  
                 v_errcode := SQLCODE;  
                 v_errmsg := SQLERRM;  
         insert into errorlog values (seq_errorlog_id.nextval, v_errcode,v_errmsg, sysdate);  
                 commit;  
     end;  
 133---------------------PL/SQL中的重點cursor(遊标)和指針的概念差不多  
     declare  
         cursor c is  
             select * from emp; --此處的語句不會立刻執行,而是當下面的open c的時候,才會真正執行  
         v_emp c%rowtype;  
     begin  
         open c;  
             fetch c into v_emp;  
         dbms_output.put_line(v_emp.ename); --這樣會隻輸出一條資料 134将使用循環的方法輸出每一條記錄  
       close c;  
     end;  
 134----------------------使用do while  循環周遊遊标中的每一個資料  
     declare  
         cursor c is  
             select * from emp;  
         v_emp c%rowtype;  
     begin  
         open c;   
         loop  
             fetch c into v_emp;  
             (1) exit when (c%notfound);  --notfound是oracle中的關鍵字,作用是判斷是否還有下一條資料  
             (2) dbms_output.put_line(v_emp.ename);  --(1)(2)的順序不能颠倒,最後一條資料,不會出錯,會把最後一條資料,再次的列印一遍  
        end loop;  
        close c;  
     end;  
 135------------------------while循環,周遊遊标  
     declare  
         cursor c is  
             select * from emp;  
         v_emp emp%rowtype;  
     begin  
         open c;  
         fetch c into v_emp;  
         while(c%found) loop  
            dbms_output.put_line(v_emp.ename);  
            fetch c into v_emp;  
        end loop;  
        close c;  
     end;  
 136--------------------------for 循環,周遊遊标  
     declare  
         cursor c is  
            select * from emp;  
     begin  
         for v_emp in c loop  
             dbms_output.put_line(v_emp.ename);  
         end loop;  
     end;  
   
 137---------------------------帶參數的遊标  
     declare  
         cursor c(v_deptno emp.deptno%type, v_job emp.job%type)  
         is  
            select ename, sal from emp where deptno=v_deptno and job=v_job;  
         --v_temp c%rowtype;此處不用聲明變量類型  
     begin  
         for v_temp in c(30, 'click') loop  
             dbms_output.put_line(v_temp.ename);  
         end loop;  
     end;  
 138-----------------------------可更新的遊标  
     declare  
         cursor c  --有點小錯誤  
         is  
            select * from emp2 for update;  
         -v_temp c%rowtype;  
     begin  
        for v_temp in c loop  
         if(v_temp.sal < 2000) then  
             update emp2 set sal = sal * 2 where current of c;  
           else if (v_temp.sal =5000) then  
         delete from emp2 where current of c;  
            end if;  
          end loop;  
          commit;  
     end;  
 139-----------------------------------procedure存儲過程(帶有名字的程式塊)  
     create or replace procedure p  
         is--這兩句除了替代declare,下面的語句全部都一樣    
         cursor c is  
             select * from emp2 for update;  
     begin  
          for v_emp in c loop  
         if(v_emp.deptno = 10) then  
             update emp2 set sal = sal +10 where current of c;  
         else if(v_emp.deptno =20) then  
             update emp2 set sal =  sal + 20 where current of c;  
         else  
             update emp2 set sal = sal + 50 where current of c;  
         end if;  
         end loop;  
       commit;  
      end;  
       
     --執行存儲過程的兩種方法:  
     (1)exec p;(p是存儲過程的名稱)  
     (2)  
         begin  
             p;  
         end;  
         /  
 140-------------------------------帶參數的存儲過程  
     create or replace procedure p  
         (v_a in number, v_b number, v_ret out number, v_temp in out number)  
     is  
       
     begin  
         if(v_a > v_b) then  
             v_ret := v_a;  
         else  
             v_ret := v_b;  
         end if;  
         v_temp := v_temp + 1;  
     end;  
 141----------------------調用140  
     declare  
         v_a  number := 3;  
         v_b  number := 4;  
         v_ret number;  
         v_temp number := 5;  
   
     begin  
         p(v_a, v_b, v_ret, v_temp);  
         dbms_output.put_line(v_ret);  
         dbms_output.put_line(v_temp);  
     end;  
   
 142------------------删除存儲過程  
     drop procedure p;  
 143------------------------建立函數計算個人所得稅    
     create or replace function sal_tax  
         (v_sal  number)   
         return number  
     is  
     begin  
         if(v_sal < 2000) then  
             return 0.10;  
         elsif(v_sal <2750) then  
             return 0.15;  
         else  
             return 0.20;  
         end if;  
     end;  
 ----144-------------------------建立觸發器(trigger)  觸發器不能單獨的存在,必須依附在某一張表上  
   
     --建立觸發器的依附表  
       
     create table emp2_log  
     (  
     ename varchar2(30) ,  
     eaction varchar2(20),  
     etime date  
     );    
   
     create or replace trigger trig  
         after insert or delete or update on emp2 ---for each row 加上此句,每更新一行,觸發一次,不加入則值觸發一次  
     begin  
         if inserting then  
             insert into emp2_log values(USER, 'insert', sysdate);  
         elsif updating then  
             insert into emp2_log values(USER, 'update', sysdate);  
         elsif deleting then  
             insert into emp2_log values(USER, 'delete', sysdate);  
         end if;  
     end;  
 145-------------------------------通過觸發器更新資料  
     create or replace trigger trig  
         after update on dept  
         for each row  
     begin  
         update emp set deptno =:NEW.deptno where deptno =: OLD.deptno;  
     end;  
       
   
     ------隻編譯不顯示的解決辦法 set serveroutput on;  
 145-------------------------------通過建立存儲過程完成遞歸  
     create or replace procedure p(v_pid article.pid%type,v_level binary_integer) is  
         cursor c is select * from article where pid = v_pid;  
         v_preStr varchar2(1024) := '';  
     begin  
       for i in 0..v_leave loop  
         v_preStr := v_preStr || '****';  
       end loop;  
   
       for v_article in c loop  
         dbms_output.put_line(v_article.cont);  
         if(v_article.isleaf = 0) then  
             p(v_article.id);  
         end if;  
         end loop;  
       
     end;  
 146-------------------------------檢視目前使用者下有哪些表---  
     --首先,用這個使用者登入然後使用語句:  
     select * from tab;  
       
 147-----------------------------用Oracle進行分頁!--------------  
     --因為Oracle中的隐含字段rownum不支援'>'是以:  
     select * from (  
         select rownum rn, t.* from (  
             select * from t_user where user_id <> 'root'  
         ) t where rownum <6  
     ) where rn >3  
 148------------------------Oracle下面的清屏指令----------------  
     clear screen; 或者 cle scr;  
   
 149-----------将建立好的guohailong的這個使用者的密碼改為abc--------------  
     alter user guohailong identified by abc  
     --當密碼使用的是數字的時候可能會不行  
     
     
     
     
     
     
     --使用在10 Oracle以上的正規表達式在dual表查詢
  with test1 as(
        select 'ao' name from dual union all
        select 'yang' from dual union all
        select 'feng' from dual  )
        select distinct regexp_replace(name,'[0-9]','') from test1
   
 ------------------------------------------
 with tab as (
       select 'hong'  name from dual union all
       select 'qi' name from dual union all 
       select 'gong' name from dual) 
       select translate(name,'\\0123456789','\\') from tab; 
 
     
     
     
     
     
     
 CREATE OR REPLACE PROCEDURE 
     calc(i_birth VARCHAR2) IS 
     s VARCHAR2(8);  
     o VARCHAR2(8);  
     PROCEDURE cc(num VARCHAR2, s OUT VARCHAR2) IS 
     BEGIN 
     FOR i 
        IN REVERSE 2 .. length(num) LOOP
      s := s || substr(substr(num, i, 1) + substr(num, i - 1, 1), -1);
       END LOOP; 
        SELECT REVERSE(s) INTO s FROM dual; 
         END; 
          BEGIN o := i_birth; 
          LOOP 
           cc(o, s); 
           o := s; 
          dbms_output.put_line(s); 
         EXIT WHEN length(o) < 2; 
         END LOOP; 
      END; 
    set serveroutput on; 
      
  exec calc('19880323');  
  
  
  
  
  ----算命pl/sql
  with t as
  (select '19880323' x from dual)
	  select 
	    case 
		     when mod (i, 2) = 0 then '命好'
		     when  i = 9 		 then '命運悲慘' 
		        else '一般'
		     end result
	    from (select mod(sum((to_number(substr(x, level, 1)) +to_number(substr(x, -level, 1))) *                      
	         greatest(((level - 1) * 2 - 1) * 7, 1)),10) i from t connect by level <= 4);
       
       
 
--構造一個表,和emp表的部分字段相同,但是順序不同
SQL> create table t_emp as
  2  select ename,empno,deptno,sal
  3  from emp
  4  where 1=0
  5  /
 
Table created
 --添加資料
SQL> insert into t_emp(ename,empno,deptno,sal)
  2  select ename,empno,deptno,sal
  3  from emp
  4  where sal >= 2500 
  5  /
  
  
  select * from tb_product where createdate>=to_date('2011-6-13','yyyy-MM-dd') and createdate<=to_date('2011-6-16','yyyy-MM-dd');  


sysdate --擷取目前系統的時間




to_date('','yyyy-mm-dd')




select * from tb_product where to_char(createdate,'yyyy-MM-dd')>='2011-6-13' and to_char(createdate,'yyyy-MM-dd')<='2011-6-16';  




select * from tb_product where trunc(createdate)>=? and trunc(createdate)<=?
用trunc函數就可以了 




 </pre>
<p> </p>
<pre name="code" >第一次
1、Oracle安裝及基本指令
1.1、Orace簡介
Oracleso一個生産中間件和資料庫的較大生産商。其發展依靠了IBM公司。創始人是Larry Ellison。
1.2、Oracle的安裝
1) Oracle的主要版本
Oracle 8;
Oracle 8i;i,指的是Internet
Oracle 9i;相比Oracle8i比較類似
Oracle 10g;g,表示網格技術
所謂網格技術,拿百度搜尋為例,現在我們需要搜尋一款叫做“EditPlus”的文本編輯器軟體,當我們在百度搜尋框中輸入“EditPlus”進行搜尋時, 會得到百度為我們搜尋到的大量關于它的連結,此時,我們考慮一個問題,如果在我所處的網絡環境周邊的某個地方的伺服器就提供這款軟體的下載下傳(也就是說提供一個下載下傳連結供我們下載下傳),那麼,我們就沒必要去通路一個遠在地球對面的某個角落的伺服器去下載下傳這款軟體。如此一來就可以節省大量的網絡資源。使用網格技術就能解決這種問題。我們将整個網絡劃分為若幹個網格,也就是說每一個使用網絡的使用者,均存在于某一個網格,當我們需要搜尋指定資源時,首先在我們所處的網格中查找是否存在指定資源,沒有的話就擴大搜尋範圍,到更大的網格中進行查找,直到查找到為止。
2) 安裝Oracle的準備工作
關閉防火牆,以免影響資料庫的正常安裝。
3) 安裝Oralce的注意事項
為了後期的開發和學習,我們将所有資料庫預設賬戶的密碼設定為統一密碼的,友善管理和使用。
在點選“安裝”後,資料庫相關參數設定完成,其安裝工作正式開始,在完成安裝時,不要急着去點選“确定”按鈕,這時候,我們需要進行一個非常重要的操作——賬戶解鎖。因為在Oracle中預設有一個叫做scott的賬戶,該賬戶中預設有4張表,并且存有相應的資料,是以,為了友善我們學習Oracle資料庫,我們可以充分利用scott這個内置賬戶。但是奇怪的是,在安裝Oracle資料庫的時候,scott預設是鎖住的,是以在使用該賬戶之前,我們就需要對其進行解鎖操作。在安裝完成界面中,點選“密碼管理”進入到相應的密碼管理界面,找到scott賬戶,将是否解鎖一欄的去掉,即可完成解鎖操作,後期就可以正常使用scott賬戶。我們運作SQLPlus(Oracle提供的指令行操作),會提示我們輸入使用者名,現在我們可以輸入使用者名scott,回車後,會提示輸入密碼,奇怪的是,當我們輸入在安裝時設定的統一密碼時,提示登入拒絕,顯然是密碼錯誤,那麼,在Oracle資料庫中,scott的預設密碼是tiger,是以使用tiger可以正常登入,但是提示我們scott的目前密碼已經失效,讓我們重新設定密碼,建議還是設定為tiger。
在Oracle中内置了很多賬戶,那麼,我們來了解下一下幾個比較重要的内置賬戶:
   |-普通使用者:scott/tiger
   |-普通管理者:system/manager
   |-超級管理者:sys/change_on_install
4) 關于Oracle的服務
    在Oracle安裝完成之後,會在我們的系統中進行相關服務的注冊,在所有注冊的服務中,我們需要關注一下兩個服務,在實際使用Oracle的過程中,這兩個服務必須啟動才能使Oracle正常使用。
     |-第一個是OracleOraDb11g_home1TNSListener,監聽服務,如果用戶端想要連接配接資料庫,此服務必須開啟。
     |-第二個是OracleServiceORCL,資料庫的主服務。命名規則:OracleService + 資料庫名稱,此 服務必須啟動。
此後,我們可以通過指令行方式進入到SQLPlus的控制中心,進行指令的輸入。
1.3、SQLPlus
SQLPlus是Oracle提供的一種指令行執行的工具軟體,安裝之後會自動在系統中進行注冊。連接配接到資料庫之後,就可以開始對資料庫中的表進行操作了。
1) 對SQLPlus的環境設定
set linesize 長度;--設定每行顯示的長度
set pagesize 行數;--修改每頁顯示記錄的長度。
需要注意的是,上述連個參數的設定隻在目前的指令行有效,指令行視窗重新開機或者開啟了第二個視窗需要重新設定。
2) SQLPlus常用操作
在SQLPlus中輸入ed a.sql,會彈出找不到檔案的提示框,此時點選“是”,将建立一個a.sql檔案,并彈出文本編輯頁面,在這裡可以輸入相關的sql語句,編輯完成後儲存,在指令行中通過 @ a.sql的方式執行指令,如果建立的檔案字尾為“sql”,那麼在執行的時候可以省略掉,即可以這麼寫, @ a。除了建立不存在的檔案外,sqlplus中也可以通過指定本地存在的檔案進行指令的執行,方式為 @ 檔案路徑。
在SQLPlus中可以通過指令使用其他賬戶進行資料庫的連接配接,如,目前連接配接的使用者是scott,我們需要使用sys進行連接配接,則可以這麼操作:conn sys/430583 as sysdba,這裡需要說明的是,sys是超級管理者,當我們需要使用sys進行登入的時候,那麼需要額外的加上as sysdba表示sys将以管理者的身份登入。這裡有幾點可以測試下
|-當我們使用sys以sysdba的角色登入時,其密碼可以随意輸入,不一定是我們設定的統一密碼(430583)。是以,我們得出結論,在管理者登入時,隻對使用者進行驗證,而普通使用者登入時,執行使用者和密碼驗證。
在sys賬戶下通路scott下的emp表時,會提示錯誤,因為在sys中是不存在emp表的,那麼如果需要在sys下通路scott的表(也就是說需要在a使用者下通路b使用者下的表),該如何操作呢?首先,我們應該知道每個對象是屬于一種模式(模式是對使用者所建立的資料庫對象的總稱,包括表,視圖,索引,同義詞,序列,過程和程式包等)的,而每個賬戶對應一個模式,是以我們需要在sys下通路scott的表時,需要指明所通路的表是屬于哪一個模式的,即,我們可以這樣操作來實作上面的操作:select * from scott.emp;
如果我們需要知道目前連接配接資料庫的賬戶是誰,可以這樣操作:show user;
我們知道,一個資料庫可以存儲多張表,那麼,如何檢視指定資料庫的所有表名稱呢?select * from tab;
在開發過程中,我們需要經常的檢視某張表的表結構,這個操作可以這樣實作:desc emp;
在SQLPlus中,我們可以輸入“/”來快速執行上一條語句。例如,在指令行中我們執行了一條這樣的語句:select * from emp;但是我們需要再次執行該查詢,就可以輸入一個“/”就可快速執行。
3) 常用資料類型
    number(4)--&gt;表示數字,長度為4
    varchar2(10)--&gt;表示的是字元串,隻能容納10個長度
date--&gt;表示日期
number(7,2)--&gt;表示數字,小數占2位,整數占5位,總共7位
第二次
1、SQL語句
1.1 準備工作--熟悉scott賬戶下的四張表及表結構
第一張表emp--&gt;雇員表,用于存儲雇員資訊
empno number(4) 表示雇員的編号,唯一編号
ename varchar2(10) 表示雇員的姓名
job varchar2(9) 表示工作職位
mgr number(4) 表示一個雇員的上司編号
hiredate date 表示雇傭日期
sal number(7,2) 表示月薪,工資
comm number(7,2) 表示獎金
deptno number(2) 表示部門編号
第二張表dept--&gt;部門表,用于存儲部門資訊
deptno number(2) 部門編号
dname varchar2(14) 部門名稱
loc varchar2(13) 部門位置
第三張表salgrade--&gt;工資等級表,用于存儲工資等級
grade number 等級名稱
losal number 此等級的最低工資
hisal number 此等級的最高工資
第四張表bonus--&gt;獎金表,用于存儲一個雇員的工資及獎金
ename varchar2(10) 雇員姓名
job varchar2(9) 雇員工作
sal number 雇員工資
comm number 雇員獎金
1.2、SQL簡介
什麼是SQL?
SQL(Structured Query Language,結構查詢語言)是一個功能強大的資料語言。SQL通常用于與資料庫的通訊。SQL是關系資料庫管理系統的标準語言。SQL功能強大,概括起來,分為以下幾組:
|-DML--&gt;Data Manipulation Language,資料操縱語言,用于檢索或者修改資料,即主要是對資料庫表中的資料的操作。
|-DDL--&gt;Data Definition Language,資料定義語言,用于定義資料的結構,如建立、修改或者删除資料庫對象,即主要是對表的操作。
|-DCL--&gt;Data Control Language,資料控制語言,用于定義資料庫使用者的權限,即主要對使用者權限的操作。
1.3、簡單查詢語句
簡單查詢語句的文法格式是怎樣的?
select * |具體的列名 [as] [别名] from 表名稱;
需要說明的是,在實際開發中,最好不要使用*代替需要查詢的所有列,最好養成顯式書寫需要查詢的列名,友善後期的維護;在給查詢的列名設定别名的時候,可以使用關鍵字as,當然不用也是可以的。
拿emp表為例,我們現在需要查詢出雇員的編号、姓名、工作三個列的資訊的話,就需要在查詢的時候明确指定查詢的列名稱,即
select empno,ename,job from emp;
如果需要指定查詢的傳回列的名稱,即給查詢列起别名,我們可以這樣操作
select empno 編号,ename 姓名,job 工作 from emp;--省略as關鍵字的寫法
或者
select empno as 編号,ename as 姓名,job as 做工 from emp; --保留as關鍵字的寫法
如果現在需要我們查詢出emp中所有的job,我們可能這麼操作
select job from emp;
可能加上一個别名會比較好
select job 工作 from emp;
但是現在出現了一個問題,從查詢的結果中可以看出,job的值是有重複的,這是為什麼呢?因為我們知道一個job職位可能會對應多個雇員,比如,在一個公司的市場部會有多名市場人員,在這裡我們使用select job from emp;查詢的實際上是目前每個雇員對應的工作職位,有多少
個雇員,就會對應的查詢出多少個職位出來,是以就出現了重複值,為了消除這樣的重複值,我們在這裡可以使用關鍵字distinct,接下來我們繼續完成上面的操作,即
select distinct job from emp;
是以,我們可以看到,使用distinct的文法是這樣的:
select distinct *|具體的列名 别名 from 表名稱;
但是在消除重複列的時候,需要強調的是,如果我們使用distinct同時查詢多列時,則必須保證查詢的所有列都存在重複資料才能消除掉。也就是說,當我們需要查詢a,b,c三列時,如果a表存在重複值,但是b和c中沒有重複值,當使用distinct時是看不到消除重複列的效果的。拿scott中的emp表為例,我們需要查詢出雇員編号及雇員工作兩個列的值,我們知道一個工作會對應多個雇員,是以,在這種操作中,雇員編号是沒有重複值的,但是工作有重複值,是以,執行此次查詢的結果将是得到每一個雇員對應的工作名稱,顯然,distinct沒起到作用。
現在我們得到了一個新的需求,要求我們按如下的方式進行查詢:
編号是:7369的雇員,姓名是:SMITH,工作是:CLERK
那麼,我們該如何解決呢?在這裡,我們需要使用到Oracle 中的字元串連接配接(“||”)操作來實作。如果需要顯示一些額外資訊的話,我們需要使用單引号将要顯示的資訊包含起來。那麼,上面的操作可以按照下面的方式進行,
select '編号是' || empno || '的雇員,姓名是:' || ename || ',工作是:' || job from emp;
下面我們再看一個新的應用。公司業績很好,是以老闆想加薪,所有員工的工資上調20%,該如何實作呢?難道在表中一個一個的修改工資列的值嗎?很顯然不是的,我們可以通過使用四則運算來完成加薪的操作。
select ename,sal*1.2 newsal from emp;--newsal是為上調後的工資設定的列名
四則運算,+、-、*、/,同樣有優先順序,先乘除後加減。
1.4、限定查詢(where子句)
在前面我們都是将一張表的全部列或者指定列的所有資料查詢出來,現在我們有新的需求了,需要在指定條件下查詢出資料,比如,需要我們查詢出部門号為20的所有雇員、查詢出工資在3000以上的雇員資訊......,這些所謂的查詢限定條件就是通過where來指定的。我們先看看如何通過限定查詢的方式進行相關操作。我們在前面知道了簡單的查詢文法是:
select *|具體的列名 from 表名稱;
那麼,限定查詢的文法格式如下:
select *|具體的列名 from 表名稱 where 條件表達式;
首先,我們現在要查詢出工資在1500(不包括1500)之上的雇員資訊
select * from emp where sal&gt;1500;
下面的操作是查詢出可以得到獎金的雇員資訊(也就是獎金列不為空的記錄)
select * from emp where comm is not null;
很顯然,查詢沒有獎金的操作就是
select * from emp where comm is null;
我們來點複雜的查詢,查詢出工資在1500之上,并且可以拿到獎金的雇員資訊。這裡的限定條件不再是一個了,當所有的限定條件需要同時滿足時,我們采用and關鍵字将多個限定條件進行連接配接,表示所有的限定條件都需要滿足,是以,該查詢可以這麼進行:
select * from emp where sal&gt;1500 and comm is not null;
現在的需求發生了變化,要求查詢出工資在1500之上,或者可以領取到獎金的雇員資訊。這裡的限定條件也是兩個,但是有所不同的是,我們不需要同時滿足着兩個條件,因為需求中寫的是
“或者”,是以在查詢時,隻需要滿足兩個條件中的一個就行。那麼,我們使用關鍵字or來實作“或者”的功能。
select * from emp where sal&gt;1500 or comm is not null;
需求再次發生變化,查詢出工資不大于1500(小于或等于1500),同時不可以領取獎金的雇員資訊,可想這些雇員的工資一定不怎麼高。之前我們使用not關鍵字對限定條件進行了取反,那麼,這裡就相當于對限定條件整體取反。我們分析下,工資不大于1500同時不可以領取獎金的反面含義就是工資大于1500同時可以領取獎金,是以,我們這樣操作:
select * from emp where sal&gt;1500 and comm is not null;
這是原始需求取反後的查詢語句,那麼為了達到最終的查詢效果,我們将限定條件整體取反,即
select * from emp where not(sal&gt;1500 and comm is not null);
在這裡,我們通過括号将一系列限定條件包含起來表示一個整體的限定條件。
我們在數學中學過這樣的表達式:100&lt;a&lt;200,那麼在資料庫中如何實作呢?一樣的,我們現在要查詢出工資在1500之上,但是在3000之下的全部雇員資訊,很顯然,兩個限定條件,同時要滿足才行。
select * from emp where sal&gt;1500 and sal&lt;3000;
這裡不要異想天開的寫成select * from emp where 1500&lt;sal&lt;3000;()試試吧,絕對會報錯。 很簡單,資料庫軟體不支援這樣的寫法,至少現在的資料庫沒有誰去支援這樣的寫法。
在SQL文法中,提供了一種專門指定範圍查詢的過濾語句:between x and y,相當于a&gt;=x and a&lt;=y,也就是包含了等于的功能,其文法格式如下:
select * from emp where sal between 1500 and 3000;
現在我們使用這種範圍查詢的方式修改上面的語句如下:
select * from emp where sal between 1500 and 3000;
好了,我們現在開始使用資料庫中非常重要的一種資料類型,日期型。
查詢出在1981年雇傭的全部雇員資訊,看似很簡單的一個查詢操作,這樣寫嗎?
select * from emp where hiredate=1981;()
很顯然,有錯。hiredate是date類型的,1981看似是一個年份(日期),但是像這樣使用,它僅僅是一個數字而已,類型都比對,怎麼進行相等判斷呢?繼續考慮。我們先這樣操作,查詢emp表的所有資訊,
select * from emp;
從查詢結果中,我們重點關注hiredate這一列的資料格式是怎麼定義的,
20-2月 -81,很顯然,我們抽象的表示出來是這樣的,
一個月的第幾天-幾月 -年份的後兩位
是以,接下來我們就有思路了,我們就按照這樣的日期格式進行限定條件的設定,該如何設定呢?考慮下,查詢1981年雇傭的雇員,是不是這個意思,從1981年1月1日到1981年12月31日雇傭的就是我們需要的資料呢?是以,這樣操作吧
select * from emp where hiredate between '1-1月 -81' and '31-12月 -81';
可以看到,上面的限定條件使用了單引号包含,我們暫且可以将一個日期看做是一個字元串。由上面的範例中我們得到結論:between...and ...除了可以進行數字範圍的查詢,還可以進行日期範圍的查詢。
我們再來看下面的例子,查詢出姓名是smith的雇員資訊,嗯,很簡單,這樣操作
select * from emp where ename='smith';
看似沒有問題,限定條件也給了,單引号也沒有少,可是為什麼查詢不到記錄呢?明明記得emp表中有一個叫做smith的雇員呀?難道被删掉了,好吧,我們不需要在這裡耗費時間猜測語句自身的問題了,上面的語句在文法上沒有任何問題,我們先看看emp表中有哪些雇員,
select * from emp;
可以看到,确實有一個叫做smith的雇員,但是不是smith,而是SMITH,是以,我們忽略了一個很重要的問題,Oracle是對大小寫敏感的。是以,更改如下:
select * from emp where ename='SMITH';
現在看一個這樣的例子,要求查詢出雇員編号是7369,7499,7521的雇員資訊。如果按照以前的做法,是這樣操作的,
select * from emp where empno=7369 or empno=7499 or empno=7521;
執行一下吧,确實沒任何問題,查詢出指定雇員編号的所有資訊。但是SQL文法提供一種更好的解決方法,使用in關鍵字完成上面的查詢,如下:
select * from emp where empno in(7369,7499,7521);
總結下in的文法如下:
select * from tablename where 列名 in (值1,值2,值3);
select * from tablename where 列名 not in (值1,值2,值3);
需要說明的是,in關鍵字不光可以用在數字上,也可以用在字元串的資訊上。看下面的例子
查詢出姓名是SMITH、ALLEN、KING的雇員資訊
select * from emp where ename in('SMITH','ALLEN','KING');
如果在指定的查詢範圍中附加了額外的内容,不會影響查詢結果。
模糊查詢對于提高使用者體驗是非常好的,對于資料庫的模糊查詢,我們通過like關鍵字來實作。首先我們了解下like主要使用的兩種通配符:
|-“%”--&gt;可以比對任意長度的内容,包括0個字元;
|-“_”--&gt;可以比對一個長度的内容。
下面我們看這樣一個需求,查詢所有雇員姓名中第二個字母包含“M”的雇員資訊
select * from emp where ename like '_M%';
說明下,前面的“_”比對姓名中第一個字母(任意一個字母),“%”比對M後面出現的0個或者多個字母。
查詢出雇員姓名中包含字母M的雇員資訊。分析可知,字母M可以出現在姓名的任意位置,如何進行正确的比對呢?
select * from emp where ename like '%M%';
這裡還是使用%,比對0個或者多個字母,即可以表示M出現在姓名的任意位置上。
如果我們在使用like查詢的時候沒有指定查詢的關鍵字,則表示查詢内容,即
select * from emp where ename like '%%';
相當于我們前面看到的
select * from emp;
前面我們遇到了一個這樣的需求,查詢出在1981年雇傭的所有雇員資訊,當時我們采取的是使用範圍查詢between ... and ...實作的,現在我們使用like同樣可以實作
select * from emp where hiredate like '%81%';
查詢工資中包含6的雇員資訊
select * from emp where sal like '%5%';
在操作條件中還可以使用:&gt;、&gt;=、=、&lt;、&lt;=等計算符号
對于不等于符号,有兩種方式:&lt;&gt;、!=
現在需要我們查詢雇員編号不是7369的雇員資訊
select * from emp where empno&lt;&gt;7369;
select * from emp where empno!=7369;
1.5、對查詢結果進行排序(order by子句)
在查詢的時候,我們常常需要對查詢結果進行一種排序,以友善我們檢視資料,比如以雇員編号排序,以雇員工資排序等。排序的文法是:
select *|具體的列名稱 from 表名稱 where 條件表達式 order by 排序列1,排序列2 asc|desc;
asc表示升序,預設排序方式,desc表示降序。
現在要求所有的雇員資訊按照工資由低到高的順序排列
select * from emp order by sal;
在更新開發中,會遇到多列排序的問題,那麼,此時,會給order by指定多個排序列。要求查詢出10部門的所有雇員資訊,查詢的資訊按照工資由高到低排序,如果工資相等,則按照雇傭日期由早到晚排序。
select * from emp where deptno=10 order by sal desc,hiredate asc;
需要注意的是,排序操作是放在整個SQL語句的最後執行。
1.6、單行函數
在衆多的資料庫系統中,每個資料庫之間唯一不同的最大差別就在于函數的支援上,使用函數可以完成一系列的操作功能。單行函數文法如下:
function_name(column|expression,[arg1,arg2...])
參數說明:
function_name:函數名稱
columne:資料庫表的列名稱
expression:字元串或計算表達式
arg1,arg2:在函數中使用參數
單行函數的分類:
字元函數:接收字元輸入并且傳回字元或數值
數值函數:接收數值輸入并傳回數值
日期函數:對日期型資料進行操作
轉換函數:從一種資料類型轉換到另一種資料類型
通用函數:nvl函數,decode函數
字元函數:
專門處理字元的,例如可以将大寫字元變為小寫,求出字元的長度。
現在我們看一個例子,将小寫字母轉為大寫字母
select upper('smith') from dual;
在實際中,我們會遇到這樣的情況,使用者需要查詢smith雇員的資訊,但是我們資料庫表中存放的是SMITH,這時為了友善使用者的使用我們将使用者輸入的雇員姓名字元串轉為大寫,
select * from emp where ename=upper('smith');
同樣,我們也可以使用lower()函數将一個字元串變為小寫字母表示,
select lower('HELLO WORLD') from dual;
那麼,将字元串的首字母變為大寫該如何實作呢?我們使用initcap()函數來完成上面的操作。
select initcap('HELLO WOLRD') from dual;
在前面的學習中我們知道,在scot賬戶下的emp表中的雇員姓名采用全大寫顯示,現在我們需要激昂姓名的首字母變為大寫,該如何操作呢?
select initcap(ename) from emp;
我們在前面使用了字元串連接配接操作符“||”對字元串連接配接顯示,比如:
select '編号為' || empno || '的姓名是:' || ename from emp;
那麼,在字元函數中提供concat()函數實作連接配接操作。
select concat('hello','world') from dual;
上面的範例使用函數實作如下:
select concat('編号為',empno,'的姓名是:',ename);?????????
此種方式不如連接配接符“||”好使。
在字元函數中可以進行字元串的截取、求出字元串的長度、進行指定内容的替換
select substr('hello',1,3) 截取字元串,length('hello') 字元串長度,replace('hello','l','x') 字元串替換 from dual;
通過上面範例的操作,我們需要注意幾以下:
Oralce中substr()函數的截取點是從0開始還是從1開始;針對這個問題,我們來操作看下,将上面的截取語句改為:
select substr('hello',0,3) 截取字元串 from dual;
由查詢結果可以發現,結果一樣,也就是說從0和從1的效果是完全一樣,這歸咎于Oracle的智能化。
如果現在要求顯示所有雇員的姓名及姓名的後三個字元,我們知道,每個雇員姓名的字元串長度可能不同,是以我們采取的措施是求出整個字元串的長度在減去2,我們這樣操作,
select ename,substr(ename,length(ename)-2) from emp;
雖然功能實作了,但是有沒有羽化的方案呢?當然是有的,我們分析下,當我們在截取字元串的時候,給定一個負數值是什麼效果,對,就是倒着截取,我們采取這種方式優化如下:
select ename,substr(ename,-3) from emp;
數值函數:
四舍五入:round()
截斷小數位:trunc()
取餘(取模):mod()
執行四舍五入操作,可以指定保留的小數位
select round(789.536) from dual;
select round(789.436) from dual;
select round(789.436,2) from dual;
可以直接對整數進行四舍五入的進位
select round(789.536,-3) from dual;--1000
select round(789.536,-2) from dual;--800
trunc()函數與round()函數的不同在于,trunc不會保留任何的小數位,而且小數點也不會執行四舍五入的操作,也就是說在使用trunc()函數時,它會将數值從小數點截斷,隻保留整數部分。
select trunc(789.536) from dual;--789
當然使用trunc()函數也可以設定小數位的保留位數
select trunc(789.536,2) from dual;--789.53
select trunc(789.536,-2) from dual;--700
使用mod()函數可以進行取餘的操作
select mod(10,3) from dual;--1
日期函數:
在Oracle中提供了很多餘日期相關的函數,包括加減日期等。但是在日期進行加或者減結果的時候有一些規律:
日期-數字=日期
日期+數字=日期
日期-日期=數字(天數的內插補點)
顯示部門10的孤雁進入公司的星期數,要想完成此查詢,必須知道目前的日期,在Oralce中可以通過以下的操作求出目前日期,使用sysdate表示
select sysdate from dual;
如何求出星期數呢?使用公式:目前日期-雇傭日期=天數 / 7 = 星期數,是以
select empno,ename,round((sysdate-hiredate)/7) from emp;
在Oracle中提供了以下的日期函數支援:
months_between()--&gt;求出給定日期範圍的月數
add_months()--&gt;在指定日期上加上指定的月數,求出之後的日期
next_day()--&gt;下一個的今天是哪一個日期
last_day()--&gt;求出給定日期的最後一天日期
查詢出所有雇員的編号,姓名,和入職的月數
select empno,ename,round(months_between(sysdate,hiredate)) from emp;
查詢出目前日期加上4個月後的日期
select add_months(sysdate,4) from dual;
查詢出下一個給定日期數
select next_day(sysdate,'星期一') from dual;
查詢給定日期的最後一天,也就是給定日期的月份的最後一天
select last_day(sysdate) from dual;
轉換函數:
to_char()--&gt;轉換成字元串
to_number()--&gt;轉換成數字
to_date()--&gt;轉換成日期
我們先看看前面做的一個範例,查詢所有雇員的雇員編号,姓名和雇傭時間
select empno,ename,hiredate from emp;
但是現在的要求是講年、月、日進行拆分,此時我們就需要使用to_char()函數進行拆分,拆分的時候必須指定拆分的通配符:
年--&gt;y,年是四位數字,是以使用yyyy表示
月--&gt;m,月是兩位數字,是以使用mm表示
日--&gt;d,日是兩位數字,是以使用dd表示
select empno,ename,to_char(hiredate,'yyyy') year,to_char(hiredate,'mm') month,to_char(hiredate,'dd') day from emp;
我們還可以使用to_char()進行日期顯示的轉換功能,Oracle中預設的日期格式是:19-4月 -87,而中國喜歡的格式是:1987-04-19
select empno,ename,to_char(hiredate,'yyyy-mm-dd') from emp;
從顯示結果中我們可以看到,對于月份和日的顯示中,如果不足10,就會自動補零,哪個0我們成為前導0,如果不希望顯示前導0的話,則可以使用fm去掉
select empno,ename,to_char(hiredate,'fmyyyy-mm-dd') from emp;
當然,to_char()也可以用在數字上
查詢全部的雇員編号、姓名和工資
select empno,ename,sal from emp;
我們可以看到,當工資數比較大時,是不利于讀的,那麼,我們可以在數字中使用“,”每3位進行一個分隔,此時,就可以使用to_char()進行格式化。格式化時,9并不代表實際的數字9,而是一個占位符
select empno,ename,to_char(sal,'99,999') from emp;
還有一個問題,工資數表示的是美元還是人民币呢?如何解決顯示區域的問題呢?我們可以使用下面的兩種符号:
L--&gt;表示Local的縮寫,以本地的語言進行金額的顯示
$--&gt;表示美元
select empno,ename,to_char(sal,'$99,999') from emp;
to_number()是可以講字元串變為數字的函數
select to_number('123') + to_number('123') from dual;
to_date()可以講一個字元串變為date的資料
select to_date('2012-09-12','yyyy-mm-dd') from dual;
通用函數:
現在又這樣一個需求,求出每個雇員的年薪。我們知道求年薪的話應該加上獎金的,格式為(sal+comm)*12
select empno,ename,(sal+comm)*12 from emp;
檢視結果,可以發現一個很奇怪的顯現,竟然有的雇員年薪為空,這是如何引起的呢?我們分析下,首先可以檢視下所有雇員的獎金列資料,發現隻有部分雇員才可以領取獎金,沒有領取獎金
的雇員其comm列是空的,沒有任何值(null),由此,上面的四則運算顯然沒結果。為了解決這個問題,我們需要用到一個通用函數nvl,将一個指定的null值變為指定的内容
select empno,ename,(sal+nvl(comm,0))*12 from emp;
decode()函數,此函數類似于if...elseif...else語句
其文法格式為:
decode(col/expression,search1,result1[search2,result2,......][,default])
說明:col/expression--&gt;列名或表達式
search1.search2......--&gt;為用于比較的條件
result1、result2......--&gt;為傳回值
如果col/expression和search i 相比較,相同的話傳回result i ,如果沒有與col/expression相比對的結果,則傳回預設值default。
select decode(1,1,'内容是1',2,'内容是2',3,'内容是3') from dual;
那麼,如何在對表查詢時使用decode()函數呢?我們來定義一個需求,
現在雇員的工作職位有:
CLERK--&gt;業務員
SALESMAN--&gt;銷售人員
MANAGER--&gt;經理
ANALYST--&gt;分析員
PRESIDENT--&gt;總裁
要求我們查詢出雇員的編号,姓名,雇傭日期及工作,将工作替換為上面的中文
select empno 雇員編号,ename 雇員姓名,hiredate 雇傭日期,decode(job,'CLERK','業務員','SALESMAN','銷售人員','MANAGER','經理','ANALYST','分析員','PRESIDENT','總裁') 職位 from emp;
從查詢結果可以看出,所有的職位都被相應的中文替換了。
1.7、SQL文法練習
現在我們再次通過相應的練習對scott賬戶下的四張表做進一步的熟悉。
選擇部門30中的所有員工。
select * from emp where deptno=30;
此查詢包含一個限定條件
列出所有業務員的姓名,編号和部門編号。
select empno 編号,ename 姓名,deptno 部門編号 from emp where job='CLERK';
此查詢應用了别名,單個限定條件,需要注意的是Oracle是區分大小寫的,是以我們要将業務員大寫為“CLERK”才能查詢出資料,或者使用upper()函數。
select empno 編号,ename 姓名,deptno 部門編号 from emp where job=upper('clerk');
找出傭金高于工資的雇員資訊
select * from emp where comm&gt;sal;
此查詢為單個限定條件的查詢
找出傭金高于工資的60%的雇員資訊
select * from emp where comm&gt;sal*0.6;
此查詢使用了比較運算符和四則運算符
找出部門10中所有經理和部門20中所有業務員的詳細資訊。
select * from emp where (deptno=10 and job='MANAGER') or (deptno=20 and job='CLERK');
此查詢使用了多限定查詢,邏輯運算符and 和 or ,并且使用()将多個限定條件包含作為一個整體看待。
看一個比較複雜的需求。找出部門10中所有經理,部門20中所有業務員,既不是經理又不是業務員但是工資大于或等于2000的所有雇員資訊。
select * from emp where (deptno=10 and job='MANAGER') or (deptno=20 and job='CLERK') or (sal&gt;=2000 and job not in('MANAGER','CLERK'));
找出領取傭金的雇員的不用工作。這個需求包含的資訊有,工作會重複複,是以我們需要使用關鍵字distinct消除重複的記錄,能夠領取傭金說明comm is not null
select distinct job from emp where comm is not null;
找出不能領取傭金或者領取的傭金低于100的雇員資訊
select * from emp where comm is null or comm&lt;100;
找出每個月中倒數第三天雇傭的雇員資訊,我們分析下,Oracle為我們提供了一個叫做last_day()的函數,它的功能是查詢出指定日期的最後一天對應的日期,但是我們這裡是要查詢倒數第三天,如何處理?我們按照倒序的思想,将最後一天減去2不就得到了倒數第三天嗎?
select * from emp where last_day(hiredate)-2=hiredate;
來一個很有趣的需求,找出早于12年前雇傭的雇員資訊,我們将這個需求轉變下,我們知道Oracle中有一個函數叫做months_between(),它的作用是查詢出給定的日期的內插補點,這個內插補點是月份數,是以,我們這麼考慮
select * from emp where months_between(sysdate,hiredate)/12&gt;12;
看一個字元函數的應用。以首字母大寫的方式顯示所有雇員的姓名
select initcap(ename) from emp;
顯示雇員姓名長度正好是5的雇員姓名
select ename from emp where length(ename)=5;
顯示雇員姓名中不含“R”的雇員姓名
select ename from emp where ename not like '%R%';
此查詢使用了like語句做模糊查詢,當like後指定的關鍵字為“%%”時,表示查詢出所有資料
顯示所有雇員姓名的前三個字元
select substr(ename,0,3) from emp;
select substr(ename,1,3) from emp;
此處應該強調的是,截取點的指定中,0和1的效果是一樣的。
顯示所有雇員的姓名,并且用“a”替換所有的“A”
select ename,replace(ename,'A','a') from emp;
此處要強調的是replace()函數的參數中,第一個表示需要做替換操作的列名稱,第二個參數是新的字元串,第三個參數表示的是原始的字元串,也就是需要替換的字元串。
顯示工齡為10或以上的雇員姓名和雇傭日期
select ename,hiredate from emp where months_between(sysdate,hiredate)/12&gt;10;
顯示雇員的詳細資訊,并按照姓名排序
select * from emp order by ename;
顯示雇員的姓名和雇傭時間,根據其工齡,将最老的雇員排在最前面
select ename,hiredate from emp order by hiredate;
顯示所有雇員的姓名、工作和工資,按照工作降序排列,若工作相同則按照工資排序
select ename,job,sal from emp order by job desc,sal;
顯示所有雇員的姓名、雇傭的年份,月份,按照雇傭日期所在月排序,如果月份相同則将最早的年份的雇員排在最前面。此需求首先要求出所有雇員的雇傭月份,使用to_char()函數求出月份
select ename,to_char(hiredate,'mm') month,to_char(hiredate,'yyyy') year from emp order by month,year;
顯示在一個月為30天的情況下所有雇員的日薪,忽略餘數。忽略餘數使用round()函數完成
select ename,round(sal/30) from emp;
找出在每年2月份雇員的所有雇員資訊
select * from emp where to_char(hiredate,'mm')=2;
此處還是使用了to_char()函數求出月份
對于每個雇員,顯示其到今天為止的總天數
select ename,round(sysdate-hiredate) from emp;
顯示雇員姓名中包含“A”的所有雇員姓名
select ename from emp where ename like '%A%';
以年月日的方式顯示所有雇員的工齡。年,求出總月數/12,此時會産生小數,但是我們不能再這裡進行四舍五入,而是采用trunc()函數得到整數部分
select ename,trunc(months_between(sysdate,hiredate)/12) year from emp;
現在工齡的年得到了,下面求出月份,我們知道年除完之後的餘數就是月,使用取餘函數進行處理
select ename ,trunc(months_between(sysdate,hiredate)/12) year,trunc(mod(months_between(sysdate,hiredate),12)) month from emp;
得到月份後,如何求出天數呢?我們知道日期-日期得到的是天數(需要做取整處理),将總天數/30(假設每月為30天)得到的就是剩餘的天數值
select ename ,trunc(months_between(sysdate,hiredate)/12) year,trunc(mod(months_between(sysdate,hiredate),12)) month,trunc(mod(sysdate-hiredate,30)) day from emp;
這樣就完成了上面的查詢操作。
第三次
1、Oracle
1.1、多表查詢
1) 多表查詢的基本文法
前面的查詢都是針對一張表的操作,如果在查詢的時候涉及到多張表,那麼就稱為多表查詢,奪标查詢的文法如下:
select *|具體的列名 from 表名稱1,表名稱2 where 條件表達式 order by 排序字段 asc|desc;
下面看一個例子,對emp表和dept表進行查詢
select * from emp,dept;
如此多的資料,我們要向知道目前的記錄總數,如何操作呢?
select count(*) from emp,dept;--56
select count(*) from emp;--14
select count(*) from emp;--4
此處查詢使用count(*|具體的列名)查詢總記錄數
上面的三條查詢語句分别得到了多表查詢,單表查詢的總記錄數,很明顯的看到,多表查詢的記錄數56并不等于單表查詢的總記錄數之和18,怎麼回事呢?因為,在進行多表查詢時,會産生笛卡爾積,如果表的資料越多,那麼笛卡爾積就會越大。如果現在有5張表,每張表有10000條資料,查詢5張表會産生10000的5次方條資料,是以在實際開發中多表查詢不建議過多的使用。
要向去掉笛卡爾積,可以使用關聯來實作。現在我們知道emp表中有字段deptno,dept表中有字段deptno,emp.deptno=dept.deptno就是灌籃字段。在多表查詢中加入where語句就可以消除笛卡爾積
select * from emp,dept where emp.deptno=dept.deptno;
此時查詢的記錄數為14條,但是如果表名過長的話,不友善我們使用,是以一般我們會為表名設定别名,
select * from emp e,dept d where e.deptno=d.deptno;
如果在進行多表查詢時,最好為表名設定别名
要求查詢出雇員的編号、雇員姓名、部門編号、部門名稱及部門位置
select e.empno,e.ename,e.deptno,d.dname,d.loc from emp e,dept d where e.deptno=d.deptno;
要求查詢出每個雇員的姓名,工作,雇員的直接上級上司的姓名
select e.ename,e.job,m.ename from emp e,emp m where e.mgr=m.empno;
此處查詢将emp表做自身的關聯
繼續擴充之前的程式,要求将雇員素在部門名稱同時列出
select e.ename,e.job,m.ename,d.dname from emp e,emp m,dept d where e.mgr=m.empno and e.deptno=d.deptno;
查詢出每個雇員的姓名,工資,部門名稱,工資等級,以及上司的姓名及工資所在公司的等級
先确定工資等級表
select * from salgrade;
在查詢出每個雇員的姓名,工資,部門名稱和工資等級
select e.ename,e.sal,d.dname,s.grade from emp e,dept d,salgrade s where e.deptno=d.deptno and e.sal between s.losal and s.hisal;
查詢其上司的姓名及工資等級
select e.ename,e.sal,m.ename,decode(ms.grade,1,'第五等工資',2,'第四等工資',3,'第三等工資',4,'第二等工資',5,'第一等工資'),decode(s.grade,1,'第五等工資',2,'第四等工資',3,'第三等工資',4,'第二等工資',5,'第一等工資'),d.dname from emp e,emp m,dept d,salgrade s,salgrade ms where e.mgr=m.empno and m.sal between ms.losal and ms.hisal and e.deptno=d.deptno and e.sal between s.losal and s.hisal;
2) 左、右連接配接
現在我們先查詢下dept表中的資料
select * from dept;
可以看到,dept表中包含了4條記錄,現在我們将emp表和dept表關聯查詢,查詢一下指定的字段
select e.empno,e.ename,d.deptno,d.dname,d.loc from emp e,dept d where e.deptno=d.deptno;
有查詢結果可以看到,部門表中的部門号隻出現了3個,因為在雇員表中沒有指定40部門的雇員,但是我們現在需要檢視兩張表關聯後的完整資訊,該如何進行呢?
select e.empno,e.ename,d.deptno,d.dname,d.loc from emp e,dept d where e.deptno(+)=d.deptno;
現在的結果中沒有指定雇員的部門資訊也顯示出來了。這裡我們使用到了右連接配接。有如下規律:
(+)在=左邊表示右連接配接,查詢時以=右邊的表作為标準
(+)在=右邊表示左連接配接,查詢時以=左邊的表作為标準
在前面我們有過如下操作:查詢雇員的編号,姓名及其上司的編号、姓名
select e.empno,e.ename,m.ename from emp e,emp m where e.mgr=m.empno;
但是我們仔細觀察會發現,雇員名稱為KING的雇員資訊沒有顯示出來,我們知道KING為president,沒有上司,是以按照上面的方式是不能查詢出來的,修改如下:
select e.empno,e.ename,m.ename from emp e,emp m where e.mgr=m.empno(+);
發現在加入做連結後KING出現了。
3) SQL:1999文法對SQL的支援
SQL:1999文法格式如下:
select table1.column,table2.column from table1
[cross join table2]|
[natural join table2]|
[join table2 using(column_name)]|
[join table2 on(table1.column_name=table2.column_name)]|
[left|right|full outer join table2 on(table1.column_name=table2.column_name)];
交叉連接配接(cross join):産生笛卡爾積
select * from emp cross join dept;--56
自然連接配接(natural join):自動進行關聯字段的比對
select * from emp natural join dept;
相當于
select * from emp,dept where emp.deptno=dept.deptno;
using子句:直接關聯的操作列
select * from emp e join dept d using(deptno) where deptno=30;
on子句,使用者自己編寫連接配接的條件
select * from emp e join dept d on(e.deptno=d.deptno) where d.deptno=30;
左連接配接(左外連接配接)、右連接配接(右外連接配接):left join,right join
select e.ename,d.deptno,d.dname,d.loc from emp e right outer join dept d on(e.deptno=d.deptno);
1.2、組函數及分組統計
什麼是分組?
舉例吧,把所有男生分為一組,把所有女生分為一組。
如果想要求出每一組的平均身高,評價呢年齡等,就需要使用分組函數。
1) 組函數
在SQL中常用的組函數有以下幾個:
count()--&gt;求出全部的記錄數
max()--&gt;求出一組資料中的最大值
min()--&gt;求出一組資料中的最小值
avg()--&gt;求出平均值
sum()--&gt;求和
count()函數:
現在我們需要查詢出emp中有多少個雇員
select count(*) from emp;--14
max()、min(),求最大最小值,一般是針對數字的應用
求出所有雇員的最低工資
select min(sal) from emp;
求出所有雇員的最高工資
select max(sal) from emp;
sum()、avg(),求和,求平均值
求出部門20中的總工資
select sum(sal) from emp where deptno=20;
求出所有雇員的平均工資
select avg(sal) from emp;
2) 分組統計
要想使用分組統計,則首先應該固定其文法,使用group by進行分組,此時SQL文法格式如下:
select *|具體的列
from 表名稱1
where 條件表達式
group by 分組條件
order by 排序字段 asc|desc
求出每個部門的雇員數量,這裡需要按照部門編号劃分,及按照deptno分組
select deptno,count(empno) from emp group by deptno;
求出每個部門的平均工資
select deptno,avg(sal)
from emp
group by deptno;
現在,我們觀察下面的一行代碼:
select deptno,count(empno) from emp;
以上代碼不能正确執行,報錯為:不是單組分組函數,為什麼呢?
如果程式中使用了分組函數,則有兩種可以使用的情況:
1-程式中存在了group by,并指定了分組條件,這樣可以将分組條件一起查詢出來。
2-如果不使用分組的話,則隻能單獨的使用分組函數
在使用分組函數的時候,不能出現分組函數和分組條件之外的字段。
看下面的代碼:
select deptno,empno,count(empno) from emp group by deptno;
程式會報錯,提示empno不是group by表達式,因為在這裡,我們使用了組函數count(empno),group by deptno,根據先前的規則,empno的出現是不合法的。
按照部門分組,并顯示部門的名稱,及每個部門的員工數
select d.dname,count(e.ename) from dept d,emp e where d.deptno=e.deptno group by d.dname;
要求顯示出平均工資大于2000的部門編号和平均工資
select deptno,avg(sal) from emp where avg(sal)&gt;2000 group by deptno;
程式報錯,提示avg(sal)&gt;2000處不允許使用分組函數。因為分組函數隻能在分組中使用,不允許出現在where語句之中,那麼如果現在假設要指定分組的條件,則隻能通過第二種條件的指令,having,此時SQL文法格式為:
select * | 具體的列名
from 表名稱
where 條件表達式
group by 分組條件
having 分組條件
order by 排序字段 asc|desc
是以,我們使用having完成上面的操作
select deptno,avg(sal) from emp group by deptno having avg(sal)&gt;2000;
下面我們看一個這樣的需求:顯示非銷售人員工作名稱以及從事同一工作的雇員的月工資的總和,并且要滿足從事同一工作的雇員的月工資合計大于5000,輸出結果按照月工資的合計升序排列
·-首先我們查詢出全部的非銷售人員,限定條件job&lt;&gt;'SALESMAN'
select * from emp where job&lt;&gt;'SALESMAN';
·-按照工作名稱分組,并且求出每組的工資總和
select job,sum(sal) from emp
where job&lt;&gt;'SALESMAN'
group by job;
·-對分組的調價進行限制,工資總和大于5000
select job,sum(sal) from emp
where job&lt;&gt;'SALESMAN'
group by job
having sum(sal)&gt;5000;
·-對查詢結果按照月工資的合計升序排列
select job,sum(sal) from emp
where job&lt;&gt;'SALESMAN'
group by job
having sum(sal)&gt;5000
order by sum(sal) asc;
下面我們總結下分組的簡單原則:
--隻要一列上存在重複的内容才有可能考慮到分組
使用分組時的注意點:
--分組函數可以嵌套使用,但是在組函數嵌套使用的時候不能再出現分組條件的查詢語句
例如,我們要求求出平均工資最高的部門工資
select deptno,max(avg(sal)) from emp
group by deptno;
程式會報錯,提示deptno不是單組分組函數
修改代碼如下:
select max(avg(sal)) from emp
group by deptno;
1.3、子查詢
子查詢:在一個查詢的内部還包括另外一個查詢,則此查詢稱為子查詢,子查詢的格式如下:
select * | 具體的列名稱
from 表名稱
where 條件表達式(
select * | 具體的列名稱
from 表名稱
where 條件表達式(
...
)
group by 分組條件
having 分組條件
order by 排序字段 asc|desc
)
group by 分組條件
having 分組條件
order by 排序字段 asc|desc
要求查詢出比7654工資要高的全部雇員資訊
·-首先要知道7654雇員的工資是多少
select sal from emp where empno=7654;
·-上面查詢的結果作為最後查詢的子查詢結果,隻要是其他的工資大于上面的查詢結果,則表示符合條件。
select * from emp where sal&gt;(select sal from emp where empno=7654);
應該要強調的是,所有的子查詢語句必須在“()”中編寫。
子查詢在操作上分為三類:
單列子查詢:傳回的結果是某列的一個内容,出現的幾率最高
單行子查詢:傳回多個列,有可能是一條完整的記錄
多行子查詢:傳回多條記錄
要求查詢出工資比7654高,同時與7788從事相同工作的全部雇員資訊
·-查詢出7654的工資
select sal from emp where empno=7654;
·-查詢出7788的工作名稱
select job from emp where empno=7788;
·-總和查找
select * from emp where sal&gt;(select sal from emp where empno=7654) and job=(select job from emp where empno=7788);
要求查詢出工資最低的雇員姓名,工作,工資
·-求出最低工資
select min(sal) from emp;
·-以最低工資為條件進一步查詢
select ename,job,sal from emp
where sal=(select min(sal) from emp);
要求查詢出:部門名稱,部門的員工數,部門的平均工資,部門的最低收入的雇員姓名,此時,程式需要兩張表關聯:dept、emp
·-如果要想求出每個部門的員工數,平均工資,要使用分組統計,這裡我們按照deptno進行分組
select deptno,count(empno),avg(sal) from emp
group by deptno;
·-但是我們要查詢的是部門的名稱,是以這裡需要與dept表進行關聯
select d.dname,ed.c,ed.a
from dept d,
(select deptno,count(empno) c,avg(sal) a from emp
group by deptno) ed
where d.deptno=ed.deptno;
·-求出最低收入的雇員姓名
select d.dname,ed.c,ed.a,e.ename
from dept d,(select deptno,count(empno) c,avg(sal) a,min(sal) min from emp
group by deptno) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
但是此程式中有一個問題,如果一個部門中同時存在兩個給你工資最低的雇員,則程式會出現錯誤。
在子查詢中,存在以下三種查詢的操作符号:
in、any、all
in操作符的作用是指定一個查詢的範圍
求出每個部門的最低工資的雇員資訊。
分析:每個部門的最低工資,傳回值肯定是多個,是以此時可以使用in指定一個操作範圍。
select * from emp
where sal in(select min(sal) from emp group by deptno);
any操作符的一般用法:=any(與in操作符的功能完全一樣)、&gt;any(比裡面最小的值要大)、&lt;any(比裡面最大的值要小)
select * from emp
where sal=any(select min(sal) from emp group by deptno);
all操作符的一般用法:&gt;all(比最大值要大)、&lt;all(比最小值要小)
select * from emp
where sal&gt;all(select min(sal) from emp group by deptno);
對于子查詢來講,還可以進行多列子查詢,一個子查詢中同時傳回多個查詢的列。
select * from emp
where (sal,nvl(comm,-1)) in(select sal,nvl(comm,-1) from emp where deptno=20);
1.4、資料庫更新操作
資料庫的主要操作分為兩種:
--資料庫的查詢操作:select
--資料庫的更新操作:insert、update、delete
此時,為了儲存原始的emp表的資訊,在進行增加、修改、删除操作之前,先将此表複制一份
create table myemp as select * from emp;
1) 添加資料
添加資料的文法是:
insert into 表名稱[(字段名1,字段名2,......)] values(值1,值2,......);
為myemp表添加一條新的記錄,按照标準的做法完成
insert into myemp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(7899,'張三','清潔工',7369,'14-2月 -1995',9000,300,40);
在添加資料時,需要強調的是:對于數字,不用加單引号,但是字元串必須加上單引号。可以使用簡略寫法,當我們想全部的阻斷插入資料時,可以不用指定需要插入資料的字段名,但是,我們并不推薦這種寫法,因為這樣寫的壞處在于,當我們向部分字段插入資料時,需要和表的字段順序一一對一個才能插入成功,而使用标準寫法時,隻需要指定的字段名和value中的值一一對應就可以完成插入操作。
插入部分資料,現在要求插入一個新的雇員,但是此雇員暫時沒有上司,也沒有獎金,也就是說,在插入資料的時候,mgr和comm字段的值要置空。
第一種做法:不明确寫出要插入的字段名 ,沒有資料的字段寫成null
insert into myemp values(8889,'王五','清潔工',null,'14-2月 -1982',9000,null,40);
第二種做法:明确寫出要插入的字段名
insert into myemp(empno,ename,job,hiredate,sal,deptno) values(8889,'王五','清潔工','14-2月 -1982',9000,40);
在上面的插入操作中,我們應該發現了這麼一個問題,插入的日期都是按照Oracle預設的日期格式進行書寫的,但是,現在有一個“2009-01-19”這樣格式的日期,該如何插入到資料庫表中呢?我們英愛還記得在前面學習單行函數的時候,介紹了一個叫做to_date()的函數,該函數的功能是将一個字元串類型的資料變為date類型的資料。
insert into myemp(empno,ename,job,hiredate,sal,deptno) values(8888,'趙六','保潔工',to_date('2009-01-19','yyyy-mm-dd'),9000,40);
2) 修改資料
在SQL文法中使用update語句就可以完成資料的修改功能,此語句的文法格式如下:
修改全部:update 表名稱 set 要修改的字段=新值,要修改的字段=新值,......;
修改局部:update 表名稱 set 要修改的字段=新值,要修改的字段=新值,...... where 修改條件;
但是,從一般的開發角度上講,我們都在修改資料時加上修改條件
現在将myemp表中的所有雇員的獎金修改為1000--&gt;修改全部
update myemp set comm=1000;
将編号為7899的雇員的工資修改為5000--&gt;指定了更新條件
update myemp set sal=5000 where empno=7899;
将編号為7899的雇員的上司取消
update myemp set mgr=null where empno=7899;
注意點:在進行資料庫更新的操作時,一定要寫上更新的條件,拒絕批量更新。
将7369、8899、7788的上司及獎金取消
update myemp set mgr=null,comm=null where empno in(7369,7788,8899);
3) 删除資料
在SQL文法中可以使用delete指令删除記錄,文法格式如下:
删除全部:delete from 表名稱;
删除局部:delete from 表名稱 where 删除條件;
删除編号是7899的雇員資訊
delete from myemp where empno=7899;
删除編号是8889,7889,8888的雇員資訊
delete from myemp where empno in(8889,7889,8888);
删除掉全部領取獎金的雇員
delete from myemp where comm is not null;
删除表的全部内容,此時不需要指定删除條件
delete from myemp;
在實際開發中不建議使用全部删除,在執行删除指令的時候都要指定删除條件。
1.5、事務處理
建立一個隻包含10部門雇員資訊的臨時表
create table emp10 as select * from emp where deptno=10;
删除emp10中7782的雇員資訊
delete from emp10 where empno=7782;
當我們再次查詢emp10表的資料時,該資料确實删除了,接下來,我們做如下操作,再次開啟一個sqlplus視窗,再次查詢emp10的資料,我們發現雇員編号為7782的雇員資訊仍然存在,這是為什麼?
這就是Oracle中事務處理的概念了。
事務處理:所謂事務處理就是保證資料的完整性,所有的操作要麼同時成功,要麼同時失敗。
在Oracle中對于每一個連接配接到資料庫的視窗(sqlplus、sqlplusw)連接配接之後實際上都會與資料庫建立一個session,即:每一個連接配接到資料庫上的使用者表示建立了一個session。
一個session對資料庫所做的修改,不會立刻反映到資料庫的真實資料之上,是允許復原的,當一個session送出所有的操作之後,資料庫才真正的做出了修改。
在資料庫的操作中提供了以下兩個主要指令完成事物的處理:
--送出事物:commit
--復原事物:rollback
如果資料已經被送出了則肯定無法復原,是以,復原隻有在事物未被送出時才有效。
在Oracle中關于事物的處理上夜壺存在一種死鎖的概念。
一個session如果更新了資料庫中的記錄,其他session是無法立刻更新的,要等待對方送出之後才允許更新。
下面我們來測試下Oracle的事務處理是如何進行的。
首先,我們在視窗1中查詢出emp10的資料
select * from emp10;
現在做一個更新的操作,将編号為7934的雇員的工資更改為3000
update emp10 set sal=3000 where empno=7934;
現在我們再次查詢emp10的資料,發現,編号為7934的雇員工資确實更改為3000來 ,但是我們應該知道,對于這個更新操作,我們是沒有送出的,我們現在再打開一個視窗,查詢emp10的資料,發現編号為7934的雇員工資還是1300,這就驗證了我們所說的“事物未送出”,接下來,我們在視窗2中進行一個更新操作,将7839的獎金設定為10000
update emp10 set comm=10000 where empno=7839;
下面我們在視窗1中送出事物
在視窗2中再次查詢emp10的資料,更新成功。
在視窗2中送出事物
同樣在視窗1中查詢emp10的資料,更新成功。
1.6、查詢練習
列出至少有一個員工的所有部門
select deptno ,count(empno) from emp
group by deptno;
此查詢使用了組函數,分組,注意,如果不加分組,該程式會報錯
列出部門人數大于1的所有部門編号
select deptno,count(empno) from emp
group by deptno having count(empno)&gt;1;
這裡沒使用where設定查詢限定條件,因為where子句中時不能出現函數的。
通過部門表,查詢出部門的資訊
select d.*,ed.cou from dept d,(select deptno,count(empno) cou from emp
group by deptno) ed
where d.deptno=ed.deptno;
列出工資比“SMITH”多的所有雇員。
--求出SMITH的工資
select sal from emp where ename='SMITH';
--将上面的結果作為查詢條件,隻要工資比上面的結果大的就是符合條件的
select * from emp where sal&gt;(select sal from emp where ename='SMITH');
列出所有員工的姓名和其直接上司的姓名
--此程式屬于自身關聯查詢,為了得到KING,我們使用左連接配接查詢,以等号左邊的表為标準
select e.ename,m.ename from emp e,emp m
where e.mgr=m.empno(+);
列出雇傭日期早于其直接上級的所有雇員的編号、姓名和部門名稱
--自身關聯,查找mgr=empno的同時還要比較hiredate,我們先查詢編号和姓名
select e.empno,e.ename
from emp e,emp m
where e.mgr=m.empno and e.hiredate&lt;m.hiredate;
--如果要加入部門名稱,我們需要加入dept表,做表關聯查詢
select e.empno,e.ename,d.dname
from emp e,emp m,dept d
where e.mgr=m.empno and e.hiredate&lt;m.hiredate and e.deptno=d.deptno;
列出部門名稱和這些部門的雇員資訊,同時列出那些沒有雇員的部門
--左右關聯問題,以=右邊的表為标準
select d.deptno,d.dname,e.empno,e.ename
from dept d,emp e
where d.deptno=e.deptno(+);
列出所有“CLERK”的姓名和其部門名稱,部門的人數
--找出所有CLERK的姓名和部門編号
select ename,deptno from emp
where job='CLERK';
--要想查詢部門名稱,則必須使用dept表
select e.ename,d.dname from emp e,dept d
where job='CLERK' and e.deptno=d.deptno;
--部門人數要用到分組完成,一旦使用分組,肯定是group by
select e.ename,d.dname,ed.cou
from emp e,dept d,(select deptno, count(empno) cou from emp group by deptno) ed
where job='CLERK' and e.deptno=d.deptno and ed.deptno=e.deptno;
列出最低工資大于1500的各種工作以及從事此工作的全部雇員人數
--按工作分組,分組條件是最低工資大于1500
select job,min(sal) from emp
group by job having min(sal)&gt;1500;
--工作就出來了,之後再求全部的雇傭人數
select e.job,count(e.empno)
from emp e
where e.job in(
select job from emp
group by job having min(sal)&gt;1500
)
group by e.job;
列出在部門“SALES”工作的員工姓名,假定不知道銷售部的部門編号
--通過dept表查詢出銷售部的部門編号
select deptno from dept where dname='SALES';
--将上面的查詢結果作為下一步查詢的條件
select ename from emp
where deptno=(
select deptno from dept where dname='SALES'
);
列出工資高于公司平均工資的所願雇員,所在部門,上級上司,公司的工資等級
--求出公司的平均工資
select avg(sal) from emp;
--列出工資高于平均工資的雇員資訊
select * from emp where sal&gt;(select avg(sal) from emp);
--與部門表關聯,查出所在部門的資訊
select e.*,d.dname,d.loc from emp e,dept d
where sal&gt;(select avg(sal) from emp) and e.deptno=d.deptno;
--要想查出上級上司,需要和自身進行關聯查詢
select e.empno,e.ename,m.ename,m.empno,d.deptno,d.dname,d.loc
from emp e,dept d,emp m
where e.sal&gt;(select avg(sal) from emp)
and e.deptno=d.deptno
and e.mgr=m.empno(+);
--與工資等級表關聯,查出工資等級
select e.empno,e.ename,s.grade,m.ename,m.empno,d.deptno,d.dname,d.loc
from emp e,dept d,emp m,salgrade s
where e.sal&gt;(select avg(sal) from emp)
and e.deptno=d.deptno
and e.mgr=m.empno(+)
and e.sal between s.losal and s.hisal;
列出與scott從事相同工作的所有雇員及部門名稱
--找到scott的工作
select job from emp where ename='SCOTT';
--找到和上面查詢工作相同的雇員
select * from emp where job=(select job from emp where ename='SCOTT');
--使用dept表查詢出所在部門名稱
select e.*,d.dname from emp e,dept d
where job=(select job from emp where ename='SCOTT')
and ename!='SCOTT'
and d.deptno=e.deptno;
列出工資等于部門30中雇員的工資的所有雇員姓名和工資
--查出部門30中雇員的工資
select sal from emp where deptno=30;
--找出工資等于上面結果的雇員姓名
select ename,sal from emp
where sal in(select sal from emp where deptno=30)
and deptno!=30;
列出工資高于在30部門工作的所有雇員的工資的雇員姓名和工資,部門名稱
--在之前的程式上進行修改,使用&gt;all,比最大的還要大
select ename,sal
from emp where sal&gt;all(
select sal from emp where deptno=30
)
and deptno!=30;
--使用dept表,查詢出部門名稱
select e.ename,e.sal,d.dname from emp e,dept d
where sal&gt;all(
select sal from emp where deptno=30
)
and e.deptno!=30
and e.deptno=d.deptno;
列出在每個部門工作的雇員數量,平均工資和平均工齡
--求出每個部門的雇員數量,按照部門名稱分組
select d.dname,count(e.empno)
from emp e,dept d
where e.deptno=d.deptno
group by d.dname;
--求出每個部門的平均工資和工齡
select d.dname,count(e.empno),avg(e.sal),avg(months_between(sysdate,hiredate)/12) 年
from emp e,dept d
where e.deptno=d.deptno
group by d.dname;
列出所有雇員的姓名、部門名稱和工資
--直接兩張表關聯
select e.ename,e.sal,d.dname
from emp e,dept d
where e.deptno=d.deptno;
列出所有部門的詳細資訊和部門的人數
--列出每個部門的雇員人數
select deptno,count(empno) cou
from emp
group by deptno;
--把以上的查詢作為一張臨時表
select d.*,ed.cou from dept d,
(select deptno dto,count(empno) cou from emp group by deptno ) ed
where d.deptno=ed.dto;
查詢結果中沒包含40部門,修改如下
select d.*,nvl(ed.cou,0) from dept d,
(select deptno dto,count(empno) cou from emp group by deptno ) ed
where d.deptno=ed.dto(+);
列出各種工作的最低工資及從事此工作的雇員姓名
--按照工作分組,使用min()求出最低工資
select job,min(sal) from emp group by job;
--按照工資查詢出雇員的資訊
select * from emp
where sal in(select min(sal) from emp group by job);
列出各個部門的MANAGER的最低工資
select deptno,min(sal)
from emp
where job='MANAGER'
group by deptno;
列出所有雇員的年薪,按照年薪從低到高排序
select ename,(sal+nvl(comm,0))*12 yearsal from emp order by yearsal asc;
查詢某個雇員的上級主管,并求出這些主管中的薪水超過3000的
select distinct m.* from emp e,emp m
where e.mgr=m.empno and m.sal&gt;3000;
求出部門名稱中帶“S”的部門雇員的工資合計和部門人數
--查詢部門表的部門名稱,使用模糊查詢,來确定部門的編号
select deptno from dept where dname like '%S%';
--查詢出符合上述條件的雇員工資合計和部門人數
select deptno,sum(sal),count(empno) from emp
where deptno in(select deptno from dept where dname like '%S%')
group by deptno;
第四次
1、Oracle
1.1、 建立和管理表
1) 常用的資料類型
varchar\varchar2--&gt;表示的是一個字元串,有長度限制,255,
number--&gt;number(n):表示一個整數,數字的長度是n,可以使用int
number(m,n):表示一個小數,數字小數長度為n,整數長度為m-n,可以使用float
date--&gt;表示日期的類型,日期要按照标準的日期格式進行存放
clob--&gt;大對象,表示大文本資料,一般可以存放4G的文本
blob--&gt;大對象,表示二進制資料,最大可以存放4G,如:電影,歌曲,圖檔
2) 表的建立
表的建立還是按照标準的文法進行,但是在表的建立時有時候會指定限制,那麼此處先給出一個建立表的簡單文法。
create table 表名稱(
字段名稱1 字段類型 [default 預設值],
字段名稱2 字段類型 [default 預設值],
....
字段名稱n 字段類型 [default 預設值]
)
在前面我們使用了一種這樣的文法來建立表:
create table 表名稱 as (子查詢)--将子查詢的結果作為一張表
如果現在子查詢寫的是:select * from emp;表示将表結構和表的内容一起複制
如果現在子查詢寫的是:select * from emp where 1=2;加入了一個永遠都不會成立的條件,則此時表示我們複制的隻是表的結構,不複制表的内容
複制表結構:
create table temp as(select * from emp where 1=2);
3) 表的删除
表的删除文法如下:
drop table 表名稱;
4) 表的修改
在SQL文法操作中,提供了alter指令,通過alter指令就可以增加新的列
為emp表添加一個address列
alter table emp add(address varchar2(200) default'暫無位址');
修改emp表中的ename,将長度改為50
alter table emp modify(ename varchar2(50));
5) 為表重命名
在Oracle中提供了rename指令,可以為表重新進行命名,但是此語句隻能在Oracle中使用。文法格式如下:
rename 舊的表名稱 to 新的表名稱;
6) 截斷表
如果現在我們需要清空一張表的資料,但是同時不需要復原,可以立刻釋放資源就需要使用截斷表的文法:
truncate table 表名稱;
思考下面的問題:現在有一張國家表,裡面隻有一個國家名稱的字段,内容如下:“中國、美國、巴西、荷蘭“,現在要求通過查詢實作對戰功能:
中國-&gt;美國
中國-&gt;巴西
中國-&gt;荷蘭
美國-&gt;中國
美國-&gt;巴西
美國-&gt;荷蘭
......
分析:本程式隻能使用笛卡爾積完成
首先,建立一張表
create table national(
name varchar2(30)
)
向表中增加測試資料
insert into national(name) values('中國');
insert into national(name) values('美國');
insert into national(name) values('巴西');
insert into national(name) values('荷蘭');
查詢的時候表自己和自己關聯
select n1.name,n2.name from national n1,national n2 where n1.name&lt;&gt;n2.name;
1.2、限制
在資料庫表的開發中,餘數是必不可少的支援。使用限制可以更好的保證資料庫中的資料完整性。
資料庫中的限制分類:
--在實際中,限制主要分為以下五種:
···主鍵限制primary key:主鍵表示是一個唯一的辨別,本身是不能為空的
|-例如:身份證号是唯一的,不可重複,不可為空
···唯一限制unique:在一個表中隻允許建立一個主鍵限制,而其他列如果不希望出現重複值的話,則可以使用唯一限制。
···檢查限制:檢查一個列的内容是否合法
|-例如:年齡。隻能在0~150之間
|-例如:性别,隻能是男、女、中性
···非空限制:姓名這樣的字段裡面的内容就不能為空
···外鍵限制:在兩張表中進行限制操作。
1) 主鍵限制(primary key)
主鍵限制一般都是使用在id上,而且本身已經預設了内容不能為空,主鍵限制可以再建表的時候指定
現在我們建立一張person表,在pid上增加主鍵限制
drop table person;
create table person(
pid varchar2(18) primary key,
name varchar2(200),
age number(3),
birthday date,
sex varchar2(3) default '男'
)
現在我們向表中插入資料
insert into person(pid,name,age,birthday,sex) values('1111111111111111','張三',30,to_date('1976-08-09','yyyy-mm-dd'),'女');
insert into person(pid,name,age,birthday,sex) values('1111111111111111','李四',30,to_date('1976-08-04','yyyy-mm-dd'),'男');
當插入第二條語句時,會提示:違反唯一限制,那麼我們将pid的值設定為null
insert into person(pid,name,age,birthday,sex) values(null,'李四',30,to_date('1976-08-04','yyyy-mm-dd'),'男');
同樣會提示錯誤:無法将 NULL 插入 ("SCOTT"."PERSON"."PID"),以上的限制是系統自動配置設定好的限制名稱,也可以通過constraint指定一個限制的名字,
将person表的pid指定名稱
drop table person;
create table person(
pid varchar2(18),
name varchar2(200),
age number(3),
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
2) 非空限制(not null)
使用非空限制,表示一個字段的内容不允許為空,即:插入資料的時候必須插入内容
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
3) 唯一限制(unique)
表示一個字段中的内容是唯一的,其他列不允許重複。
假設:現在姓名不允許出現重名的情況
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) unique not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
4) 檢查限制(check)
使用檢查限制來判斷一個列中插入的内容是否合法,例如,年齡的取值範圍,性别的取值範圍
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) unique not null,
age number(3) not null check(age between 0 and 150),
birthday date,
sex varchar2(3) default '男' check(sex in('男','女','中')),
constraint person_pid_pk primary key(pid)
)
5) 主-外鍵限制(foreign key)
之前的限制都是針對一張表的,那麼主-外鍵限制是針對兩張表的限制。為什麼需要主-外鍵限制呢?
要求完成一個程式,一本書隻屬于一個人
書本身應該是一張表,一本書中必然有一個字段表示屬于某個人的
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18)
);
insert into person(pid,name,age,birthday,sex) values('1111111111111111','張三',30,to_date('1976-08-09','yyyy-mm-dd'),'女');
insert into book(bid,bname,bprice,pid) values(1,'JAVA SE',89.9,'0000000000000');
在插入第二條資料前,我們看看pid字段的值,很明顯,在我們的person表中不存在這樣的person,那麼, 這樣的資料時不應該插入到資料庫中的,為了解決這樣的問題,我們使用主-外鍵關聯,關聯之後字表的資料要跟随父表的資料内内容。
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18),
constraint person_book_pid_fk foreign key(pid) references person(pid)
);
現在我們再次執行資料的插入操作,此時系統提示:違反完整限制條件 (SCOTT.PERSON_BOOK_PID_FK) - 未找到父項關鍵字,根據上面的分析沒我們修改如下:
insert into book(bid,bname,bprice,pid) values(1,'JAVA SE',89.9,'1111111111111111');
此時插入資料成功。
在使用主-外鍵關聯的時候有幾點需要注意:
|-在子表中設定的外鍵在父表中必須是主鍵
|-删除時應該先删除子表,再删除父表
在主-外鍵關聯中也可以使用級聯删除
以現有資料庫中的資料為例
delete from person where pid='1111111111111111';
要删除person表中編号為1111111111111111的人員,但是這個人在book表中存在一本書的記錄。提示錯誤:違反完整限制條件 (SCOTT.PERSON_BOOK_PID_FK) - 已找到子記錄,那麼,如果想删除成功必須先删除book表中pid對應的記錄,再删除此人的資訊
如果我們希望一個表中的資料在删除時,可以自動删除掉其對應的子表記錄,則可以使用級聯删除來實作。
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18),
constraint person_book_pid_fk foreign key(pid) references person(pid) on delete cascade
);
6) 修改限制
如果一張表已經建立完成,則可以為其添加限制
關于限制類型的命名,一定要統一:
--primary key--&gt;主鍵字段_pk
--unique--&gt;字段_uk
--check--&gt;字段_ck
--foreign key--&gt;父字段_子字段_fk
為person添加一個限制
alter table person add constraint person_pid_pk primary key(pid);
将person的主鍵限制删除掉該怎麼操作呢?
alter table person drop constraint person_pid_pk;
1.3、rownum
rownum:表示行号,實際上這是一個列的列名,但是這個列我們稱為僞列,此列尅在每張表中出現。
例如,在我們查詢雇員表的時候,加上rownum這個列名稱
select rownum,empno,ename,job,sal,hiredate from emp;
從執行的效果來看,rownum本身采用自動編号的形式出現。
我們擴充下rownum的應用,現在我們隻想顯示前5條雇員資訊,該如何實作呢?
select rownum,empno,ename,job,sal,hiredate from emp where rownum&lt;=5;
既然可以查詢前5條資料,那麼,我們現在要求提高了,查詢中間的5條資料
select rownum,empno,ename,job,sal,hiredate from emp where rownum between 5 and 10;
看似沒有問題的語句卻查不出資料來,到底哪裡出錯了呢?
如果現在要想進行中間的截取操作,則隻能采用子查詢,例如現在假設每頁顯示5條,第二頁應該顯示6~10條,那麼對于資料庫操作來講,它在查詢的時候應該首先查詢出1~10條,之後再在查詢的結果中截取出後5條。
select * from (select rownum m,empno,ename,job,sal,hiredate from emp where rownum&lt;=10) temp where temp.m&gt;5;
如果現在要求輸出最後的4條呢?
select * from (select rownum m,empno,ename,job,sal,hiredate from emp where rownum&lt;=15) temp where temp.m&gt;10;
1.4、集合操作
在Oracle中提供了三種類型集合的操作,并(union)、交(intersect)、差(minus)
|-union:将多個查詢的結果組合到一個查詢結果中,沒有重複的内容
|-union all:将多個查詢結果組合到一個查詢之中,但是包含了重複值
|-intersect:傳回多個查詢結果中相同的部分
|-minus:傳回兩個查詢結果的差集
為了更好的觀察查詢結果,我們将複制emp表,将20部門的雇員資訊取出來
create table emp20 as select * from emp where deptno=20;
1) 驗證union
傳回兩個集合的所有内容,不包含重負的内容
select * from emp
union
select * from emp20;
2) 驗證union all
傳回兩個集合的所有内容,包含重複内容
select * from emp
union all
select * from emp20;
3) 驗證intersect
傳回多個查詢結果中相同的部分
select * from emp
intersect
select * from emp20;
因為兩張表中隻有20部門的雇員資訊是重複的,所有實際上傳回的相同内容就是表emp20的内容
4) 驗證minus
傳回兩個查詢結果的差集
select * from emp
minus
select * from emp20;
1.5、交表、限制、查詢綜合練習
題目背景:
有某個學生運動會比賽資訊的資料庫,儲存了如下的表:
|-運動員sporter(運動員編号sporterid,運動員姓名name,運動員性别sex,所屬系号department)
|-項目item(項目編号itemid,項目名稱itemname,項目比賽地點location)
|-成績grade(運動員編号sporterid,項目編号itemid,積分mark)
功能要求
1) 建表
--定義各個表的主碼外碼限制
--運動員的姓名和所屬系别不能為空值
--積分要麼為空值,要麼為6、4、2、0,分别代表第一、第二、第三和其他名次的積分
create table sporter(
sporterid number(4) primary key not null,
name varchar2(50) not null,
sex varchar2(3) not null,
department varchar2(30) not null,
constraint sporter_sex_ck check(sex in('男','女'))
);
create table item(
itemid varchar2(4) primary key not null,
itemname varchar2(50) not null,
location varchar2(50) not null
);
create table grade(
sporterid number(4),
itemid varchar2(4),
mark number(2),
constraint sporter_grade_sporterid_fk foreign key(sporterid) references sporter(sporterid) on delete cascade,
constraint sporter_item_itemid_fk foreign key(itemid) references item(itemid) on delete cascade,
constraint grade_mark_ck check(mark in(6,4,2,0))
);
2) 資料
運動員sporter
insert into sporter(sporterid,name,sex,department) values(1001,'李明','男','計算機系');
insert into sporter(sporterid,name,sex,department) values(1002,'張三','男','數學系');
insert into sporter(sporterid,name,sex,department) values(1003,'李四','男','計算機系');
insert into sporter(sporterid,name,sex,department) values(1004,'王二','男','實體系');
insert into sporter(sporterid,name,sex,department) values(1005,'李娜','女','心理系');
insert into sporter(sporterid,name,sex,department) values(1006,'孫俪','女','數學系');
項目item
insert into item(itemid,itemname,location) values('x001','男子五千米','一操場');
insert into item(itemid,itemname,location) values('x002','男子标槍','一操場');
insert into item(itemid,itemname,location) values('x003','男子跳遠','二操場');
insert into item(itemid,itemname,location) values('x004','女子跳高','二操場');
insert into item(itemid,itemname,location) values('x005','女子三千米','三操場');
積分grade
insert into grade(sporterid,itemid,mark) values(1001,'x001',6);
insert into grade(sporterid,itemid,mark) values(1002,'x001',4);
insert into grade(sporterid,itemid,mark) values(1003,'x001',2);
insert into grade(sporterid,itemid,mark) values(1004,'x001',0);
insert into grade(sporterid,itemid,mark) values(1001,'x003',4);
insert into grade(sporterid,itemid,mark) values(1002,'x003',6);
insert into grade(sporterid,itemid,mark) values(1004,'x003',2);
insert into grade(sporterid,itemid,mark) values(1005,'x004',6);
insert into grade(sporterid,itemid,mark) values(1006,'x004',4);
3) 要求
求出目前總積分最高的系名,及其積分
--所有的系名都在sporter表中,而積分在grade表中,是以sporter和grade進行關聯查詢
select s.department,sum(g.mark) sum
from sporter s,grade g
where s.sporterid=g.sporterid
group by s.department
order by sum desc;
--使用rownum最友善
select * from(
select s.department,sum(g.mark) sum
from sporter s,grade g
where s.sporterid=g.sporterid
group by s.department
order by sum desc)
where rownum=1;
第五次
1、Oracle資料庫
1.1、視圖
視圖的功能:一個視圖實際上就是封裝了一條複雜的查詢語句
建立視圖的文法如下:
create view 視圖名稱 as 子查詢
|-實際上此時的子查詢就表示一條非常複雜的查詢語句
建立一個視圖:此視圖包含了全部的20部門的雇員資訊(雇員編号,姓名,工作,雇傭日期)
create view empv20 as select empno,ename,job,hiredate from emp where deptno=20;
視圖建立完成之後,就可以像查找表那樣直接對視圖進行查詢的操作了。
select * from empv20;
此時,我們通過視圖查詢出20部門的雇員資訊,也就是,可以使用視圖包裝的查詢語句完成我們的操作。但是,我們思考下,現在這個視圖中同樣隻包含了4個字段的資訊,如果,現在希望多包含一個字段呢?
create view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
此時,系統會報錯,名稱已有現有對象使用。也就是說,該名稱的視圖已經存在了,是以,在建立視圖的時候是不允許重名的,那麼,我們隻能先删除掉這個視圖然後進行新視圖的建立。該如何删除視圖呢?
drop view 視圖名稱;
是以,類似于删除表的操作,我們将上面建立的視圖empv20删除
drop view empv20;
删除成功後,重新執行建立視圖的語句
create view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
但是,我們應該發現,如果所有的代碼都這樣去寫肯定很麻煩,因為如果要想對視圖進行修改操作,則肯定先要删除掉視圖,再進行新視圖的建立才能達到目的,是以在Oracle中為了友善使用者修改視圖,提供了一種替換的指令,此時完整的視圖建立文法如下:
create or replace 視圖名稱 as 子查詢;
按照上面的文法格式,我們在更改視圖的時候就不需要先執行删除操作了,系統會為使用者自動進行删除及重建的功能。
create or replace view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
此時,系統不會提示任何錯誤,表示該視圖删除及建立成功。
我們說視圖實際上是封裝了一個非常複雜的查詢語句。下面我們使用視圖來封裝一個非常複雜的查詢。此查詢傳回部門名稱、部門人數、平均工資以及最低工資的雇員姓名。首先看看以前的寫法
select d.dname,ed.c,ed.a,e.ename
from dept d,
(
select count(empno) c,deptno,avg(sal) a,min(sal) min from emp e
group by deptno
) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
如果在開發中每次都寫如此之長的SQL語句,則肯定很不友善,是以此時就可以通過建立師視圖簡化操作,友善使用者做查詢。
create or replace view myempv as
select d.dname,ed.c,ed.a,e.ename
from dept d,
(
select count(empno) c,deptno,avg(sal) a,min(sal) min from emp e
group by deptno
) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
在以後的操作中隻需要查詢該視圖就可以得到結果,而不需要再次執行那麼長的SQL語句。
建立一個隻包含20部門的雇員視圖
create or replace view mepv20
as
select * from emp where deptno=20;
視圖建立成功。下面進行視圖的更新操作,我們應該記住,在視圖中是不應該包含真實資料的,而且在此程式中,建立的視圖實際上是存在建立條件的,此條件是deptno=20.如果現在将視圖中的7369的部門編号修改為30呢?
update empv20 set deptno=30 where empno=7369;
更新成功,現在我們查詢該視圖,
select * from mepv20;
發現在視圖中已經沒有7369這個雇員了。那麼,在我們的原始表emp中呢?
select * from emp;
發現在emp表中的編号為7369的雇員的部門編号已經修改為30,我們思考下,這樣的更新操作合适嗎?很明顯,是不合适的,我們在建立視圖的時候是有條件的,一旦修改之後,該條件被破壞。是以在建立視圖的時候SQL中提供了兩個很重要的參數:
|-with check option:不能更新視圖的建立條件
下面我們在視圖建立中使用此參數
create or replace view empv20
as
select * from emp where deptno=20
with check option;
我們再對建立的視圖進行更新操作
update mepv20 set deptno=30 where empno=7566;
此時,系統報錯,提示:視圖 with check option where 子句違規
很明顯,建立條件不能更新,那麼其他字段呢,例如:現在将7566的雇員姓名修改為“約翰”
update empv20 set ename='約翰' where empno=7566;
更新成功,也就是說在使用了上述的with限制後,在更新視圖時,除了建立條件不能更新其他字段均可以更新。
但是,我們說視圖本身的作用還是用來查詢的,是以不應該允許修改,是以此時可以使用第二個參數:
|-with read only:建立的視圖隻讀,即隻能讀取操作
建立隻讀視圖
create or replace view empv20
as
select * from emp where deptno=20
with read only;
再次執行更新操作,更新雇員的姓名
update empv20 set ename='約翰' where empno=7566;
提示錯誤:無法對隻讀視圖進行DML操作。
1.2、序列
在很多資料庫系統中都存在一個自動增長的列,如果現在要想在Oracle中完成自動增長的功能,則隻能依靠序列完成,所有的自動增長操作,需要使用者手工完成處理。
序列的建立格式:
create sequence sequence
[increment by n][start with n]
[{maxvalue n | nomaxvalue}]
[{minvalue n | nominvalue}]
[cycle | nocycle]
[{cache n | nocache}];
建立一個myseq的序列,驗證自動增長的操作
create sequence myseq;
序列建立完成之後,所有的自動增長應該由使用者自己處理,在序列中提供了以下兩種操作:
|-nextVal:取得序列的下一個内容
|-currVal:取得序列的目前内容
現在我們先建立一張用于驗證序列的表
create table testseq(
next number,
curr number
);
下面向表中添加資料,添加資料的時候需要手工使用序列
使用序列插入資料
insert into testseq(next,curr) values(myseq.nextval,myseq.currval);
将以上的插入語句執行5次
我們查詢下testseq表,看看序列的變化
select * from testseq;
從查詢結果中我們發現,nextval的内容始終在進行自動增長的操作,而curr使用取出目前操作的序列結果,也就是說,現在的這種序列,每次增長的幅度是1,那麼也可以修改序列的增長幅度。
可以使用以下的一個參數:
|-每次增長長度:increment by 長度
重建立立序列
drop sequence myseq;
create sequence myseq increment by 2;
此時,序列已經正常的建立,建立之後來測試下,序列的操作,重新建立testseq表
drop table testseq;
create table testseq(
next number,
curr number
);
重新進行資料的插入操作,插入5次
insert into testseq(next,curr) values(myseq.nextval,myseq.currval);
再次查詢testseq表,觀察序列的變化
select * from testseq;
從序列的結果來看,每次取得都是奇數。
預設情況下,序列從1開始的,那麼可以使用start with來指定其開始的位置
drop sequence myseq;
create sequence myseq increment by 2 start with 10;
這裡指定序列開始點為10,以後直接從10開始進行序列的計算。
下面我們重新建立下該序列,讓其取值固定在1、3、5、7、9,并循環序列
drop sequence myseq;
create sequence myseq
maxvalue 10
increment by 2 start with 1
cache 2 cycle;
重建立立testseq表,插入資料,測試最終的結果,可以發現序列的内容是循環出現的,但是我們說在實踐中,序列使用最多的文法是:create sequence 序列名稱。其他選項使用預設值。
1.3、同義詞
在前面我們使用過這樣的查詢語句:
select sysdate from dual;
我們知道dual是一張虛拟表,那麼雖然是虛拟表,可是此表到底是在哪裡定義的呢?
通過測試,我們發現在sys賬戶下存在dual表。現在問題出現了,既然dual表是sys賬戶下的,那麼根據我們前面的知識,如果想要在scott使用者中使用dual表時,正确的做法是:
select sysdate from sys.dual;
但是我們在scott賬戶下是這樣寫的
select sysdate from dual;
這是為什麼呢?此時,實際上就是同義詞的作用。什麼是同義詞?同義詞可以讓其他使用者通過一個名稱友善的通路”使用者名.表名稱“。
建立同義詞的文法:
create synonym 同義詞名稱 for 使用者名.表名稱;
下面我們将scott表的emp定義emp的同義詞:
create sysnonym emp for scott.emp;
如果要删除一個同義詞,可以使用如下的文法格式:
drop sysnonym 同義詞名稱;
是以,删除上面建立的同義詞:
drop sysnonym emp;
但是,此種特性隻适用于Oracle資料庫。
1.4、使用者管理
在Oracle中可以對使用者進行建立和授權的操作。
建立使用者的文法是:
create user 使用者名 identified by 密碼;
假設現在要建立一個test使用者,密碼為123
create user test identified by 123;
建立使用者成功過後,是否可以登入呢?顯然是不行的,在登入請安必須為新建立的使用者授予相關的權限才能執行相應的操作。
為使用者授權的格式如下:
grant 權限1,權限2,...... to 使用者名;
是以,為了新建立的使用者test能夠連接配接資料庫,我們需要為它授權
grant create session to test;
之後我們就能使用test正常登陸了。
那麼,我們開始常見一張表吧。
可是,我們發現,系統又提示權限不足。很明顯的知道,目前使用者test沒有建立表的權限,既然如此,我們就為它授予建立表的權限。在此之前,我們給出一個這樣的結論:對于一個新建立的使用者,所有的權限均要分别賦予,該使用者才能進行相應的操作。如果現在假設要想把多個權限一次性賦予一個使用者,則可以講這些權限先定義成一組角色的集合。
在Oracle中提供了兩個主要角色:connect、resource,可以直接把這啷個角色賦予test使用者。
grant connect,resource to test;
突然,test使用者密碼忘記了,那麼如何修改一個使用者的密碼呢?當然該操作隻有超級管理者才有權限
alter user 使用者名 identified by 密碼;
将test的使用者密碼修改為hello
alter user test identified by hello;
在一般的系統中存在這樣的情況,在使用者第一次登陸的時候可以修改密碼,是以要想完成此功能,可以手工讓一個密碼失效,格式如下:
alter user 使用者名 password expire;
現在我們可以設定test的目前密碼失效
alter user test password expire;
如果系統中某個使用者需要被鎖住,該如何操作呢?
alter user 使用者名 account lock;
現在由于某些原因,我們需要将test使用者鎖住
alter user test account lock;
那麼,test使用者就不能連接配接資料庫了。
如果要解鎖test呢?
alter user 使用者名 account unlock;
好了,現在我們解鎖test
alter user test account unlock;
那麼,test使用者就能正常連接配接資料庫了。
現在我們需要使用test使用者來通路scott使用者下的emp表
select * from scott.emp;
按照前面的知識,該查詢時沒有問題的,但是系統提示錯誤說:scott.emp表不存在。怎麼回事?
再想想前面的一句話,”我們需要為新建立的使用者分别授予相應的權限來執行相應的操作“,很明顯,test沒有通路其他使用者下表的權限,是以這麼操作
grant select,delete on scott.emp to test;
我們将查詢和删除emp表的權限授予給test使用者
既然可以授予權限,那麼也可以回收權限,回收權限使用revoke文法。,文法格式如下:
revoke 權限名 on 使用者表名稱 from 使用者;
如果我們不希望test使用者查詢和删除scott的emp表,
revoke select,delete on scott.emp from test;
1.5、資料庫的備份和恢複
資料庫在運作的期間都是需要不斷的進行備份的,萬一假設系統崩潰了,可以從備份中恢複資料。
Oracle在安裝完成之後可以使用兩個命名進行資料庫的備份和恢複:
|-資料庫備份:exp
|-資料庫恢複:imp
1.6、嵌套表
嵌套表:在一個表中還包含另外一個子表
例如:現在有一種情況,一個部門可能承接多個項目,如果此時,按照最原始的方法設計,那麼定義兩張表,department表,project表
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null
);
create table project(
proid number(4) primary key not null,
proname varchar2(50) not null,
deptno number(2),
constraint department_project_deptno foreign key(deptno) references department(deptno) on delete cascade
);
這是我們最常見的思路,而且本身也屬于一個正确的做法,但是在Oracle中引入了嵌套表的概念,可以直接将項目表的類型作為一個department表的字段類型,達到嵌套的目的。
但是,要想完成一個嵌套表的制作,則首先要保證一點:因為資料庫在建立資料表的時候都要指定字段的類型,是以嵌套表本身也需要同樣指定類型,那麼這種類型就需要單獨的定義:
create type project_ty as object(
proid number(4),
proname varchar2(50),
prodate date
);
/
類型建立成功之後,并不意味着此類型可以直接使用,因為此類型是一個完整的類型,是以要為此類型指定一個名稱
create type project_nt as table of project_ty;
/
以上的操作表示以後直接使用project_nt表示project_ty類型,就類似于varchar2表示字元串是一樣的,此時可以使用此類型建立department表
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null,
projects project_nt
)nested table projects store as project_nt_tab_temp;
對于插入語句來講,需要指定每個project_ty的類型
insert into department(deptno,dname,projects)
values(
1,'技術部',
project_nt(
project_ty(1001,'ERP',sysdate),
project_ty(1002,'CRM',sysdate),
project_ty(1003,'OA',sysdate)
)
);
此時,查詢嵌套表,可以傳回多個項目
select * from department;
如果這個時候,我們需要檢視一個部門的全部項目的話,則需要查詢嵌套表
select * from table
(select projects from department where deptno=1);
如果現在我們需要更新項目編号為1001的項目名稱,将此項目名稱更新為“測試項目”
update table (select projects from department where deptno=1) pro
set value(pro)=project_ty(1001,'測試項目',to_date('1998-09-21','yyyy-mm-dd')) where pro.proid=1001;
1.7、可變數組
可變數組屬于嵌套表的更新版,在可變數組中,實際上就是将内部的嵌套表的内容的長度進行了限制。
例如,一個部門有多個勞工,如果按照可變數組的做法,肯定首先要做出一個勞工的類型。
create type worker_info as object(
id number(4),
name varchar2(50),
sex varchar2(6)
);
/
下面再定義數組類型
create type worker_info_list as varray(10) of worker_info;
/
定義部門表,一個部門中可能存在多個勞工
drop table department;
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null,
workers worker_info_list
);
插入測試資料
insert into department(deptno,dname,workers)
values(20,'後勤部',
worker_info_list(
worker_info(1,'張三','男'),
worker_info(2,'李四','男'),
worker_info(3,'王五','男')
)
);
查詢全部
select * from department;
除了以上的所有内容之外,對于資料庫的開發中,像過程之類的基本不用了,因為現在的很多地方都使用程式完成功能。
而且,對于進階開發部分:遊标、觸發器、包、函數。基本上很少去直接調用。
1.8、資料庫設計範式
資料庫設計範式實際上非常的重要,但是從實際的開發來看,如果真的全部按照範式去做,則這個程式沒法寫,包括查詢語句也會變得複雜。
在Oracle中的scott使用者的全部表,實際上就已經很好的展現了一張設計思路,雇員-部門的關系。
1) 第一範式
例如,現在假設有如下的資料庫建立腳本
create table person(
pid number(4) primary key not null,
name varchar2(50),
info varchar(200)
);
插入以下測試資料
insert into person(pid,name,info) values(1111,'張三','1983年11月23日出生,現在的住址是:北京市西城區。。。。。');
實際上對于人員來看,由以下幾部分組成:
|-生日:1983年1月23日
|-省市:北京
|-地區:西城區
|-詳細的資訊:。。。。。
每個字段不可再分,是以,以上的資料庫建立腳本修改如下:
create table person(
pid number(4) primary key not null,
name varchar2(50),
birthday date,
area varchar2(200),
subarea varchar2(200),
address varchar2(200)
);
這種設計看上去每個字段是不可再分的,但是我們應該會注意到,在一些網站的注冊中,會要求使用者分别輸入“姓”和“名”,是以,可将上面的設計修改如下:
create table person(
pid number(4) primary key not null,
姓 varchar2(50),
名 varchar2(50),
birthday date,
area varchar2(200),
subarea varchar2(200),
address varchar2(200)
);
是以,在設計表字段的時候,最好保證每個字段均不能再分。
2) 第二範式
第一範式的要求非常簡單,保證每個字段有意義。但是如果所有的操作都使用第一範式,那麼會存在問題:
現在建立一張學生選課表:學号、姓名、年齡、課程名稱、成績、學分
create table selectcourse(
stuno varchar2(50),
stuname varchar2(50),
stuage number,
cname varchar2(50),
grade number,
credit number
);
以上的腳本符合第一範式的要求,但是如果按照第一範式設計的話,會存在問題:
insert into selectcourse values('s001','張三',21,'JAVA',89,0.3);
insert into selectcourse values('s001','李四',20,'JAVA',78,0.3);
insert into selectcourse values('s001','王五',23,'JAVA',80,0.3);
insert into selectcourse values('s001',趙六',22,'JAVA',90,0.3);
從以上的資料庫腳本上可以發現,所有的課程資訊備援了,而且還存在以下問題:
|-如果一門課程沒有一個學生選擇,則此而成就從學校徹底消失了
|-課程中本身也應該包含一個課程的編号,但是如果按照以上的設計,則課程編号肯定重複
|-如果要更改課程資訊,則要更改許多條記錄
我們使用第二範式修改資料庫腳本:
|-學生是一個實體--學生表
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number
);
|-課程也應該是一個實體--課程表
create table course(
cid number(5) primary key not null,
cname varchar2(50),
credit number
);
|-學生選課資訊也是一個實體--學生選課表
create table selectcourse(
stuno varchar2(50),
cid number(5),
grade number,
加入外鍵關聯,因為學生沒了,成績就沒了,因為課程沒了,成績就沒了
);
以上設計解決了以下問題:
|-學生不選課的時候,課程資訊不會消失
|-更新課程的時候直接更新課程表即可
|-所有的關聯關系在關系表中展現。
3) 第三範式
在實際開發中,第三範式的使用是最多的。
例如,現在要求設計一張學生表,包含學号、姓名、年齡、所在院校、學院位址、學院電話,此時肯定不能使用第一範式,但是現在如果使用的是第二範式呢?
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number
);
create table collage(
cid number(4) primary key not null,
cname varchar2(50) not not null,
caddress varchar2(200) not nul,
ctel varchar2(200) not null
);
create table studentcollage(
stuno varchar2(50),
cid number(4),
設定主-外鍵關系
);
按照上面的設計,一個學生可以同時在多個學院同時上課,多個學院會同時有同一個學生,此時,最好的做法是:一個學院包含多個學生,一個學生屬于一個學院,實際上,此設計就完全類似于部門和雇員表的設計結構。
create table collage(
cid number(4) primary key not null,
cname varchar2(50) not not null,
caddress varchar2(200) not nul,
ctel varchar2(200) not null
);
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number,
cid number(4),
建立主-外鍵關系
);
該設計是一個很明确的一對多的關系設計。
資料庫的唯一原則:
|-資料庫表的關聯查詢越少越好,SQL語句的複雜度越低越好。
1.9、資料庫設計工具
在實際中資料庫也有自己的設計工具,比較常用的就是Sybase的PowerDesigner開發工具,此工具可以友善的做各種設計,啟動之後,可以使用此工具,進行資料庫的模組化設計。
啟動PowerDesigner後,選擇建立,Physical Data Model,選擇Oracle資料庫
下面使用PowerDesigner工具将Oracle中的dept和emp表進行還原
建立表--在工具中進行主-外鍵的操作--得到關系之後,就可以通過Powerdesigner工具進行資料庫腳本的建立了。
1.10、資料庫設計分析
1) 要求
設計要求,要求設計一個網上購物程式(使用Powerdesigner建立模型并編寫測試資料),有以下的需求
|-管理者可以再背景添加商品,每個商品屬于一個商品組
|-可以對管理者進行分組,對每一組進行分别授權,即一個管理者組可以有多個管理者,一個管理者組有多個權限,一個管理者可以再多個組
|-使用者可以自己購買商品,購買商品時要在訂單表中添加資訊,一個使用者可以同時購買多個商品,使用者可以選擇自己所在的地區進行商品的派送
|-使用者可以根據自己的購買積分,對商品進行折扣
2) 實作
根據第一個要求,一個商品屬于一個商品組,則此時應該建立一個“一對多”的關系
根據第二個要求,可以對管理者進行分組,需要管理者表、管理者組表、權限表、管理者-管理者組表、管理者組-權限表
管理者和商品表也要存在關系
需要一個使用者表,與其産生關系的有地區表、子地區表、訂單表、訂單詳情表、積分表
正常情況下,一份訂單肯定會按照以上的格式顯示,那麼請問,這樣一來要查詢多少張表?
|-使用者表(使用者姓名、使用者電話、使用者位址)
|-地區表-子地區表(使用者地區)
|-訂單表、訂單詳情表(商品總價、訂單日期、郵政編碼)
本查詢需要同時查詢6張表。本程式中的所有代碼都是按照标準範式完成的,是以此時出現了以上的問題。
在開發中減少多表查詢的方法可以通過備援資料完成。</pre>
<p> </p>
<pre name="code" >Oracle 筆記
1
韓順平老師 oracle教程筆記
1.Oracle認證,與其它資料庫比較,安裝 Oracle安裝會自動的生成sys使用者和system使用者: (1)sys使用者是超級使用者,具有最高權限,具有sysdba角色,有create database的權限,該使用者預設的密碼是change_on_install (2)system使用者是管理操作員,權限也很大。具有sysoper角色,沒有create database的權限,預設的密碼是manager (3)一般講,對資料庫維護,使用system使用者登入就可以拉 也就是說sys和system這兩個使用者最大的差別是在于有沒有create database的權限。
2.Oracle的基本使用--基本指令
sql*plus的常用指令
連接配接指令 1.conn[ect] 用法:conn 使用者名/密碼@網絡服務名[as sysdba/sysoper]當用特權使用者身份連接配接時,必須帶上as sysdba或是as sysoper 2.disc[onnect] 說明: 該指令用來斷開與目前資料庫的連接配接 3.psssw[ord] 說明: 該指令用于修改使用者的密碼,如果要想修改其它使用者的密碼,需要用sys/system登入。 4.show user 說明: 顯示目前使用者名 5.exit 說明: 該指令會斷開與資料庫的連接配接,同時會退出sql*plus 檔案操作指令 1.start和@ 說明: 運作sql腳本 案例: sql&gt;@ d:\a.sql或是sql&gt;start d:\a.sql 2.edit 說明: 該指令可以編輯指定的sql腳本 案例: sql&gt;edit d:\a.sql,這樣會把d:\a.sql這個檔案打開 3.spool 說明: 該指令可以将sql*plus螢幕上的内容輸出到指定檔案中去。 案例: sql&gt;spool d:\b.sql 并輸入 sql&gt;spool off 互動式指令 1.&amp; 說明:可以替代變量,而該變量在執行時,需要使用者輸入。 select * from emp where job='&amp;job'; 2.edit 說明:該指令可以編輯指定的sql腳本 案例:SQL&gt;edit d:\a.sql 3.spool 說明:該指令可以将sql*plus螢幕上的内容輸出到指定檔案中去。 spool d:\b.sql 并輸入 spool off 顯示和設定環境變量 概述:可以用來控制輸出的各種格式,set show如果希望永久的儲存相關的設定,可以去修改glogin.sql腳本
Oracle 筆記
2
1.linesize 說明:設定顯示行的寬度,預設是80個字元 show linesize set linesize 90 2.pagesize說明:設定每頁顯示的行數目,預設是14 用法和linesize一樣 至于其它環境參數的使用也是大同小異
3.oracle使用者管理
oracle使用者的管理 建立使用者 概述:在oracle中要建立一個新的使用者使用create user語句,一般是具有dba(資料庫管理者)的權限才能使用。 create user 使用者名 identified by 密碼; (oracle有個毛病,密碼必須以字母開頭,如果以字母開頭,它不會建立使用者) 給使用者修改密碼 概述:如果給自己修改密碼可以直接使用 password 使用者名 如果給别人修改密碼則需要具有dba的權限,或是擁有alter user的系統權限 SQL&gt; alter user 使用者名 identified by 新密碼 删除使用者 概述:一般以dba的身份去删除某個使用者,如果用其它使用者去删除使用者則需要具有drop user的權限。 比如 drop user 使用者名 【cascade】 在删除使用者時,注意: 如果要删除的使用者,已經建立了表,那麼就需要在删除的時候帶一個參數cascade; 使用者管理綜合案例 概述:建立的新使用者是沒有任何權限的,甚至連登陸的資料庫的權限都沒有,需要為其指定相應的權限。給一個使用者賦權限使用指令grant,回收權限使用指令revoke。 為了給講清楚使用者的管理,這裡我給大家舉一個案例。 SQL&gt; conn xiaoming/m12; ERROR: ORA-01045: user XIAOMING lacks CREATE SESSION privilege; logon denied 警告: 您不再連接配接到 ORACLE。 SQL&gt; show user; USER 為 "" SQL&gt; conn system/p; 已連接配接。 SQL&gt; grant connect to xiaoming; 授權成功。 SQL&gt; conn xiaoming/m12; 已連接配接。 SQL&gt; 注意:grant connect to xiaoming;在這裡,準确的講,connect不是權限,而是角色。
現在說下對象權限,現在要做這麼件事情: * 希望xiaoming使用者可以去查詢emp表 * 希望xiaoming使用者可以去查詢scott的emp表
Oracle 筆記
3
grant select on emp to xiaoming * 希望xiaoming使用者可以去修改scott的emp表 grant update on emp to xiaoming * 希望xiaoming使用者可以去修改/删除,查詢,添加scott的emp表 grant all on emp to xiaoming * scott希望收回xiaoming對emp表的查詢權限 revoke select on emp from xiaoming //對權限的維護。 * 希望xiaoming使用者可以去查詢scott的emp表/還希望xiaoming可以把這個權限繼續給别人。 --如果是對象權限,就加入 with grant option grant select on emp to xiaoming with grant option 我的操作過程: SQL&gt; conn scott/tiger; 已連接配接。 SQL&gt; grant select on scott.emp to xiaoming with grant option; 授權成功。 SQL&gt; conn system/p; 已連接配接。 SQL&gt; create user xiaohong identified by m123; 使用者已建立。 SQL&gt; grant connect to xiaohong; 授權成功。 SQL&gt; conn xiaoming/m12; 已連接配接。 SQL&gt; grant select on scott.emp to xiaohong; 授權成功。 --如果是系統權限。 system給xiaoming權限時: grant connect to xiaoming with admin option 問題:如果scott把xiaoming對emp表的查詢權限回收,那麼xiaohong會怎樣? 答案:被回收。 下面是我的操作過程: SQL&gt; conn scott/tiger; 已連接配接。 SQL&gt; revoke select on emp from xiaoming; 撤銷成功。 SQL&gt; conn xiaohong/m123; 已連接配接。 SQL&gt; select * from scott.emp; select * from scott.emp 第 1 行出現錯誤: ORA-00942: 表或視圖不存在 結果顯示:小紅受到誅連了。。 使用profile管理使用者密碼 概述:profile是密碼限制,資源限制的指令集合,當建立資料庫的,oracle會自動建立名稱為default的profile。當建立使用者沒
Oracle 筆記
4
有指定profile選項,那麼oracle就會将default配置設定給使用者。 1.賬戶鎖定 概述:指定該賬戶(使用者)登陸時最多可以輸入密碼的次數,也可以指定使用者鎖定的時間(天)一般用dba的身份去執行該指令。 例子:指定scott這個使用者最多隻能嘗試3次登陸,鎖定時間為2天,讓我們看看怎麼實作。 建立profile檔案 SQL&gt; create profile lock_account limit failed_login_attempts 3 password_lock_time 2; SQL&gt; alter user scott profile lock_account; 2.給賬戶(使用者)解鎖 SQL&gt; alter user tea account unlock; 3.終止密碼 為了讓使用者定期修改密碼可以使用終止密碼的指令來完成,同樣這個指令也需要dba的身份來操作。 例子:給前面建立的使用者tea建立一個profile檔案,要求該使用者每隔10天要修改自己的登陸密碼,寬限期為2天。看看怎麼做。 SQL&gt; create profile myprofile limit password_life_time 10 password_grace_time 2; SQL&gt; alter user tea profile myprofile; 密碼曆史 概述:如果希望使用者在修改密碼時,不能使用以前使用過的密碼,可使用密碼曆史,這樣oracle就會将密碼修改的資訊存放到資料字典中,這樣當使用者修改密碼時,oracle就會對新舊密碼進行比較,當發現新舊密碼一樣時,就提示使用者重新輸入密碼。 例子: 1)建立profile SQL&gt;create profile password_history limit password_life_time 10 password_grace_time 2 password_reuse_time 10 password_reuse_time //指定密碼可重用時間即10天後就可以重用 2)配置設定給某個使用者
删除profile 概述:當不需要某個profile檔案時,可以删除該檔案。 SQL&gt; drop profile password_history 【casade】 注意:檔案删除後,用這個檔案去限制的那些使用者通通也都被釋放了。。 加了casade,就會把級聯的相關東西也給删除掉
4.oracle表的管理(資料類型,表建立删除,資料CRUD操作)
期望目标
? 1.掌握oracle表的管理(建立/維護)
? 2.掌握對oracle表的各種查詢技巧
? 3.學會建立新的oracle資料庫 oracle的表的管理 表名和列的命名規則
? 必須以字母開頭
? 長度不能超過30個字元
? 不能使用oracle的保留字
? 隻能使用如下字元 A-Z,a-z,0-9,$,#等
oracle支援的資料類型? 字元類 char 定長 最大2000個字元。
Oracle 筆記
5
例子:char(10) ‘小韓’前四個字元放‘小韓’,後添6個空格補全 如‘小韓 ’ varchar2(20) 變長 最大4000個字元。 例子:varchar2(10) ‘小韓’ oracle配置設定四個字元。這樣可以節省空間。 clob(character large object) 字元型大對象 最大4G char 查詢的速度極快浪費空間,查詢比較多的資料用。 varchar 節省空間 數字型 number範圍 -10的38次方 到 10的38次方 可以表示整數,也可以表示小數 number(5,2) 表示一位小數有5位有效數,2位小數 範圍:-999.99到999.99 number(5) 表示一個5位整數 範圍99999到-99999 日期類型 date 包含年月日和時分秒 oracle預設格式 1-1月-1999 timestamp 這是oracle9i對date資料類型的擴充。可以精确到毫秒。 ? 圖檔 blob 二進制資料 可以存放圖檔/聲音 4G 一般來講,在真實項目中是不會把圖檔和聲音真的往資料庫裡存放,一般存放圖檔、視訊的路徑,如果安全需要比較高的話,則放入資料庫。 怎樣建立表 建表 --學生表 create table student ( ---表名 xh number(4), --學号 xm varchar2(20), --姓名 sex char(2), --性别 birthday date, --出生日期 sal number(7,2) --獎學金 ); --班級表 CREATE TABLE class( classId NUMBER(2), cName VARCHAR2(40) ); 修改表 ? 添加一個字段 SQL&gt;ALTER TABLE student add (classId NUMBER(2)); ? 修改一個字段的長度 SQL&gt;ALTER TABLE student MODIFY (xm VARCHAR2(30)); ? 修改字段的類型/或是名字(不能有資料) 不建議做 SQL&gt;ALTER TABLE student modify (xm CHAR(30)); ? 删除一個字段 不建議做(删了之後,順序就變了。加就沒問題,應為是加在後面) SQL&gt;ALTER TABLE student DROP COLUMN sal;
Oracle 筆記
6
? 修改表的名字 很少有這種需求 SQL&gt;RENAME student TO stu; ? 删除表 SQL&gt;DROP TABLE student; 添加資料 所有字段都插入資料 INSERT INTO student VALUES ('A001', '張三', '男', '01-5月-05', 10); oracle中預設的日期格式‘dd-mon-yy’ dd日子(天) mon 月份 yy 2位的年 ‘09-6月-99’ 1999年6月9日 修改日期的預設格式(臨時修改,資料庫重新開機後仍為預設;如要修改需要修改系統資料庫) ALTER SESSION SET NLS_DATE_FORMAT ='yyyy-mm-dd'; 修改後,可以用我們熟悉的格式添加日期類型: INSERT INTO student VALUES ('A002', 'MIKE', '男', '1905-05-06', 10); 插入部分字段 INSERT INTO student(xh, xm, sex) VALUES ('A003', 'JOHN', '女'); 插入空值 INSERT INTO student(xh, xm, sex, birthday) VALUES ('A004', 'MARTIN', '男', null); 問題來了,如果你要查詢student表裡birthday為null的記錄,怎麼寫sql呢? 錯誤寫法:select * from student where birthday = null; 正确寫法:select * from student where birthday is null; 如果要查詢birthday不為null,則應該這樣寫: select * from student where birthday is not null; 修改資料 ? 修改一個字段 UPDATE student SET sex = '女' WHERE xh = 'A001'; ? 修改多個字段 UPDATE student SET sex = '男', birthday = '1984-04-01' WHERE xh = 'A001'; 修改含有null值的資料 不要用 = null 而是用 is null; SELECT * FROM student WHERE birthday IS null; ? 删除資料 DELETE FROM student; 删除所有記錄,表結構還在,寫日志,可以恢複的,速度慢。 Delete 的資料可以恢複。 savepoint a; --建立儲存點 DELETE FROM student; rollback to a; --恢複到儲存點 一個有經驗的DBA,在確定完成無誤的情況下要定期建立還原點。 DROP TABLE student; --删除表的結構和資料; delete from student WHERE xh = 'A001'; --删除一條記錄; truncate TABLE student; --删除表中的所有記錄,表結構還在,不寫日志,無法找回删除的記錄,速度快。
5.oracle表查詢(1)
在我們講解的過程中我們利用scott使用者存在的幾張表(emp,dept)為大家示範如何使用select語句,select語句在軟體程式設計中非常有用,希望大家好好的掌握。
Oracle 筆記
7
emp 雇員表 clerk 普員工 salesman 銷售 manager 經理 analyst 分析師 president 總裁 mgr 上級的編号 hiredate 入職時間 sal 月工資 comm 獎金 deptno 部門 dept部門表 deptno 部門編号 accounting 财務部 research 研發部 operations 業務部 loc 部門所在地點 salgrade 工資級别 grade 級别 losal 最低工資 hisal 最高工資 簡單的查詢語句 ? 檢視表結構 DESC emp; ? 查詢所有列 SELECT * FROM dept; 切忌動不動就用select * SET TIMING ON; 打開顯示操作時間的開關,在下面顯示查詢時間。 CREATE TABLE users(userId VARCHAR2(10), uName VARCHAR2 (20), uPassw VARCHAR2(30)); INSERT INTO users VALUES('a0001', '啊啊啊啊', 'aaaaaaaaaaaaaaaaaaaaaaa'); --從自己複制,加大資料量 大概幾萬行就可以了 可以用來測試sql語句執行效率 INSERT INTO users (userId,UNAME,UPASSW) SELECT * FROM users; SELECT COUNT (*) FROM users;統計行數 ? 查詢指定列 SELECT ename, sal, job, deptno FROM emp; ? 如何取消重複行DISTINCT SELECT DISTINCT deptno, job FROM emp; ?查詢SMITH所在部門,工作,薪水 SELECT deptno,job,sal FROM emp WHERE ename = 'SMITH'; 注意:oracle對内容的大小寫是區分的,是以ename='SMITH'和ename='smith'是不同的
Oracle 筆記
8
? 使用算術表達式 nvl null 問題:如何顯示每個雇員的年工資? SELECT sal*13+nvl(comm, 0)*13 "年薪" , ename, comm FROM emp; ? 使用列的别名 SELECT ename "姓名", sal*12 AS "年收入" FROM emp; ? 如何處理null值 使用nvl函數來處理 ? 如何連接配接字元串(||) SELECT ename || ' is a ' || job FROM emp; ? 使用where子句 問題:如何顯示工資高于3000的 員工? SELECT * FROM emp WHERE sal &gt; 3000; 問題:如何查找1982.1.1後入職的員工? SELECT ename,hiredate FROM emp WHERE hiredate &gt;'1-1月-1982'; 問題:如何顯示工資在2000到3000的員工? SELECT ename,sal FROM emp WHERE sal &gt;=2000 AND sal &lt;= 3000; ? 如何使用like操作符 %:表示0到多個字元 _:表示任意單個字元 問題:如何顯示首字元為S的員工姓名和工資? SELECT ename,sal FROM emp WHERE ename like 'S%'; 如何顯示第三個字元為大寫O的所有員工的姓名和工資? SELECT ename,sal FROM emp WHERE ename like '__O%'; ? 在where條件中使用in 問題:如何顯示empno為7844, 7839,123,456 的雇員情況? SELECT * FROM emp WHERE empno in (7844, 7839,123,456); ? 使用is null的操作符 問題:如何顯示沒有上級的雇員的情況? 錯誤寫法:select * from emp where mgr = ''; 正确寫法:SELECT * FROM emp WHERE mgr is null;
6.oracle表查詢(2)
? 使用邏輯操作符号 問題:查詢工資高于500或者是崗位為MANAGER的雇員,同時還要滿足他們的姓名首字母為大寫的J? SELECT * FROM emp WHERE (sal &gt;500 or job = 'MANAGER') and ename LIKE 'J%'; ? 使用order by 字句 預設asc 問題:如何按照工資的從低到高的順序顯示雇員的資訊? SELECT * FROM emp ORDER by sal; 問題:按照部門号升序而雇員的工資降序排列 SELECT * FROM emp ORDER by deptno, sal DESC; ? 使用列的别名排序 問題:按年薪排序 select ename, (sal+nvl(comm,0))*12 "年薪" from emp order by "年薪" asc; 别名需要使用“”号圈中,英文不需要“”号
Oracle 筆記
9
? 分頁查詢 等學了子查詢再說吧。。。。。。。。 Clear 清屏指令 oracle表複雜查詢 ? 說明 在實際應用中經常需要執行複雜的資料統計,經常需要顯示多張表的資料,現在我們給大家介紹較為複雜的select語句 資料分組 ——max,min, avg, sum, count 問題:如何顯示所有員工中最高工資和最低工資? SELECT MAX(sal),min(sal) FROM emp e; 最高工資那個人是誰? 錯誤寫法:select ename, sal from emp where sal=max(sal); 正确寫法:select ename, sal from emp where sal=(select max(sal) from emp); 注意:select ename, max(sal) from emp;這語句執行的時候會報錯,說ORA-00937:非單組分組函數。因為max是分組函數,而ename不是分組函數....... 但是select min(sal), max(sal) from emp;這句是可以執行的。因為min和max都是分組函數,就是說:如果列裡面有一個分組函數,其它的都必須是分組函數,否則就出錯。這是文法規定的 問題:如何顯示所有員工的平均工資和工資總和? 問題:如何計算總共有多少員工問題:如何 擴充要求: 查詢最高工資員工的名字,工作崗位 SELECT ename, job, sal FROM emp e where sal = (SELECT MAX(sal) FROM emp); 顯示工資高于平均工資的員工資訊 SELECT * FROM emp e where sal &gt; (SELECT AVG(sal) FROM emp); ? group by 和 having子句 group by用于對查詢的結果分組統計, having子句用于限制分組顯示結果。 問題:如何顯示每個部門的平均工資和最高工資? SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno; (注意:這裡暗藏了一點,如果你要分組查詢的話,分組的字段deptno一定要出現在查詢的清單裡面,否則會報錯。因為分組的字段都不出現的話,就沒辦法分組了) 問題:顯示每個部門的每種崗位的平均工資和最低工資? SELECT min(sal), AVG(sal), deptno, job FROM emp GROUP by deptno, job; 問題:顯示平均工資低于2000的部門号和它的平均工資? SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno having AVG(sal) &lt; 2000; ? 對資料分組的總結 1 分組函數隻能出現在選擇清單、having、order by子句中(不能出現在where中) 2 如果在select語句中同時包含有group by, having, order by 那麼它們的順序是group by, having, order by 3 在選擇列中如果有列、表達式和分組函數,那麼這些列和表達式必須有一個出現在group by 子句中,否則就會出錯。 如SELECT deptno, AVG(sal), MAX(sal) FROM emp GROUP by deptno HAVING AVG(sal) &lt; 2000; 這裡deptno就一定要出現在group by 中 多表查詢 ? 說明 多表查詢是指基于兩個和兩個以上的表或是視圖的查詢。在實際應用中,查詢單個表可能不能滿足你的需求,(如顯示sales部門位置和其員工的姓名),這種情況下需要使用到(dept表和emp表)
Oracle 筆記
10
問題:顯示雇員名,雇員工資及所在部門的名字【笛卡爾集】? 規定:多表查詢的條件是 至少不能少于 表的個數-1 才能排除笛卡爾集 (如果有N張表聯合查詢,必須得有N-1個條件,才能避免笛卡爾集合) SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno; 問題:顯示部門号為10的部門名、員工名和工資? SELECT d.dname, e.ename, e.sal FROM emp e, dept d WHERE e.deptno = d.deptno and e.deptno = 10; 問題:顯示各個員工的姓名,工資及工資的級别? 先看salgrade的表結構和記錄 SQL&gt;select * from salgrade; GRADE LOSAL HISAL ------------- ------------- ------------ 1 700 1200 2 1201 1400 3 1401 2000 4 2001 3000 5 3001 9999 SELECT e.ename, e.sal, s.grade FROM emp e, salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal; 擴充要求: 問題:顯示雇員名,雇員工資及所在部門的名字,并按部門排序? SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno ORDER by e.deptno; (注意:如果用group by,一定要把e.deptno放到查詢列裡面) ? 自連接配接 自連接配接是指在同一張表的連接配接查詢 問題:顯示某個員工的上級上司的姓名? 比如顯示員工‘FORD’的上級 SELECT worker.ename, boss.ename FROM emp worker,emp boss WHERE worker.mgr = boss.empno AND worker.ename = 'FORD'; 子查詢 ? 什麼是子查詢 子查詢是指嵌入在其他sql語句中的select語句,也叫嵌套查詢。 ? 單行子查詢 單行子查詢是指隻傳回一行資料的子查詢語句 請思考:顯示與SMITH同部門的所有員工? 思路: 1 查詢出SMITH的部門号 select deptno from emp WHERE ename = 'SMITH'; 2 顯示 SELECT * FROM emp WHERE deptno = (select deptno from emp WHERE ename = 'SMITH'); 資料庫在執行sql 是從左到右掃描的, 如果有括号的話,括号裡面的先被優先執行。 ? 多行子查詢 多行子查詢指傳回多行資料的子查詢 請思考:如何查詢和部門10的工作相同的雇員的名字、崗位、工資、部門号 SELECT DISTINCT job FROM emp WHERE deptno = 10; SELECT * FROM emp WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10); (注意:不能用job=..,因為等号=是一對一的) ? 在多行子查詢中使用all操作符
Oracle 筆記
11
問題:如何顯示工資比部門30的所有員工的工資高的員工的姓名、工資和部門号? SELECT ename, sal, deptno FROM emp WHERE sal &gt; all (SELECT sal FROM emp WHERE deptno = 30); 擴充要求: 大家想想還有沒有别的查詢方法。 SELECT ename, sal, deptno FROM emp WHERE sal &gt; (SELECT MAX(sal) FROM emp WHERE deptno = 30); 執行效率上, 函數高得多 ? 在多行子查詢中使用any操作符 問題:如何顯示工資比部門30的任意一個員工的工資高的員工姓名、工資和部門号? SELECT ename, sal, deptno FROM emp WHERE sal &gt; ANY (SELECT sal FROM emp WHERE deptno = 30); 擴充要求: 大家想想還有沒有别的查詢方法。 SELECT ename, sal, deptno FROM emp WHERE sal &gt; (SELECT min(sal) FROM emp WHERE deptno = 30); ? 多列子查詢 單行子查詢是指子查詢隻傳回單列、單行資料,多行子查詢是指傳回單列多行資料,都是針對單列而言的,而多列子查詢是指查詢傳回多個列資料的子查詢語句。 請思考如何查詢與SMITH的部門和崗位完全相同的所有雇員。 SELECT deptno, job FROM emp WHERE ename = 'SMITH'; SELECT * FROM emp WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = 'SMITH'); ? 在from子句中使用子查詢 請思考:如何顯示高于自己部門平均工資的員工的資訊 思路: 1. 查出各個部門的平均工資和部門号 SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno; 2. 把上面的查詢結果看做是一張子表 SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) ds WHERE e.deptno = ds.deptno AND e.sal &gt; ds.mysal; 如何衡量一個程式員的水準? 網絡處理能力, 資料庫, 程式代碼的優化程式的效率要很高 小總結: 在這裡需要說明的當在from子句中使用子查詢時,該子查詢會被作為一個視圖來對待,是以叫做内嵌視圖,當在from子句中使用子查詢時,必須給子查詢指定别名。 注意:别名不能用as,如:SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) as ds WHERE e.deptno = ds.deptno AND e.sal &gt; ds.mysal; 在ds前不能加as,否則會報錯 (給表取别名的時候,不能加as;但是給列取别名,是可以加as的) ? 分頁查詢 按雇員的id号升序取出 oracle的分頁一共有三種方式 1.根據rowid來分 select * from t_xiaoxi where rowid in (select rid from (select rownum rn, rid from(select rowid rid, cid from t_xiaoxi order by cid desc) where rownum&lt;10000) where rn&gt;9980) order by cid desc; 執行時間0.03秒 2.按分析函數來分 select * from (select t.*, row_number() over(order by cid desc) rk from t_xiaoxi t) where rk&lt;10000 and rk&gt;9980; 執行時間1.01秒 3.按rownum來分
Oracle 筆記
12
select * from (select t.*,rownum rn from(select * from t_xiaoxi order by cid desc)t where rownum&lt;10000) where rn&gt;9980; 執行時間0.1秒 其中t_xiaoxi為表名稱,cid為表的關鍵字段,取按cid降序排序後的第9981-9999條記錄,t_xiaoxi表有70000多條記錄。 個人感覺1的效率最好,3次之,2最差。 //測試通過的分頁查詢okokok select * from (select a1.*, rownum rn from(select ename,job from emp) a1 where rownum&lt;=10)where rn&gt;=5; 下面最主要介紹第三種:按rownum來分 1. rownum 分頁 SELECT * FROM emp; 2. 顯示rownum[oracle配置設定的] SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e; rn相當于Oracle配置設定的行的ID号 3.挑選出6—10條記錄 先查出1-10條記錄 SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM &lt;= 10; 如果後面加上rownum&gt;=6是不行的, 4. 然後查出6-10條記錄 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM &lt;= 10) WHERE rn &gt;= 6; 5. 幾個查詢變化 a. 指定查詢列,隻需要修改最裡層的子查詢 隻查詢雇員的編号和工資 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp) e WHERE ROWNUM &lt;= 10) WHERE rn &gt;= 6; b. 排序查詢,隻需要修改最裡層的子查詢 工資排序後查詢6-10條資料 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp ORDER by sal) e WHERE ROWNUM &lt;= 10) WHERE rn &gt;= 6; ? 用查詢結果建立新表 這個指令是一種快捷的建表方式 CREATE TABLE mytable (id, name, sal, job, deptno) as SELECT empno, ename, sal, job, deptno FROM emp; 建立好之後,desc mytable;和select * from mytable;看看結果如何? 合并查詢 ? 合并查詢 有時在實際應用中,為了合并多個select語句的結果,可以使用集合操作符号union,union all,intersect,minus 多用于資料量比較大的資料局庫,運作速度快。 1). union 該操作符用于取得兩個結果集的并集。當使用該操作符時,會自動去掉結果集中重複行。 SELECT ename, sal, job FROM emp WHERE sal &gt;2500 UNION SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 2).union all 該操作符與union相似,但是它不會取消重複行,而且不會排序。 SELECT ename, sal, job FROM emp WHERE sal &gt;2500 UNION ALL SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';
Oracle 筆記
13
該操作符用于取得兩個結果集的并集。當使用該操作符時,會自動去掉結果集中重複行。 3). intersect 使用該操作符用于取得兩個結果集的交集。 SELECT ename, sal, job FROM emp WHERE sal &gt;2500 INTERSECT SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 4). minus 使用改操作符用于取得兩個結果集的差集,他隻會顯示存在第一個集合中,而不存在第二個集合中的資料。 SELECT ename, sal, job FROM emp WHERE sal &gt;2500 MINUS SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; (MINUS就是減法的意思) 建立資料庫有兩種方法: 1). 通過oracle提供的向導工具。√ database Configuration Assistant 【資料庫配置助手】 2).我們可以用手工步驟直接建立。
7.java操作oracle 内容介紹 1.上節回顧 2.java程式如何操作oracle √ 3.如何在oracle中操作資料 4.oracle事務處理 5.sql函數的使用 √ 期望目标 1.掌握oracle表對資料操作技巧 2.掌握在java程式中操作oracle 3.了解oracle事物概念 4.掌握oracle各種sql函數 java連接配接oracle ? 介紹 前面我們一直在plsql中操作oracle,那麼如何在java 程式中操作資料庫呢? 下面我們舉例說明,寫一個java,分頁顯示emp表的使用者資訊。
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//示範 如何使用 jdbc_odbc橋連接配接方式
public class TestOracle {
public static void main(String[] args) {
try {
// 1.加載驅動
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Oracle 筆記
14
// 2.得到連接配接
Connection ct = DriverManager.getConnection(
"jdbc.odbc:testConnectOracle", "scott",
"tiger");
// 從下面開始,和SQL Server一模一樣
Statement sm = ct.createStatement();
ResultSet rs = sm.executeQuery("select * from emp");
while (rs.next()) {
//使用者名
System.out.println("使用者名: "+rs.getString(2));
//預設是從1開始編号的
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
在得到連接配接那裡,要去配置資料源,點選控制台--&gt;系統和安全--&gt;管理工具--&gt;資料源(ODBC), 打開後點添加,如圖: 可以看到,有個Oracle in OraDb10g_home1的驅動,它是Oracle安裝完後自動加上去的。 選中 後,點完成,再填如下資訊,如圖: 這樣配好後基本就可以了,但為了安全起見,建議大家測試一下,點選 Test Connection按鈕, 測試通過後點ok,然後資料源就生成了,如圖: 然後把資料源名稱寫進jdbc.odbc:???裡。 這裡要注意:jdbcodbc能不能遠端連接配接呢?不能遠端連接配接,也就是你這樣寫的話就意味着java程 序和oracle資料庫應該是在同一台機器上,因為這裡沒有指定IP位址,肯定預設就是本地。 如 果要遠端連,就用jdbc,jdbc是可以遠端連的。 運作TestOracle.java,控制台輸出....................... 可惜我沒運作成功,說 java.sql.SQLException: No suitable driver found for jdbc.odbc:testConnectOracle at java.sql.DriverManager.getConnection(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at com.sp.TestOracle.main(TestOracle.java:18) 不知道為什麼。。。 接下來講解用JDBC的方式連接配接Oracle
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//使用 jdbc連接配接oracle
public class TestOracle2 {
public static void main(String[] args) {
try {
// 1.加載驅動
Oracle 筆記
15
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.得到連接配接
Connection ct = DriverManager.getConnection
("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
// 從下面開始,和SQL Server一模一樣
Statement sm = ct.createStatement();
ResultSet rs = sm.executeQuery("select * from emp");
while (rs.next()) {
//使用者名
System.out.println("使用者名: "+rs.getString(2));
//預設是從1開始編号的
}
} catch (Exception e) {
e.printStackTrace();
}
}
} 記得要把驅動包引入,classes12.jar 運作,。。。。 再次可惜,我還是沒運作成功,錯誤是: java.sql.SQLException: Io 異常: The Network Adapter could not establish the connection at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134) at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179) at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:334) at oracle.jdbc.driver.OracleConnection.&lt;init&gt;(OracleConnection.java:418) at oracle.jdbc.driver.OracleDriver.getConnectionInstance (OracleDriver.java:521) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:325) at java.sql.DriverManager.getConnection(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at com.sp.TestOracle2.main(TestOracle2.java:18) 我也不知道為什麼。。。 幽怨了。。 接下來建個web project,來測試oracle的分頁,挺麻煩,不記錄了。。 在oracle中操作資料 - 使用特定格式插入日期值 ? 使用 to_date函數 請大家思考: 如何插入列帶有日期的表,并按照年-月-日的格式插入? insert into emp values (9998, 'xiaohong', 'MANAGER', 7782, to_date('1988-12- 12', 'yyyy-mm-dd'), 78.9, 55.33, 10); 注意: insert into emp values (9998, 'xiaohong', 'MANAGER', 7782, '12-12月-1988', 78.9, 55.33, 10); 這句語句是可以成功運作的 使用子查詢插入資料 ? 介紹 當使用valus子句時,一次隻能插入一行資料,當使用子查詢插入資料時,一條inset語句可以插
Oracle 筆記
16
入大量的資料。當處理行遷移或者裝載外部表的資料到資料庫時,可以使用子查詢來插入資料。 把emp表中10号部門的資料導入到新表中 create table kkk(myId number(4), myName varchar2(50), myDept number(5)); insert into kkk (myId, myName, myDept) select empno, ename, deptno from emp where deptno = 10; ? 介紹 使用update語句更新資料時,既可以使用表達式或者數值直接修改資料,也可以使用子查詢修改 資料。 問題:希望員工SCOTT的崗位、工資、補助與SMITH員工一樣。 update emp set(job, sal, comm)=(select job, sal, comm from emp where ename='SMITH') where ename='SCOTT';
8.oracle中事務處理
? 什麼是事務 事務用于保證資料的一緻性,它由一組相關的dml語句組成,該組的dml(資料操作語言,增删改,沒有查詢)語句要麼全部成功,要麼全部失敗。 如:網上轉賬就是典型的要用事務來處理,用于保證資料的一緻性。 dml 資料操作語言 銀行轉賬、QQ申請、車票購買 ? 事務和鎖 當執行事務操作時(dml語句),oracle會在被作用的表上加鎖,防止其它使用者修改表的結構。這裡對我們的使用者來來講是非常重要的。 .....其它程序排序,知道1号程序完成,鎖打開,2号程序進入。依次進行,如果有程序級别較高的,可以插隊。 ? 送出事務 當執行用commit語句可以送出事務。當執行了commit語句之後,會确認事務的變化、結束事務。删除儲存點、釋放鎖,當使用commit語句結束事務之後,其它會話将可以檢視到事務變化後的新資料。 儲存點就是為回退做的。儲存點的個數沒有限制 ? 回退事務 在介紹回退事務前,我們先介紹一下儲存點(savepoint)的概念和作用。儲存點是事務中的一點。用于取消部分事務,當結束事務時,會自動的删除該事務所定義的所有儲存點。當執行rollback時,通過指定儲存點可以回退到指定的點,這裡我們作圖說明。 ? 事務的幾個重要操作 1.設定儲存點 savepoint a 2.取消部分事務 rollback to a 3.取消全部事務 rollback 注意:這個回退事務,必須是沒有commit前使用的;如果事務送出了,那麼無論你剛才做了多少個儲存點,都統統沒有。 如果沒有手動執行commit,而是exit了,那麼會自動送出 ? java程式中如何使用事務 在java操作資料庫時,為了保證資料的一緻性,比如賬戶操作(1)從一個賬戶中減掉10$(2)在另一個賬戶上加入10$,我們看看如何使用事務?
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
Oracle 筆記
17
import java.sql.Statement;
public class TestTrans {
public static void main(String[] args) {
try {
// 1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.得到連接配接
Connection ct = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
Statement sm = ct.createStatement();
// 從scott的sal中減去100
sm.executeUpdate("update emp set sal=sal-100 where ename='SCOTT'");
int i = 7 / 0;
// 給smith的sal加上100
sm.executeUpdate("update emp set sal=sal+100 where ename='SMITH'");
// 關閉打開的資源
sm.close();
ct.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
運作,會出現異常,檢視資料庫,SCOTT的sal減了100,但是SMITH的sal卻不變,很可怕。。。 我們怎樣才能保證,這兩個操作要麼同時成功,要麼同時失敗呢?
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestTrans {
public static void main(String[] args) {
Connection ct = null;
try {
// 1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.得到連接配接
ct = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
// 加入事務處理
ct.setAutoCommit(false);// 設定不能預設送出
Statement sm = ct.createStatement();
// 從scott的sal中減去100
sm.executeUpdate("update emp set sal=sal-100 where ename='SCOTT'");
int i = 7 / 0;
Oracle 筆記
18
// 給smith的sal加上100
sm.executeUpdate("update emp set sal=sal+100 where ename='SMITH'");
// 送出事務
ct.commit();
// 關閉打開的資源
sm.close();
ct.close();
} catch (Exception e) {
// 如果發生異常,就復原
try {
ct.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
再運作一下,會出現異常,檢視資料庫,資料沒變化。。 ? 隻讀事務 隻讀事務是指隻允許執行查詢的操作,而不允許執行任何其它dml操作的事務,使用隻讀事務可以確定使用者隻能取得某時間點的資料。假定機票代售點每天18點開始統計今天的銷售情況,這時可以使用隻讀事務。在設定了隻讀事務後,盡管其它會話可能會送出新的事務,但是隻讀事務将不會取得最新資料的變化,進而可以保證取得特定時間點的資料資訊。 ? 設定隻讀事務 set transaction read only;
9.oracle的函數
sql函數的使用 字元函數? 介紹 字元函數是oracle中最常用的函數,我們來看看有哪些字元函數: ? lower(char):将字元串轉化為小寫的格式。 ? upper(char):将字元串轉化為大寫的格式。 ? length(char):傳回字元串的長度。 ? substr(char,m,n):取字元串的子串 n代表取n個的意思,不是代表取到第n個 ? replace(char1,search_string,replace_string) ? instr(char1,char2,[,n[,m]])取子串在字元串的位置 問題:将所有員工的名字按小寫的方式顯示 SQL&gt; select lower(ename) from emp; 問題:将所有員工的名字按大寫的方式顯示。 SQL&gt; select upper(ename) from emp; 問題:顯示正好為5個字元的員工的姓名。 SQL&gt; select * from emp where length(ename)=5; 問題:顯示所有員工姓名的前三個字元。
Oracle 筆記
19
SQL&gt; select substr(ename,1,3) from emp; 問題:以首字母大寫,後面小寫的方式顯示所有員工的姓名。 SQL&gt; select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename)-1)) from emp; 問題:以首字母小寫,後面大寫的方式顯示所有員工的姓名。 SQL&gt; select lower(substr(ename,1,1)) || upper(substr(ename,2,length(ename)-1)) from emp; 問題:顯示所有員工的姓名,用“我是老虎”替換所有“A” SQL&gt; select replace(ename,'A', '我是老虎') from emp; 數學函數? 介紹 數學函數的輸入參數和傳回值的資料類型都是數字類型的。數學函數包括cos,cosh,exp,ln, log,sin,sinh,sqrt,tan,tanh,acos,asin,atan,round,我們講最常用的: ? round(n,[m]) 該函數用于執行四舍五入,如果省掉m,則四舍五入到整數,如果m是正數,則四舍五入到小數點的m位後。如果m是負數,則四舍五入到小數點的m位前。 ? trunc(n,[m]) 該函數用于截取數字。如果省掉m,就截去小數部分,如果m是正數就截取到小數點的m位後,如果m是負數,則截取到小數點的前m位。 ? mod(m,n) ? floor(n) 傳回小于或是等于n的最大整數 ? ceil(n) 傳回大于或是等于n的最小整數 對數字的處理,在财務系統或銀行系統中用的最多,不同的處理方法,對财務報表有不同的結果。 問題:顯示在一個月為30天的情況下,所有員工的日薪金,忽略餘數。 SQL&gt; select trunc(sal/30), ename from emp; or SQL&gt; select floor(sal/30), ename from emp; 在做oracle測試的時候,可以使用dual表 select mod(10,2) from dual;結果是0 select mod(10,3) from dual;結果是1 其它的數學函數,有興趣的同學可以自己去看看: abs(n): 傳回數字n的絕對值 select abs(-13) from dual; acos(n): 傳回數字的反餘弦值 asin(n): 傳回數字的反正弦值 atan(n): 傳回數字的反正切值 cos(n): exp(n): 傳回e的n次幂 log(m,n): 傳回對數值 power(m,n): 傳回m的n次幂 日期函數? 介紹 日期函數用于處理date類型的資料。 預設情況下日期格式是dd-mon-yy 即12-7月-78 (1)sysdate: 該函數傳回系統時間 (2)add_months(d,n) (3)last_day(d):傳回指定日期所在月份的最後一天 問題:查找已經入職8個月多的員工 SQL&gt; select * from emp where sysdate&gt;=add_months(hiredate,8); 問題:顯示滿10年服務年限的員工的姓名和受雇日期。
Oracle 筆記
20
SQL&gt; select ename, hiredate from emp where sysdate&gt;=add_months(hiredate,12*10); 問題:對于每個員工,顯示其加入公司的天數。 SQL&gt; select floor(sysdate-hiredate) "入職天數",ename from emp; or SQL&gt; select trunc(sysdate-hiredate) "入職天數",ename from emp; 問題:找出各月倒數第3天受雇的所有員工。 SQL&gt; select hiredate,ename from emp where last_day(hiredate)-2=hiredate; 轉換函數 ? 介紹√ 轉換函數用于将資料類型從一種轉為另外一種。在某些情況下,oracle server允許值的資料類型和實際的不一樣,這時oracle server會隐含的轉化資料類型 比如: create table t1(id int); insert into t1 values('10');--&gt;這樣oracle會自動的将'10' --&gt;10 create table t2 (id varchar2(10)); insert into t2 values(1); --&gt;這樣oracle就會自動的将1 --&gt;'1'; 我們要說的是盡管oracle可以進行隐含的資料類型的轉換,但是它并不适應所有的情況,為了提高程式的可靠性,我們應該使用轉換函數進行轉換。 ? to_char 你可以使用select ename, hiredate, sal from emp where deptno = 10;顯示資訊,可是,在某些情況下,這個并不能滿足你的需求。 問題:日期是否可以顯示 時/分/秒 SQL&gt; select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss') from emp; 問題:薪水是否可以顯示指定的貨币符号 SQL&gt; yy:兩位數字的年份 2004--&gt;04 yyyy:四位數字的年份 2004年 mm:兩位數字的月份 8月--&gt;08 dd:兩位數字的天 30号--&gt;30 hh24: 8點--&gt;20 hh12:8點--&gt;08 mi、ss--&gt;顯示分鐘\秒 9:顯示數字,并忽略前面0 0:顯示數字,如位數不足,則用0補齊 .:在指定位置顯示小數點 ,:在指定位置顯示逗号 $:在數字前加美元 L:在數字前面加本地貨币符号 C:在數字前面加國際貨币符号 G:在指定位置顯示組分隔符、 D:在指定位置顯示小數點符号(.) 問題:顯示薪水的時候,把本地貨币機關加在前面 SQL&gt; select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss'), to_char(sal,'L99999.99') from emp; 問題:顯示1980年入職的所有員工 SQL&gt; select * from emp where to_char(hiredate, 'yyyy')=1980;
Oracle 筆記
21
問題:顯示所有12月份入職的員工 SQL&gt; select * from emp where to_char(hiredate, 'mm')=12; ? to_date 函數to_date用于将字元串轉換成date類型的資料。 問題:能否按照中國人習慣的方式年—月—日添加日期。 系統函數 ? sys_context 1)terminal:目前會話客戶所對應的終端的标示符 2)lanuage: 語言 3)db_name: 目前資料庫名稱 4)nls_date_format: 目前會話客戶所對應的日期格式 5)session_user: 目前會話客戶所對應的資料庫使用者名 6)current_schema: 目前會話客戶所對應的預設方案名 7)host: 傳回資料庫所在主機的名稱 通過該函數,可以查詢一些重要資訊,比如你正在使用哪個資料庫? select sys_context('USERENV','db_name') from dual; 注意:USERENV是固定的,不能改的,db_name可以換成其它,比如select sys_context('USERENV','lanuage') from dual;又比如select sys_context('USERENV','current_schema') from dual;
10.資料庫管理,表的邏輯備份與恢複
内容介紹 1.上節回顧 2.資料庫管理者 3.資料庫(表)的邏輯備份與恢複 √ 4.資料字典和動态性能視圖 √ 5.管理表空間和資料檔案 √ 期望目标 1.了解oracle管理者的基本職責 2.掌握備份和恢複資料庫/表的方法 3.了解表空間、資料字典、性能視圖 資料庫管理者 ? 介紹 每個oracle資料庫應該至少有一個資料庫管理者(dba),對于一個小的資料庫,一個dba就夠了,但是對于一個大的資料庫可能需要多個dba分擔不同的管理職責。那麼一個資料庫管理者的主要工作是什麼呢: ? 職責 1.安裝和更新oracle資料庫 2.建庫,表空間,表,視圖,索引? 3.制定并實施備份和恢複計劃 4.資料庫權限管理,調優,故障排除 5.對于進階dba,要求能參與項目開發,會編寫sql語句、存儲過程、觸發器、規則、限制、包 ? 管理資料庫的使用者主要是sys和system (sys好像是董事長,system好像是總經理,董事長比總經理大,但是通常是總經理幹事) 在前面我們已經提到這兩個使用者,差別主要是: 1.最重要的差別,存儲的資料的重要性不同
Oracle 筆記
22
sys:所有oracle的資料字典的基表和視圖都存放在sys使用者中,這些基表和視圖對于oracle的運作是至關重要的,由資料庫自己維護,任何使用者都不能手動更改。sys使用者擁有dba,sysdba,sysoper角色或權限,是oracle權限最高的使用者。 system:用于存放次一級的内部資料,如oracle的一些特性或工具的管理資訊。system使用者擁有dba,sysdba角色或系統權限。 看圖: sysdba可以建資料庫,sysope不能建資料庫 2. 其次的差別,權限的不同。 sys使用者必須以as sysdba或as sysoper形式登入。不能以normal方式登入資料庫 system如果正常登入,它其實就是一個普通的dba使用者,但是如果以as sysdba登入,其結果實際上它是作為sys使用者登入的,從登入資訊裡面我們可以看出來。 sysdba和sysoper權限差別圖,看圖: sysdba&gt;sysoper&gt;dba 可以看到:隻要是sysoper擁有的權限,sysdba都有;藍色是它們差別的地方。(它們的最大差別是:sysdba可以建立資料庫,sysoper不可以建立資料庫) ? dba權限的使用者 dba使用者是指具有dba角色的資料庫使用者。特權使用者可以執行啟動執行個體,關閉執行個體等特殊操作,而dba使用者隻有在啟動資料庫後才能執行各種管理工作。 (相當于說dba連startup和shutdown這兩個權限都沒有) 兩個主要的使用者,三個重要權限,他們的差別和聯系,大家要弄清楚 管理初始化參數 ? 管理初始化參數(調優的一個重要知識點,憑什麼可以對資料庫進行調優呢?是因為它可以對資料庫的一些參數進行修改修正) 初始化參數用于設定執行個體或是資料庫的特征。oracle9i提供了200多個初始化參數,并且每個初始化參數都有預設值。 ? 顯示初始化參數 (1) show parameter指令 ? 如何修改參數 需要說明的如果你希望修改這些初始化的參數,可以到檔案D:\oracle\admin\myoral\pfile\init.ora檔案中去修改比如要修改執行個體的名字 資料庫(表)的邏輯備份與恢複 介紹 ? 介紹 邏輯備份是指使用工具export将資料對象的結構和資料導出到檔案的過程,邏輯恢複是指當資料庫對象被誤操作而損壞後使用工具import利用備份的檔案把資料對象導入到資料庫的過程。 實體備份即可在資料庫open的狀态下進行也可在關閉資料庫後進行,但是邏輯備份和恢複隻能在open的狀态下進行。 看圖: ? 導出 導出具體的分為:導出表,導出方案,導出資料庫三種方式。 導出使用exp指令來完成的,該指令常用的選項有: userid: 用于指定執行導出操作的使用者名,密碼,連接配接字元串 tables: 用于指定執行導出操作的表 owner: 用于指定執行導出操作的方案 full=y: 用于指定執行導出操作的資料庫 inctype: 用于指定執行導出操作的增量類型 rows: 用于指定執行導出操作是否要導出表中的資料 file: 用于指定導出檔案名
Oracle 筆記
23
? 導出表 1.導出自己的表 exp userid=scott/[email protected] tables=(emp,dept) file=d:\e1.dmp 2.導出其它方案的表 如果使用者要導出其它方案的表,則需要dba的權限或是exp_full_database的權限,比如system就可以導出scott的表 E:\oracle\ora92\bin&gt;exp userid=system/[email protected] tables=(scott.emp) file=d:\e2.emp 特别說明:在導入和導出的時候,要到oracle目錄的bin目錄下。 3. 導出表的結構 exp userid=scott/[email protected] tables=(emp) file=d:\e3.dmp rows=n 4. 使用直接導出方式 exp userid=scott/[email protected] tables=(emp) file=d:\e4.dmp direct=y 這種方式比預設的正常方式速度要快,當資料量大時,可以考慮使用這樣的方法。 這時需要資料庫的字元集要與用戶端字元集完全一緻,否則會報錯... ? 導出方案 導出方案是指使用export工具導出一個方案或是多個方案中的所有對象(表,索引,限制...)和資料。并存放到檔案中。 1. 導出自己的方案 exp userid=scott/[email protected] owner=scott file=d:\scott.dmp 2. 導出其它方案 如果使用者要導出其它方案,則需要dba的權限或是exp_full_database的權限,比如system使用者就可以導出任何方案 exp userid=system/[email protected] owner=(system,scott) file=d:\system.dmp ? 導出資料庫 導出資料庫是指利用export導出所有資料庫中的對象及資料,要求該使用者具有dba的權限或者是exp_full_database權限 增量備份(好處是第一次備份後,第二次備份就快很多了) exp userid=system/[email protected] full=y inctype=complete file=d:\all.dmp 導入 ? 介紹 導入就是使用工具import将檔案中的對象和資料導入到資料庫中,但是導入要使用的檔案必須是export所導出的檔案。與導出相似,導入也分為導入表,導入方案,導入資料庫三種方式。 imp常用的選項有 userid: 用于指定執行導入操作的使用者名,密碼,連接配接字元串 tables: 用于指定執行導入操作的表 formuser: 用于指定源使用者 touser: 用于指定目标使用者 file: 用于指定導入檔案名 full=y: 用于指定執行導入整個檔案 inctype: 用于指定執行導入操作的增量類型 rows: 指定是否要導入表行(資料) ignore: 如果表存在,則隻導入資料 ? 導入表 1. 導入自己的表 imp userid=scott/[email protected] tables=(emp) file=d:\xx.dmp 2. 導入表到其它使用者 要求該使用者具有dba的權限,或是imp_full_database imp userid=system/[email protected] tables=(emp) file=d:\xx.dmp touser=scott 3. 導入表的結構
Oracle 筆記
24
隻導入表的結構而不導入資料 imp userid=scott/[email protected] tables=(emp) file=d:\xx.dmp rows=n 4. 導入資料 如果對象(如比表)已經存在可以隻導入表的資料 imp userid=scott/[email protected] tables=(emp) file=d:\xx.dmp ignore=y ? 導入方案 導入方案是指使用import工具将檔案中的對象和資料導入到一個或是多個方案中。如果要導入其它方案,要求該使用者具有dba的權限,或者imp_full_database 1. 導入自身的方案 imp userid=scott/tiger file=d:\xxx.dmp 2. 導入其它方案 要求該使用者具有dba的權限 imp userid=system/manager file=d:\xxx.dmp fromuser=system touser=scott ? 導入資料庫 在預設情況下,當導入資料庫時,會導入所有對象結構和資料,案例如下: imp userid=system/manager full=y file=d:\xxx.dmp
11.資料字典和動态性能視圖 介紹:資料字典是什麼 資料字典是oracle資料庫中最重要的組成部分,它提供了資料庫的一些系統資訊。 動态性能視圖記載了例程啟動後的相關資訊。 ? 資料字典 資料字典記錄了資料庫的系統資訊,它是隻讀表和視圖的集合,資料字典的所有者為sys使用者。 使用者隻能在資料字典上執行查詢操作(select語句),而其維護和修改是由系統自動完成的。 這裡我們談談資料字典的組成:資料字典包括資料字典基表和資料字典視圖,其中基表存儲資料庫的基本資訊,普通使用者不能直接通路資料字典的基表。資料字典視圖是基于資料字典基表所建立的視圖,普通使用者可以通過查詢資料字典視圖取得系統資訊。資料字典視圖主要包括user_xxx,all_xxx,dba_xxx三種類型。 ? user_tables; 用于顯示目前使用者所擁有的所有表,它隻傳回使用者所對應方案的所有表 比如:select table_name from user_tables; ? all_tables; 用于顯示目前使用者可以通路的所有表,它不僅會傳回目前使用者方案的所有表,還會傳回目前使用者可以通路的其它方案的表: 比如:select table_name from all_tables; ? dba_tables; 它會顯示所有方案擁有的資料庫表。但是查詢這種資料庫字典視圖,要求使用者必須是dba角色或是有select any table系統權限。 例如:當用system使用者查詢資料字典視圖dba_tables時,會傳回system,sys,scott...方案所對應的資料庫表。 ? 使用者名,權限,角色 在建立使用者時,oracle會把使用者的資訊存放到資料字典中,當給使用者授予權限或是角色時,oracle會将權限和角色的資訊存放到資料字典。 通過查詢dba_users可以顯示所有資料庫使用者的詳細資訊; 通過查詢資料字典視圖dba_sys_privs,可以顯示使用者所具有的系統權限; 通過查詢資料字典視圖dba_tab_privs,可以顯示使用者具有的對象權限; 通過查詢資料字典dba_col_privs可以顯示使用者具有的列權限; 通過查詢資料庫字典視圖dba_role_privs可以顯示使用者所具有的角色。
Oracle 筆記
25
這裡給大家再講講角色和權限的關系。 例如:要檢視scott具有的角色,可查詢dba_role_privs; SQL&gt; select * from dba_role_privs where grantee='SCOTT'; //查詢orale中所有的系統權限,一般是dba select * from system_privilege_map order by name; //查詢oracle中所有對象權限,一般是dba select distinct privilege from dba_tab_privs; //查詢oracle中所有的角色,一般是dba select * from dba_roles; //查詢資料庫的表空間 select tablespace_name from dba_tablespaces; 問題1:如何查詢一個角色包括的權限? a.一個角色包含的系統權限 select * from dba_sys_privs where grantee='角色名' 另外也可以這樣檢視: select * from role_sys_privs where role='角色名' b.一個角色包含的對象權限 select * from dba_tab_privs where grantee='角色名' 問題2:oracle究竟有多少種角色? SQL&gt; select * from dba_roles; 問題3:如何檢視某個使用者,具有什麼樣的角色? select * from dba_role_privs where grantee='使用者名' ? 顯示目前使用者可以通路的所有資料字典視圖。 select * from dict where comments like '%grant%'; ? 顯示目前資料庫的全稱 select * from global_name; ? 其它說明 資料字典記錄有oracle資料庫的所有系統資訊。通過查詢資料字典可以取得以下系統資訊:比如 1.對象定義情況 2.對象占用空間大小 3.列資訊 4.限制資訊 ... 但是因為這些個資訊,可以通過pl/sql developer工具查詢得到,是以這裡我就飄過。 ? 動态性能視圖 動态性能視圖用于記錄目前例程的活動資訊,當啟動oracle server時,系統會建立動态性能視圖;當停止oracle server時,系統會删除動态性能視圖。oracle的所有動态性能視圖都是以v_$開始的,并且oracle為每個動态性能視圖都提供了相應的同義詞,并且其同義詞是以V$開始的,例如v_$datafile的同義詞為v$datafile;動态性能視圖的所有者為sys,一般情況下,由dba或是特權使用者來查詢動态性能視圖。 因為這個在實際中用的較少,是以飛過。
12.資料庫管理 -- 管理表空間和資料檔案 ? 介紹 表空間是資料庫的邏輯組成部分。從實體上講,資料庫資料存放在資料檔案中;從邏輯上講,資料庫則是存放在表空間中,表空間由一個或多個資料檔案組成。
Oracle 筆記
26
資料庫的邏輯結構 ? 介紹 oracle中邏輯結構包括表空間、段、區和塊。 說明一下資料庫由表空間構成,而表空間又是由段構成,而段又是由區構成,而區又是由oracle塊構成的這樣的一種結構,可以提高資料庫的效率。 為了讓大家明白,我們畫圖說明邏輯關系:看圖: 表空間 ? 介紹 表空間用于從邏輯上組織資料庫的資料。資料庫邏輯上是由一個或是多個表空間組成的。通過表空間可以達到以下作用: 1. 控制資料庫占用的磁盤空間 2. dba可以将不同資料類型部署到不同的位置,這樣有利于提高i/o性能,同時利于備份和恢複等管理操作。 ? 建立表空間 建立表空間是使用crate tablespace指令完成的,需要注意的是,一般情況下,建立表空間是特權使用者或是dba來執行的,如果用其它使用者來建立表空間,則使用者必須要具有create tablespace的系統權限。 ? 建立資料表空間 在建立資料庫後,為便于管理表,最好建立自己的表空間 create tablespace data01 datafile 'd:\test\dada01.dbf' size 20m uniform size 128k; 說明:執行完上述指令後,會建立名稱為data01的表空間,并為該表空間建立名稱為data01.dbf的資料檔案,區的大小為128k ? 使用資料表空間 create table mypart(deptno number(4), dname varchar2(14), loc varchar2(13)) tablespace data01; ? 改變表空間的狀态 當建立表空間時,表空間處于聯機的(online)狀态,此時該表空間是可以通路的,并且該表空間是可以讀寫的,即可以查詢該表空間的資料,而且還可以在表空間執行各種語句。但是在進行系統維護或是資料維護時,可能需要改變表空間的狀态。一般情況下,由特權使用者或是dba來操作。 1. 使表空間脫機 alter tablespace 表空間名 offline; 2. 使表空間聯機 alter tablespace 表空間名 online; 3. 隻讀表空間 當建立表空間時,表空間可以讀寫,如果不希望在該表空間上執行update,delete,insert操作,那麼可以将表空間修改為隻讀 alter tablespace 表空間名 read only; (修改為可寫是 alter tablespace 表空間名 read write;) ? 改變表空間的狀态 我們給大家舉一個執行個體,說明隻讀特性: 1. 知道表空間名,顯示該表空間包括的所有表 select * from all_tables where tablespace_name=’表空間名’; 2. 知道表名,檢視該表屬于那個表空間 select tablespace_name, table_name from user_tables where table_name=’emp’; 通過2.我們可以知道scott.emp是在system這個表空間上,現在我們可以将system改為隻讀的但是我們不會成功,因為system是系統表空間,如果是普通表空間,那麼我們就可以将其設為隻讀的,給大家做一個示範,可以加強了解。 3. 4. 使表空間可讀寫 alter tablespace 表空間名 read write; ? 删除表空間
Oracle 筆記
27
一般情況下,由特權使用者或是dba來操作,如果是其它使用者操作,那麼要求使用者具有drop tablespace系統權限。 drop tablespace ‘表空間’ including contents and datafiles; 說明:including contents表示删除表空間時,删除該空間的所有資料庫對象,而datafiles表示将資料庫檔案也删除。 ? 擴充表空間 表空間是由資料檔案組成的,表空間的大小實際上就是資料檔案相加後的大小。那麼我們可以想象,假定表employee存放到data01表空間上,初始大小就是2M,當資料滿2M空間後,如果在向employee表插入資料,這樣就會顯示空間不足的錯誤。 案例說明: 1. 建立一個表空間 sp01 2. 在該表空間上建立一個普通表 mydment 其結構和dept一樣 3. 向該表中加入資料 insert into mydment select * from dept; 4. 當一定時候就會出現無法擴充的問題,怎麼辦? 5. 就擴充該表空間,為其增加更多的存儲空間。有三種方法: 1. 增加資料檔案 SQL&gt; alter tablespace sp01 add datafile ‘d:\test\sp01.dbf’ size 20m; 2. 增加資料檔案的大小 SQL&gt; alter tablespace 表空間名 ‘d:\test\sp01.dbf’ resize 20m; 這裡需要注意的是資料檔案的大小不要超過500m。 3. 設定檔案的自動增長。 SQL&gt; alter tablespace 表空間名 ‘d:\test\sp01.dbf’ autoextend on next 10m maxsize 500m; ? 移動資料檔案 有時,如果你的資料檔案所在的磁盤損壞時,該資料檔案将不能再使用,為了能夠重新使用,需要将這些檔案的副本移動到其它的磁盤,然後恢複。 下面以移動資料檔案sp01.dbf為例來說明: 1. 确定資料檔案所在的表空間 select tablespace_name from dba_data_files where file_name=’d:\test\sp01.dbf’; 2. 使表空間脫機 確定資料檔案的一緻性,将表空間轉變為offline的狀态。 alter tablespace sp01(表空間名) offline; 3. 使用指令移動資料檔案到指定的目标位置 host move d:\test\sp01.dbf c:\test\sp01.dbf 4. 執行alter tablespace指令 在實體上移動了資料後,還必須執行alter tablespace指令對資料庫檔案進行邏輯修改: alter tablespace sp01 rename datafile ‘d:\test\sp01.dbf’ to ‘c:\test\sp01.dbf’; 5. 使得表空間聯機 在移動了資料檔案後,為了使使用者可以通路該表空間,必須将其轉變為online狀态。 alter tablespace sp01(表空間名) online; ? 顯示表空間資訊 查詢資料字典視圖dba_tablespaces,顯示表空間的資訊: select tablespace_name from dba_tablespaces; ? 顯示表空間所包含的資料檔案 查詢資料字典視圖dba_data_files,可顯示表空間所包含的資料檔案,如下: select file_name, bytes from dba_data_files where tablespce_name=’表空間’; ? 表空間小結 1. 了解表空間和資料檔案的作用
Oracle 筆記
28
2. 掌握常用表空間,undo表空間和臨時表空間的建立方法 3. 了解表空間的各個狀态(online, offline, read write, read only)的作用,及如何改變表空間的狀态的方法。 4. 了解移動資料檔案的原因,及使用alter tablespace 和alter datatable指令移動資料檔案的方法。 ? 其它表空間 除了最常用的資料表空間外,還有其它類型表空間: 1. 索引表空間 2. undo表空間 3. 臨時表空間 4. 非标準塊的表空間 這幾種表空間,大家夥可以自己參考書籍研究,這裡我就不講。 ? 其它說明 關于表空間的組成部分 段/區/塊,我們在後面給大家講解。
13.限制 玩轉oracle實戰教程(第五天) 期望目标 1.掌握維護oracle資料完整性的技巧 2.了解索引概念,會建立索引 3.管理oracle的權限和角色 維護資料的完整性 ? 介紹 資料的完整性用于確定資料庫資料遵從一定的商業和邏輯規則,在oracle中,資料完整性可以使用限制、觸發器、應用程式(過程、函數)三種方法來實作,在這三種方法中,因為限制易于維護,并且具有最好的性能,是以作為維護資料完整性的首選。 限制 ? 限制 限制用于確定資料庫資料滿足特定的商業規則。在oracle中,限制包括:not null、 unique, primary key, foreign key,和check五種。 使用 ? not null(非空) 如果在列上定義了not null,那麼當插入資料時,必須為列提供資料。 ? unique(唯一) 當定義了唯一限制後,該列值是不能重複的,但是可以為null。 ? primary key(主鍵) 用于唯一的标示表行的資料,當定義主鍵限制後,該列不但不能重複而且不能為null。 需要說明的是:一張表最多隻能有一個主鍵,但是可以有多個unqiue限制。 ? foreign key(外鍵) 用于定義主表和從表之間的關系。外鍵限制要定義在從表上,主表則必須具有主鍵限制或是unique限制,當定義外鍵限制後,要求外鍵列資料必須在主表的主鍵列存在或是為null。 ? check 用于強制行資料必須滿足的條件,假定在sal列上定義了check限制,并要求sal列值在1000-2000之間如果不在1000-2000之間就會提示出錯。 ? 商店售貨系統表設計案例 現有一個商店的資料庫,記錄客戶及其購物情況,由下面三個表組成:商品goods(商品号goodsId,商品名 goodsName,單價 unitprice,商品類别category,供應商provider); 客戶customer(客戶号customerId,姓名name,住在address,電郵email,性别sex,身份證cardId);
Oracle 筆記
29
購買purchase(客戶号customerId,商品号goodsId,購買數量nums); 請用SQL語言完成下列功能: 1. 建表,在定義中要求聲明: (1). 每個表的主外鍵; (2). 客戶的姓名不能為空值; (3). 單價必須大于0,購買數量必須在1到30之間; (4). 電郵不能夠重複; (5). 客戶的性别必須是 男 或者 女,預設是男; SQL&gt; create table goods(goodsId char(8) primary key, --主鍵 goodsName varchar2(30), unitprice number(10,2) check(unitprice&gt;0), category varchar2(8), provider varchar2(30) ); SQL&gt; create table customer( customerId char(8) primary key, --主鍵 name varchar2(50) not null, --不為空 address varchar2(50), email varchar2(50) unique, sex char(2) default '男' check(sex in ('男','女')), -- 一個char能存半個漢字,兩位char能存一個漢字 cardId char(18) ); SQL&gt; create table purchase( customerId char(8) references customer(customerId), goodsId char(8) references goods(goodsId), nums number(10) check (nums between 1 and 30) ); 表是預設建在SYSTEM表空間的 維護 ? 商店售貨系統表設計案例(2) 如果在建表時忘記建立必要的限制,則可以在建表後使用alter table指令為表增加限制。但是要注意:增加not null限制時,需要使用modify選項,而增加其它四種限制使用add選項。 1. 增加商品名也不能為空 SQL&gt; alter table goods modify goodsName not null; 2. 增加身份證也不能重複 SQL&gt; alter table customer add constraint xxxxxx unique(cardId); 3. 增加客戶的住址隻能是’海澱’,’朝陽’,’東城’,’西城’,’通州’,’崇文’,’昌平’; SQL&gt; alter table customer add constraint yyyyyy check (address in (’海澱’,’朝陽’,’東城’,’西城’,’通州’,’崇文’,’昌平’)); ? 删除限制 當不再需要某個限制時,可以删除。 alter table 表名 drop constraint 限制名稱; 特别說明一下: 在删除主鍵限制的時候,可能有錯誤,比如: alter table 表名 drop primary key; 這是因為如果在兩張表存在主從關系,那麼在删除主表的主鍵限制時,必須帶上cascade選項 如像:
Oracle 筆記
30
alter table 表名 drop primary key cascade; ? 顯示限制資訊 1.顯示限制資訊 通過查詢資料字典視圖user_constraints,可以顯示目前使用者所有的限制的資訊。 select constraint_name, constraint_type, status, validated from user_constraints where table_name = '表名'; 2.顯示限制列 通過查詢資料字典視圖user_cons_columns,可以顯示限制所對應的表列資訊。 select column_name, position from user_cons_columns where constraint_name = '限制名'; 3.當然也有更容易的方法,直接用pl/sql developer檢視即可。簡單示範一下下... 表級定義 列級定義 ? 列級定義 列級定義是在定義列的同時定義限制。 如果在department表定義主鍵限制 create table department4(dept_id number(12) constraint pk_department primary key, name varchar2(12), loc varchar2(12)); ? 表級定義 表級定義是指在定義了所有列後,再定義限制。這裡需要注意: not null限制隻能在列級上定義。 以在建立employee2表時定義主鍵限制和外鍵限制為例: create table employee2(emp_id number(4), name varchar2(15), dept_id number(2), constraint pk_employee primary key (emp_id), constraint fk_department foreign key (dept_id) references department4(dept_id));
14.Oracle索引、權限
管理索引-原理介紹 ? 介紹 索引是用于加速資料存取的資料對象。合理的使用索引可以大大降低i/o次數,進而提高資料通路性能。索引有很多種我們主要介紹常用的幾種: 為什麼添加了索引後,會加快查詢速度呢? 建立索引 ? 單列索引 單列索引是基于單個列所建立的索引,比如: create index 索引名 on 表名(列名); ? 複合索引 複合索引是基于兩列或是多列的索引。在同一張表上可以有多個索引,但是要求列的組合必須不同,比如: create index emp_idx1 on emp (ename, job); create index emp_idx1 on emp (job, ename); 使用原則 ? 使用原則 1. 在大表上建立索引才有意義 2. 在where子句或是連接配接條件上經常引用的列上建立索引 3. 索引的層次不要超過4層 這裡能不能給學生示範這個效果呢? 如何建構一個大表呢?
Oracle 筆記
31
索引的缺點 ? 索引缺點分析 索引有一些先天不足: 1. 建立索引,系統要占用大約為表1.2倍的硬碟和記憶體空間來儲存索引。 2. 更新資料的時候,系統必須要有額外的時間來同時對索引進行更新,以維持資料和索引的一緻性。 實踐表明,不恰當的索引不但于事無補,反而會降低系統性能。因為大量的索引在進行插入、修改和删除操作時比沒有索引花費更多的系統時間。 比如在如下字段建立索引應該是不恰當的: 1. 很少或從不引用的字段; 2. 邏輯型的字段,如男或女(是或否)等。 綜上所述,提高查詢效率是以消耗一定的系統資源為代價的,索引不能盲目的建立,這是考驗一個DBA是否優秀的很重要的名額。 其它索引 ? 介紹 按照資料存儲方式,可以分為B*樹、反向索引、位圖索引; 按照索引列的個數分類,可以分為單列索引、複合索引; 按照索引列值的唯一性,可以分為唯一索引和非唯一索引。 此外還有函數索引,全局索引,分區索引... 對于索引我還要說: 在不同的情況,我們會在不同的列上建立索引,甚至建立不同種類的索引,請記住,技術是死的,人是活的。比如: B*樹索引建立在重複值很少的列上,而位圖索引則建立在重複值很多、不同值相對固定的列上。 顯示索引資訊 ? 顯示表的所有索引 在同一張表上可以有多個索引,通過查詢資料字典視圖dba_indexs和user_indexs,可以顯示索引資訊。其中dba_indexs用于顯示資料庫所有的索引資訊,而user_indexs用于顯示目前使用者的索引資訊: select index_name, index_type from user_indexes where table_name = '表名'; ? 顯示索引列 通過查詢資料字典視圖user_ind_columns,可以顯示索引對應的列的資訊 select table_name, column_name from user_ind_columns where index_name = 'IND_ENAME'; ? 你也可以通過pl/sql developer工具檢視索引資訊 管理權限和角色 介紹 ? 介紹 這一部分我們主要看看oracle中如何管理權限和角色,權限和角色的差別在那裡。 當剛剛建立使用者時,使用者沒有任何權限,也不能執行任何操作。如果要執行某種特定的資料庫操作,則必須為其授予系統的權限;如果使用者要通路其它方案的對象,則必須為其授予對象的權限。為了簡化權限的管理,可以使用角色。這裡我們會詳細的介紹。看圖: 權限 ? 權限 權限是指執行特定類型sql指令或是通路其它方案對象的權利,包括系統權限和對象權限兩種。 系統權限 ? 系統權限介紹 系統權限是指執行特定類型sql指令的權利。它用于控制使用者可以執行的一個或是一組資料庫操作。比如當使用者具有create table權限時,可以在其方案中建表,當使用者具有create any table權限時,可以在任何方案中建表。oracle提供了100多種系統權限。
Oracle 筆記
32
常用的有: create session 連接配接資料庫 create table 建表 create view 建視圖 create public synonym 建同義詞 create procedure 建過程、函數、包 create trigger 建觸發器 create cluster 建簇 ? 顯示系統權限 oracle提供了100多種系統權限,而且oracle的版本越高,提供的系統權限就越多,我們可以查詢資料字典視圖system_privilege_map,可以顯示所有系統權限。 select * from system_privilege_map order by name; ? 授予系統權限 一般情況,授予系統權限是由dba完成的,如果用其他使用者來授予系統權限,則要求該使用者必須具有grant any privilege的系統權限。在授予系統權限時,可以帶有with admin option選項,這樣,被授予權限的使用者或是角色還可以将該系統權限授予其它的使用者或是角色。為了讓大家快速了解,我們舉例說明: 1.建立兩個使用者ken,tom。初始階段他們沒有任何權限,如果登入就會給出錯誤的資訊。 create user ken identfied by ken; 2 給使用者ken授權 1). grant create session, create table to ken with admin option; 2). grant create view to ken; 3 給使用者tom授權 我們可以通過ken給tom授權,因為with admin option是加上的。當然也可以通過dba給tom授權,我們就用ken給tom授權: 1. grant create session, create table to tom; 2. grant create view to ken; --ok嗎?不ok ? 回收系統權限 一般情況下,回收系統權限是dba來完成的,如果其它的使用者來回收系統權限,要求該使用者必須具有相應系統權限及轉授系統權限的選項(with admin option)。回收系統權限使用revoke來完成。 當回收了系統權限後,使用者就不能執行相應的操作了,但是請注意,系統權限級聯收回的問題?[不是級聯回收!] system ---------&gt;ken ----------&gt;tom (create session)(create session)( create session) 用system執行如下操作: revoke create session from ken; --請思考tom還能登入嗎? 答案:能,可以登入 對象權限 ? 對象權限介紹 指通路其它方案對象的權利,使用者可以直接通路自己方案的對象,但是如果要通路别的方案的對象,則必須具有對象的權限。 比如smith使用者要通路scott.emp表(scott:方案,emp:表) 常用的有: alter 修改 delete 删除 select 查詢 insert 添加 update 修改 index 索引 references 引用 execute 執行 ? 顯示對象權限 通過資料字段視圖可以顯示使用者或是角色所具有的對象權限。視圖為dba_tab_privs SQL&gt; conn system/manager; SQL&gt; select distinct privilege from dba_tab_privs; SQL&gt; select grantor, owner, table_name, privilege from dba_tab_privs where grantee = 'BLAKE';
Oracle 筆記
33
1.授予對象權限 在oracle9i前,授予對象權限是由對象的所有者來完成的,如果用其它的使用者來操作,則需要使用者具有相應的(with grant option)權限,從oracle9i開始,dba使用者(sys,system)可以将任何對象上的對象權限授予其它使用者。授予對象權限是用grant指令來完成的。 對象權限可以授予使用者,角色,和public。在授予權限時,如果帶有with grant option選項,則可以将該權限轉授給其它使用者。但是要注意with grant option選項不能被授予角色。 1.monkey使用者要操作scott.emp表,則必須授予相應的對象權限 1). 希望monkey可以查詢scott.emp表的資料,怎樣操作? grant select on emp to monkey; 2). 希望monkey可以修改scott.emp的表資料,怎樣操作? grant update on emp to monkey; 3). 希望monkey可以删除scott.emp的表資料,怎樣操作? grant delete on emp to monkey; 4). 有沒有更加簡單的方法,一次把所有權限賦給monkey? grant all on emp to monkey; 2.能否對monkey通路權限更加精細控制。(授予列權限) 1). 希望monkey隻可以修改scott.emp的表的sal字段,怎樣操作? grant update on emp(sal) to monkey 2).希望monkey隻可以查詢scott.emp的表的ename,sal資料,怎樣操作? grant select on emp(ename,sal) to monkey ... 3.授予alter權限 如果black使用者要修改scott.emp表的結構,則必須授予alter對象權限 SQL&gt; conn scott/tiger SQL&gt; grant alter on emp to blake; 當然也可以用system,sys來完成這件事。 4.授予execute權限 如果使用者想要執行其它方案的包/過程/函數,則須有execute權限。 比如為了讓ken可以執行包dbms_transaction,可以授予execute權限。 SQL&gt; conn system/manager SQL&gt; grant execute on dbms_transaction to ken; 5.授予index權限 如果想在别的方案的表上建立索引,則必須具有index對象權限。 如果為了讓black可以在scott.emp表上建立索引,就給其index的對象權限 SQL&gt; conn scott/tiger SQL&gt; grant index on scott.emp to blake; 6.使用with grant option選項 該選項用于轉授對象權限。但是該選項隻能被授予使用者,而不能授予角色 SQL&gt; conn scott/tiger; SQL&gt; grant select on emp to blake with grant option; SQL&gt; conn black/shunping SQL&gt; grant select on scott.emp to jones; ? 回收對象權限 在oracle9i中,收回對象的權限可以由對象的所有者來完成,也可以用dba使用者(sys,system)來完成。 這裡要說明的是:收回對象權限後,使用者就不能執行相應的sql指令,但是要注意的是對象的權限是否會被級聯收回?【級
Oracle 筆記
34
聯回收】 如:scott-------------&gt;blake--------------&gt;jones select on emp select on emp select on emp SQL&gt; conn scott/[email protected] SQL&gt; revoke select on emp from blake 請大家思考,jones能否查詢scott.emp表資料。 答案:查不了了(和系統權限不一樣,剛好相反)
15.角色
? 介紹 角色就是相關權限的指令集合,使用角色的主要目的就是為了簡化權限的管理,假定有使用者a,b,c為了讓他們都擁有權限 1. 連接配接資料庫 2. 在scott.emp表上select,insert,update。 如果采用直接授權操作,則需要進行12次授權。 因為要進行12次授權操作,是以比較麻煩喔!怎麼辦? 如果我們采用角色就可以簡化: 首先将creat session,select on scott.emp,insert on scott.emp, update on scott.emp授予角色,然後将該角色授予a,b,c使用者,這樣就可以三次授權搞定。 角色分為預定義和自定義角色兩類: ? 預定義角色 預定義角色是指oracle所提供的角色,每種角色都用于執行一些特定的管理任務,下面我們介紹常用的預定義角色connect,resource,dba 1.connect角色 connect角色具有一般應用開發人員需要的大部分權限,當建立了一個使用者後,多數情況下,隻要給使用者授予connect和resource角色就夠了,那麼connect角色具有哪些系統權限呢? alter session create cluster create database link create session create table create view create sequence 2.resource角色 resource角色具有應用開發人員所需要的其它權限,比如建立存儲過程,觸發器等。這裡需要注意的是resource角色隐含了unlimited tablespace系統權限。 resource角色包含以下系統權限: create cluster create indextype create table create sequence create type create procedure create trigger 3.dba角色
Oracle 筆記
35
dba角色具有所有的系統權限,及with admin option選項,預設的dba使用者為sys和system,它們可以将任何系統權限授予其他使用者。但是要注意的是dba角色不具備sysdba和sysoper的特權(啟動和關閉資料庫)。 ? 自定義角色 顧名思義就是自己定義的角色,根據自己的需要來定義。一般是dba來建立,如果用别的使用者來建立,則需要具有create role的系統權限。在建立角色時可以指定驗證方式(不驗證,資料庫驗證等)。 1.建立角色(不驗證) 如果角色是公用的角色,可以采用不驗證的方式建立角色。 create role 角色名 not identified; 2.建立角色(資料庫驗證) 采用這樣的方式時,角色名、密碼存放在資料庫中。當激活該角色時,必須提供密碼。在建立這種角色時,需要為其提供密碼。 create role 角色名 identified by 密碼; 角色授權 當建立角色時,角色沒有任何權限,為了使得角色完成特定任務,必須為其授予相應的系統權限和對象權限。 1.給角色授權 給角色授予權限和給使用者授權沒有太多差別,但是要注意,系統權限的unlimited tablespace和對象權限的with grant option選項是不能授予角色的。 SQL&gt; conn system/manager; SQL&gt; grant create session to 角色名 with admin option SQL&gt; conn scott/[email protected]; SQL&gt; grant select on scott.emp to 角色名; SQL&gt; grant insert, update, delete on scott.emp to 角色名; 通過上面的步驟,就給角色授權了。 2.配置設定角色給某個使用者 一般配置設定角色是由dba來完成的,如果要以其它使用者身份配置設定角色,則要求使用者必須具有grant any role的系統權限。 SQL&gt; conn system/manager; SQL&gt; grant 角色名 to blake with admin option; 因為我給了with admin option選項,是以,blake可以把system配置設定給它的角色配置設定給别的使用者。 ? 删除角色 使用drop role,一般是dba來執行,如果其它使用者則要求該使用者具有drop any role系統權限。 SQL&gt; conn system/manager; SQL&gt; drop role 角色名; 問題:如果角色被删除,那麼被授予角色的使用者是否還具有之前角色裡的權限? 答案:不具有了 ? 顯示角色資訊 1.顯示所有角色 SQL&gt; select * from dba_roles; 2.顯示角色具有的系統權限 SQL&gt; select privilege, admin_option from role_sys_privs where role='角色名'; 3.顯示角色具有的對象權限 通過查詢資料字典視圖dba_tab_privs可以檢視角色具有的對象權限或是列的權限。 4.顯示使用者具有的角色,及預設角色 當以使用者的身份連接配接到資料庫時,oracle會自動的激活預設的角色,通過查詢資料字典視圖dba_role_privs可以顯示某個使用者具有的所有角色及目前預設的角色
Oracle 筆記
36
SQL&gt; select granted_role, default_role from dba_role_privs where grantee = ‘使用者名’; ? 精細通路控制 精細通路控制是指使用者可以使用函數,政策實作更加細微的安全通路控制。如果使用精細通路控制,則當在用戶端發出sql語句(select,insert,update,delete)時,oracle會自動在sql語句後追加謂詞(where子句),并執行新的sql語句,通過這樣的控制,可以使得不同的資料庫使用者在通路相同表時,傳回不同的資料資訊,如: 使用者 scott blake jones 政策 emp_access 資料庫表 emp 如上圖所示,通過政策emp_access,使用者scott,black,jones在執行相同的sql語句時,可以傳回不同的結果。例如:當執行select ename from emp; 時,根據實際情況可以傳回不同的結果。
16.PL/SQL 塊的結構和執行個體 韓順平.玩轉oralce第24講.plsql程式設計(1) 玩轉orcle實戰教程(第六天) 内容介紹 1.上節回顧 2.pl/sql的介紹 √ 3.pl/sql的基礎 √ 期望目标 1.了解oracle的pl/sql概念 2.掌握pl/sql程式設計技術(包括編寫過程、函數、觸發器...) pl/sql的介紹 pl/sql是什麼 pl/sql(procedural language/sql)是oracle在标準的sql語言上的擴充。pl/sql不僅允許嵌入sql語言,還可以定義變量和常量,允許使用條件語句和循環語句,允許使用例外處理各種錯誤,這樣使得它的功能變得更加強大。 為什麼學pl/sql ? 學習必要性 1.提高應用程式的運作性能 2.子產品化的設計思想【分頁的過程,訂單的過程,轉賬的過程。。】 3.減少網絡傳輸量 4.提高安全性(sql會包括表名,有時還可能有密碼,傳輸的時候會洩露。PL/SQL就不會) 為什麼PL/SQL會快呢?看圖: 不好的地方: 移植性不好(換資料庫就用不了), 用什麼編寫pl/sql ? sqlplus開發工具 sqlplus是oracle公司提供的一個工具,這個因為我們在以前介紹過的: 舉一個簡單的案例: 編寫一個存儲過程,該過程可以向某表中添加記錄。 1.建立一個簡單的表
create table mytest(name varchar2(30),passwd varchar2(30));
2.建立過程
create or replace procedure sp_pro1 is
Oracle 筆記
37
begin--執行部分
insert into mytest values('韓順平','m1234');
end;
/ replace:表示如果有sp_pro1,就替換 如何檢視錯誤資訊:show error; 如何調用該過程: 1)exec 過程名(參數值1,參數值2...); 2)call 過程名(參數值1,參數值2...); ? pl/sql developer開發工具 pl/sql developer是用于開發pl/sql塊的內建開發環境(ide),它是一個獨立的産品,而不是oracle的一個附帶品。 舉一個簡單案例: 編寫一個存儲過程,該過程可以删除某表記錄。
create or replace procedure sp_pro2 is
begin--執行部分
delete from mytest where name='韓順平';
end; pl/sql基礎 pl/sql介紹 ? 介紹 開發人員使用pl/sql編寫應用子產品時,不僅需要掌握sql語句的編寫方法,還要掌握pl/sql語句及文法規則。pl/sql程式設計可以使用變量和邏輯控制語句,進而可以編寫非常有用的功能子產品。比如:分頁存儲過程子產品、訂單處理存儲過程子產品、轉賬存儲過程子產品。而且如果使用pl/sql程式設計,我們可以輕松地完成非常複雜的查詢要求。 pl/sql可以做什麼 ? 簡單分類 |————過程(存儲過程) | |————函數 塊(程式設計)—————| |————觸發器 | |————包 編寫規範 ? 編寫規範 1.注釋 單行注釋 --
select * from emp where empno=7788; --取得員工資訊 多行注釋 /*...*/來劃分 2.标志符号的命名規範 1).當定義變量時,建議用v_作為字首v_sal 2).當定義常量時,建議用c_作為字首c_rate 3).當定義遊标時,建議用_cursor作為字尾emp_cursor 4).當定義例外時,建議用e_作為字首e_error pl/sql塊介紹 ? 介紹
Oracle 筆記
38
塊(block)是pl/sql的基本程式單元,編寫pl/sql程式實際上就是編寫pl/sql塊,要完成相對簡單的應用功能,可能隻需要編寫一個pl/sql塊,但是如果想要實作複雜的功能,可能需要在一個pl/sql塊中嵌套其它的pl/sql塊。 ? 塊結構示意圖 pl/sql塊由三個部分構成:定義部分,執行部分,例外處理部分。 如下所示: declare /*定義部分——定義常量、變量、遊标、例外、複雜資料類型*/ begin /*執行部分——要執行的pl/sql語句和sql語句*/ exception /*例外處理部分——處理運作的各種錯誤*/ end; 定義部分是從declare開始的,該部分是可選的; 執行部分是從begin開始的,該部分是必須的; 例外處理部分是從exception開始的,該部分是可選的。 可以和java程式設計結構做一個簡單的比較。 pl/sql塊的執行個體(1) ? 執行個體1-隻包括執行部分的pl/sql塊
set serveroutput on --打開輸出選項
begin
dbms_output.put_line('hello');
end;
相關說明: dbms_output是oracle所提供的包(類似java的開發包),該包包含一些過程,put_line就是dbms_output包的一個過程。 pl/sql塊的執行個體(2) ? 執行個體2-包含定義部分和執行部分的pl/sql塊
declare
v_ename varchar2(5); --定義字元串變量
begin
select ename into v_ename from emp where empno=&amp;aa;
dbms_output.put_line('雇員名:'||v_ename);
end;
/ 如果要把薪水也顯示出來,那麼執行部分就應該這麼寫:
select ename,sal into v_ename,v_sal from emp where empno=&amp;aa;
相關說明: &amp; 表示要接收從控制台輸入的變量。 pl/sql塊的執行個體(3) ? 執行個體3-包含定義部分,執行部分和例外處理部分 為了避免pl/sql程式的運作錯誤,提高pl/sql的健壯性,應該對可能的錯誤進行處理,這個很有必要。 1.比如在執行個體2中,如果輸入了不存在的雇員号,應當做例外處理。 2.有時出現異常,希望用另外的邏輯處理,[網示] 我們看看如何完成1的要求。 相關說明: oracle事先預定義了一些例外,no_data_found就是找不到資料的例外。
Oracle 筆記
39
declare
--定義變量
v_ename varchar2(5);
v_sal number(7,2);
begin
--執行部分
select ename,sal into v_ename,v_sal from emp where empno=&amp;aa;
--在控制台顯示使用者名
dbms_output.put_line('使用者名是:'||v_ename||' 工資:'||v_sal);
--異常處理
exception
when no_data_found then
dbms_output.put_line('朋友,你的編号輸入有誤!');
end;
/
17.pl/sql分類 -- 過程,函數,包,觸發器
? 過程 過程用于執行特定的操作,當建立過程時,既可以指定輸入參數(in),也可以指定輸出參數(out), 通過在過程中使用輸入參數,可以将資料傳遞到執行部分;通過使用輸出參數,可以将執行部分的資料傳遞到應用環境。在sqlplus中可以使用create procedure指令來建立過程。 執行個體如下: 1.請考慮編寫一個過程,可以輸入雇員名,新工資,可修改雇員的工資 2.如何調用過程有兩種方法; exec call 3.如何在java程式中調用一個存儲過程 問題:如何使用過程傳回值? 特别說明: 對于過程我們會在以後給大家詳細具體的介紹,現在請大家先有一個概念。 create procedure sp_pro3(spName varchar2, newSal number) is --不要寫成number(3,2),表明類型就可以了,不需要大小。就好像Java寫方法時的參數一樣
begin
--執行部分,根據使用者名去修改工資
update emp set sal=newSal where ename=spName;
end;
/ java程式中調用一個存儲過程 //示範java程式去調用oracle的存儲過程案例
import java.sql.*;
public class TestOraclePro{
public static void main(String[] args){
try{
//1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到連接配接
Oracle 筆記
40
Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
//3.建立CallableStatement
CallableStatement cs = ct.prepareCall("{call sp_pro3(?,?)}");
//4.給?指派
cs.setString(1,"SMITH");
cs.setInt(2,10);
//5.執行
cs.execute();
//關閉
cs.close();
ct.close();
} catch(Exception e){
e.printStackTrace();
}
}
} ? 函數 函數用于傳回特定的資料,當建立函數時,在函數頭部必須包含return子句。而在函數體内必須包含return語句傳回的資料。我們可以使用create function來建立函數,實際案例:
--輸入雇員的姓名,傳回該雇員的年薪
create function annual_incomec(name varchar2)
return number is
annual_salazy number(7,2);
begin
--執行部分
select sal*12+nvl(comm, 0) into annual_salazy from emp where ename=name;
return annual_salazy;
end;
/
如果函數建立過程有編譯錯誤,可以使用show error;指令顯示錯誤 在sqlplus中調用函數
SQL&gt; var income number
SQL&gt; call annual_incomec('scott') into: income;
SQL&gt; print income 同樣我們可以在java程式中調用該函數 select annual_income('SCOTT') from dual; 這樣可以通過rs.getInt(l)得到傳回的結果。 ? 包 包用于在邏輯上組合過程和函數,它由包規範和包體兩部分組成。 1.我們可以使用create package指令來建立包。 執行個體: --建立一個包sp_package --聲明該包有一個過程update_sal --聲明該包有一個函數annual_income
Oracle 筆記
41
create package sp_package is
procedure update_sal(name varchar2, newsal number);
function annual_income(name varchar2) return number;
end; 包的規範隻包含了過程和函數的說明,但是沒有過程和函數的實作代碼。包體用于實作包規範中的過程和函數。 2.建立包體可以使用create package body指令 --給包sp_package實作包體
create or replace package body sp_package is
procedure update_sal(name varchar2, newsal number)
is
begin
update emp set sal = newsal where ename = name;
end;
function annual_income(name varchar2) return number is
annual_salary number;
begin
select sal * 12 + nvl(comm, 0) into annual_salary from emp
where ename = name;
return annual_salary;
end;
end;
/ 3.如何調用包的過程或是函數 當調用包的過程或是函數時,在過程和函數前需要帶有包名,如果要通路其它方案的包,還需要在包名前加方案名。 如: SQL&gt; call sp_package.update_sal('SCOTT', 1500); 特别說明: 包是pl/sql中非常重要的部分,我們在使用過程分頁時,将會再次體驗它的威力呵呵。 ? 觸發器 觸發器是指隐含的執行的存儲過程。當定義觸發器時,必須要指定觸發的事件和觸發的操作,常用的觸發事件包括insert,update,delete語句,而觸發操作實際就是一個pl/sql塊。可以使用create trigger來建立觸發器。 特别說明: 我們會在後面詳細為大家介紹觸發器的使用,因為觸發器是非常有用的,可維護資料庫的安全和一緻性。
18.定義并使用變量,複合類型 定義并使用變量 ? 介紹 在編寫pl/sql程式時,可以定義變量和常量;在pl/sql程式中包括有: 1.标量類型(scalar) 2.複合類型(composite) 3.參照類型(reference) 4.lob(large object) ? 标量(scalar)——常用類型 在編寫pl/sql塊時,如果要使用變量,需在定義部分定義變量。pl/sql中定義變量和常量的文法如下: identifier [constant] datatype [not null] [:=| default expr]
Oracle 筆記
42
identifier : 名稱 constant :指定常量。需要指定它的初始值,且其值是不能改變的 datatype :資料類型 not null :指定變量值不能為null := 給變量或是常量指定初始值 default 用于指定初始值 expr :指定初始值的pl/sql表達式,可以是文本值、其它變量、函數等。 ? 标量定義的案例 1.定義一個變長字元串 v_ename varchar2(10); 2.定義一個小數,範圍 -9999.99~9999.99 v_sal number(6,2); 3.定義一個小數并給一個初始值為5.4 :=是pl/sql的指派号 v_sal2 number(6,2):=5.4; 4.定義一個日期類型的資料 v_hiredate date; 5.定義一個布爾變量,不能為空,初始值為false v_valid boolean not null default false; ? 标量(scalar)——使用标量 在定義好變量後,就可以使用這些變量。這裡需要說明的是pl/sql塊為變量指派不同于其它的程式設計語言,需要在等号前面加冒号(:=) 下面以輸入員工号,顯示雇員姓名、工資、個人所得稅(稅率為0.03)為例。說明變量的使用,看看如何編寫。
declare
c_tax_rate number(3,2):=0.03;
--使用者名
v_ename varchar2(5);
v_sal number(7,2);
v_tax_sal number(7,2);
begin
--執行
select ename,sal into v_ename,v_sal from emp where empno=&amp;no;
--計算所得稅
v_tax_sal := v_sal*c_tax_rate;
--輸出
dbms_output.put_line('姓名是:'||v_ename||'工資:'||v_sal||' 交稅:'||v_tax_sal);
end;
/ ? 标量(scalar)——使用%type類型 對于上面的pl/sql塊有一個問題: 就是如果員工的姓名超過了5個字元的話,就會有錯誤,為了降低pl/sql程式的維護工作量,可以使用%type屬性定義變量,這樣它會按照資料庫列來确定你定義的變量的類型和長度。 我們看看這個怎麼使用: 辨別符名 表名.列名%type; 比如上例的v_ename,這樣定義: v_ename emp.ename%type;
Oracle 筆記
43
? 複合變量(composite)——介紹 用于存放多個值的變量。主要包括這幾種: 1.pl/sql記錄 2.pl/sql表 3.嵌套表 4.varray ? 複合類型——pl/sql記錄 類似于進階語言中的結構體,需要注意的是,當引用pl/sql記錄成員時,必須要加記錄變量作為字首(記錄變量.記錄成員)如下:
declare
--定義一個pl/sql記錄類型emp_record_type,類型包含3個資料name,salary,title。說白了,就是一個類型可以存放3個資料,主要是為了好管理
type emp_record_type is record(
name emp.ename%type,
salary emp.sal%type,
title emp.job%type);
--定義了一個sp_record變量,這個變量的類型是emp_record_type
sp_record emp_record_type;
begin
select ename, sal, job into sp_record from emp where empno = 7788;
dbms_output.put_line ('員工名:' || sp_record.name);
end; ? 複合類型-pl/sql表 相當于進階語言中的數組,但是需要注意的是在進階語言中數組的下标不能為負數,而pl/sql是可以為負數的,并且表元素的下标沒有限制。執行個體如下:
declare
--定義了一個pl/sql表類型sp_table_type,該類型是用于存放emp.ename%type
--index by binary_integer 表示下标是整數
type sp_table_type is table of emp.ename%type
index by binary_integer;
--定義了一個sp_table變量,這個變量的類型是sp_table_type
sp_table sp_table_type;
begin
select ename into sp_table(-1) from emp where empno = 7788;
dbms_output.put_line('員工名:' || sp_table(-1));
end;
說明: sp_table_type 是pl/sql表類型 emp.ename%type 指定了表的元素的類型和長度 sp_table 為pl/sql表變量 sp_table(0) 則表示下标為0的元素 注意:如果把select ename into sp_table(-1) from emp where empno = 7788;變成select ename into sp_table(-1) from emp;則運作時會出現錯誤,錯誤如下: ORA-01422:實際傳回的行數超出請求的行數 解決方法是:使用參照變量(這裡不講)
Oracle 筆記
44
? 複合變量——嵌套表(nested table) ? 複合變量——變長數組(varray) ? 參照變量——介紹 參照變量是指用于存放數值指針的變量。通過使用參照變量,可以使得應用程式共享相同對象,進而降低占用的空間。在編寫pl/sql程式時,可以使用遊标變量(ref cursor)和對象類型變量(ref obj_type)兩種參照變量類型。 ? 參照變量——ref cursor遊标變量 使用遊标時,當定義遊标時不需要指定相應的select語句,但是當使用遊标時(open時)需要指定select語句,這樣一個遊标就與一個select語句結合了。執行個體如下: 1.請使用pl/sql編寫一個塊,可以輸入部門号,并顯示該部門所有員工姓名和他的工資。 2.在1的基礎上,如果某個員工的工資低于200元,就添加100元。 1.
declare
--定義遊标sp_emp_cursor
type sp_emp_cursor is ref cursor;
--定義一個遊标變量
test_cursor sp_emp_cursor;
--定義變量
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
--執行
--把test_cursor和一個select結合
open test_cursor for select ename,sal from emp where deptno=&amp;no;
--循環取出
loop
fetch test_cursor into v_ename,v_sal;
--判斷是否test_cursor為空
exit when test_cursor%notfound;
dbms_output.put_line('名字:'||v_ename||' 工資:'||v_sal);
end loop;
end;
/
19.pl/sql的進階--控制結構(分支,循環,控制)
玩轉oracle實戰教程(第七天) 内容介紹 1.上節回顧 2.pl/sql的進階 √ 3.oracle的視圖(具有安全性,和簡化複雜查詢的功能) √ 4.oracle的觸發器 √ 期望目标 1.掌握pl/sql的進階用法(能縮寫分頁過程子產品,下訂單過程子產品...) 2.會處理oracle常見的例外 3.會編寫oracle各種觸發器
Oracle 筆記
45
4.了解視圖的概念并能靈活使用視圖 pl/sql的進階--控制結構 ? 介紹 在任何計算機語言(c,java,pascal)都有各種控制語句(條件語句,循環結構,順序控制結構...)在pl/sql中也存在這樣的控制結構。 在本部分學習完成後,希望大家達到: 1.使用各種if語句 2.使用循環語句 3.使用控制語句——goto和null; ? 條件分支語句 pl/sql中提供了三種條件分支語句if—then,if – then – else,if – then – elsif – then 這裡我們可以和java語句進行一個比較 ? 簡單的條件判斷 if – then 問題:編寫一個過程,可以輸入一個雇員名,如果該雇員的工資低于2000,就給該員工工資增加10%。
create or replace procedure sp_pro6(spName varchar2) is
--定義
v_sal emp.sal%type;
begin
--執行
select sal into v_sal from emp where ename=spName;
--判斷
if v_sal&lt;2000 then
update emp set sal=sal+sal*10% where ename=spName;
end if;
end;
/ ? 二重條件分支 if – then – else 問題:編寫一個過程,可以輸入一個雇員名,如果該雇員的補助不是0就在原來的基礎上增加100;如果補助為0就把補助設為200;
create or replace procedure sp_pro6(spName varchar2) is
--定義
v_comm emp.comm%type;
begin
--執行
select comm into v_comm from emp where ename=spName;
--判斷
if v_comm&lt;&gt;0 then
update emp set comm=comm+100 where ename=spName;
else
update emp set comm=comm+200 where ename=spName;
end if;
end;
/ ? 多重條件分支 if – then – elsif – then
Oracle 筆記
46
問題:編寫一個過程,可以輸入一個雇員編号,如果該雇員的職位是PRESIDENT就給他的工資增加1000,如果該雇員的職位是MANAGER就給他的工資增加500,其它職位的雇員工資增加200。
create or replace procedure sp_pro6(spNo number) is
--定義
v_job emp.job%type;
begin
--執行
select job into v_job from emp where empno=spNo;
if v_job='PRESIDENT' then
update emp set sal=sal+1000 where empno=spNo;
elsif v_job='MANAGER' then
update emp set sal=sal+500 where empno=spNo;
else
update emp set sal=sal+200 where empno=spNo;
end if;
end;
/ ? 循環語句 –loop 是pl/sql中最簡單的循環語句,這種循環語句以loop開頭,以end loop結尾,這種循環至少會被執行一次。 案例:現有一張表users,表結構如下: 使用者id | 使用者名 | 請編寫一個過程,可以輸入使用者名,并循環添加10個使用者到users表中,使用者編号從1開始增加。
create or replace procedure sp_pro6(spName varchar2) is
--定義 :=表示指派
v_num number:=1;
begin
loop
insert into users values(v_num,spName);
--判斷是否要退出循環
exit when v_num=10;
--自增
v_num:=v_num+1;
end loop;
end;
/ ? 環語句 –while循環 基本循環至少要執行循環體一次,而對于while循環來說,隻有條件為true時,才會執行循環體語句,while循環以while...loop開始,以end loop結束。 案例:現有一張表users,表結構如下: 使用者id 使用者名 問題:請編寫一個過程,可以輸入使用者名,并循環添加10個使用者到users表中,使用者編号從11開始增加。
create or replace procedure sp_pro6(spName varchar2) is
--定義 :=表示指派
v_num number:=11;
Oracle 筆記
47
begin
while v_num&lt;=20 loop
--執行
insert into users values(v_num,spName);
v_num:=v_num+1;
end loop;
end;
/ ? 循環語句 –for循環 基本for循環的基本結構如下
begin
for i in reverse 1..10 loop
insert into users values (i, 'shunping');
end loop;
end;
我們可以看到控制變量i,在隐含中就在不停地增加。 ? 順序控制語句 –goto,null 1.goto語句 goto語句用于跳轉到特定符号去執行語句。注意由于使用goto語句會增加程式的複雜性,并使得應用程式可讀性變差,是以在做一般應用開發時,建議大家不要使用goto語句。 基本文法如下 goto lable,其中lable是已經定義好的标号名,
declare
i int := 1;
begin
loop
dbms_output.put_line('輸出i=' || i);
if i = 1{} then
goto end_loop;
end if;
i := i + 1;
end loop;
&lt;&lt;end_loop&gt;&gt;
dbms_output.put_line('循環結束');
end; 2.null null語句不會執行任何操作,并且會直接将控制傳遞到下一條語句。使用null語句的主要好處是可以提高pl/sql的可讀性。
declare
v_sal emp.sal%type;
v_ename emp.ename%type;
begin
select ename, sal into v_ename, v_sal from emp where empno = &amp;no;
if v_sal &lt; 3000 then
update emp set comm = sal * 0.1 where ename = v_ename;
else
null;
Oracle 筆記
48
end if;
end;
20.PL/SQL分頁 編寫分頁過程 ? 介紹 分頁是任何一個網站(bbs,網上商城,blog)都會使用到的技術,是以學習pl/sql程式設計開發就一定要掌握該技術。看圖: ? 無傳回值的存儲過程 古人雲:欲速則不達,為了讓大家夥比較容易接受分頁過程編寫,我還是從簡單到複雜,循序漸進的給大家講解。首先是掌握最簡單的存儲過程,無傳回值的存儲過程: 案例:現有一張表book,表結構如下:看圖: 書号 書名 出版社 請寫一個過程,可以向book表添加書,要求通過java程式調用該過程。 --in:表示這是一個輸入參數,預設為in --out:表示一個輸出參數
create or replace procedure sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is
begin
insert into book values(spBookId,spbookName,sppublishHouse);
end;
/ --在java中調用
//調用一個無傳回值的過程
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
	//1.加載驅動
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//2.得到連接配接
	Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
	//3.建立CallableStatement
	CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
	//4.給?指派
	cs.setInt(1,10);
	cs.setString(2,"笑傲江湖");
	cs.setString(3,"人民出版社");
	//5.執行
	cs.execute();
	} catch(Exception e){
		e.printStackTrace();
	} finally{
	//6.關閉各個打開的資源
	cs.close
	//Oracle 筆記
	ct.close();
	}
	}
}
執行,記錄被加進去了 ? 有傳回值的存儲過程(非清單) 再看如何處理有傳回值的存儲過程: 案例:編寫一個過程,可以輸入雇員的編号,傳回該雇員的姓名。 案例擴張:編寫一個過程,可以輸入雇員的編号,傳回該雇員的姓名、工資和崗位。
--有輸入和輸出的存儲過程
create or replace procedure sp_pro8
(spno in number, spName out varchar2) is
begin
select ename into spName from emp where empno=spno;
end;
/
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到連接配接
Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
//4.給?指派
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");*/
//看看如何調用有傳回值的過程
//建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?)}");
//給第一個?指派
cs.setInt(1,7788);
//給第二個?指派
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
//5.執行
cs.execute();
//取出傳回值,要注意?的順序
String name=cs.getString(2);
System.out.println("7788的名字"+name);
} catch(Exception e){
e.printStackTrace();
Oracle 筆記
50
} finally{
//6.關閉各個打開的資源
cs.close();
ct.close();
}
}
}
運作,成功得出結果。。 案例擴張:編寫一個過程,可以輸入雇員的編号,傳回該雇員的姓名、工資和崗位。
--有輸入和輸出的存儲過程
create or replace procedure sp_pro8
(spno in number, spName out varchar2,spSal out number,spJob out varchar2) is
begin
select ename,sal,job into spName,spSal,spJob from emp where empno=spno;
end;
/
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到連接配接
Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
//4.給?指派
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");*/
//看看如何調用有傳回值的過程
//建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?,?,?)}");
//給第一個?指派
cs.setInt(1,7788);
//給第二個?指派
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
//給第三個?指派
cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
//給第四個?指派
cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
//5.執行
cs.execute();
//取出傳回值,要注意?的順序
Oracle 筆記
51
String name=cs.getString(2);
String job=cs.getString(4);
System.out.println("7788的名字"+name+" 工作:"+job);
} catch(Exception e){
e.printStackTrace();
} finally{
//6.關閉各個打開的資源
cs.close();
ct.close();
}
}
}
運作,成功找出記錄 ? 有傳回值的存儲過程(清單[結果集]) 案例:編寫一個過程,輸入部門号,傳回該部門所有雇員資訊。 對該題分析如下: 由于oracle存儲過程沒有傳回值,它的所有傳回值都是通過out參數來替代的,清單同樣也不例外,但由于是集合,是以不能用一般的參數,必須要用pagkage了。是以要分兩部分: 傳回結果集的過程 1.建立一個包,在該包中,我定義類型test_cursor,是個遊标。 如下:
create or replace package testpackage as
TYPE test_cursor is ref cursor;
end testpackage; 2.建立存儲過程。如下:
create or replace procedure sp_pro9(spNo in number,p_cursor out testpackage.test_cursor) is
begin
open p_cursor for
select * from emp where deptno = spNo;
end sp_pro9; 3.如何在java程式中調用該過程
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到連接配接
Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
//看看如何調用有傳回值的過程
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro9(?,?)}");
//4.給第?指派
cs.setInt(1,10);
//給第二個?指派
Oracle 筆記
52
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
//5.執行
cs.execute();
//得到結果集
ResultSet rs=(ResultSet)cs.getObject(2);
while(rs.next()){
System.out.println(rs.getInt(1)+" "+rs.getString(2));
}
} catch(Exception e){
e.printStackTrace();
} finally{
//6.關閉各個打開的資源
cs.close();
ct.close();
}
}
}
運作,成功得出部門号是10的所有使用者 ? 編寫分頁過程 有了上面的基礎,相信大家可以完成分頁存儲過程了。 要求,請大家編寫一個存儲過程,要求可以輸入表名、每頁顯示記錄數、目前頁。傳回總記錄數,總頁數,和傳回的結果集。 如果大家忘了oracle中如何分頁,請參考第三天的内容。 先自己完成,老師在後面給出答案,并講解。 --oracle的分頁
select t1.*, rownum rn from (select * from emp) t1 where rownum&lt;=10;
--在分頁時,大家可以把下面的sql語句當做一個模闆使用
select * from
(select t1.*, rownum rn from (select * from emp) t1 where rownum&lt;=10)
where rn&gt;=6; --開發一個包 --建立一個包,在該包中,我定義類型test_cursor,是個遊标。 如下:
create or replace package testpackage as
TYPE test_cursor is ref cursor;
end testpackage;
--開始編寫分頁的過程
create or replace procedure fenye
(tableName in varchar2,
Pagesize in number,--一頁顯示記錄數
pageNow in number,
myrows out number,--總記錄數
myPageCount out number,--總頁數
p_cursor out testpackage.test_cursor--傳回的記錄集
) is
--定義部分
--定義sql語句 字元串
Oracle 筆記
53
v_sql varchar2(1000);
--定義兩個整數
v_begin number:=(pageNow-1)*Pagesize+1;
v_end number:=pageNow*Pagesize;
begin
--執行部分
v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||') t1 where rownum&lt;='||v_end||') where rn&gt;='||v_begin;
--把遊标和sql關聯
open p_cursor for v_sql;
--計算myrows和myPageCount
--組織一個sql語句
v_sql:='select count(*) from '||tableName;
--執行sql,并把傳回的值,賦給myrows;
execute inmediate v_sql into myrows;
--計算myPageCount
--if myrows%Pagesize=0 then這樣寫是錯的
if mod(myrows,Pagesize)=0 then
myPageCount:=myrows/Pagesize;
else
myPageCount:=myrows/Pagesize+1
end if;
--關閉遊标
close p_cursor;
end;
/ --使用java測試 //測試分頁
import java.sql.*;
public class FenYe{
public static void main(String[] args){
try{
//1.加載驅動
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.得到連接配接
Connection ct = DriverManager.getConnection("jdbc:oracle:[email protected]:1521:MYORA1","scott","m123");
//3.建立CallableStatement
CallableStatement cs = ct.prepareCall("{call fenye(?,?,?,?,?,?)}");
//4.給第?指派
cs.seString(1,"emp");
cs.setInt(2,5);
cs.setInt(3,2);
//注冊總記錄數
Oracle 筆記
54
cs.registerOutParameter(4,oracle.jdbc.OracleTypes.INTEGER);
//注冊總頁數
cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);
//注冊傳回的結果集
cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);
//5.執行
cs.execute();
//取出總記錄數 /這裡要注意,getInt(4)中4,是由該參數的位置決定的
int rowNum=cs.getInt(4);
int pageCount = cs.getInt(5);
ResultSet rs=(ResultSet)cs.getObject(6);
//顯示一下,看看對不對
System.out.println("rowNum="+rowNum);
System.out.println("總頁數="+pageCount);
while(rs.next()){
System.out.println("編号:"+rs.getInt(1)+" 名字:"+rs.getString(2)+" 工資:"+rs.getFloat(6));
}
} catch(Exception e){
e.printStackTrace();
} finally{
//6.關閉各個打開的資源
cs.close();
ct.close();
}
}
}
運作,控制台輸出: rowNum=19 總頁數:4 編号:7369 名字:SMITH 工資:2850.0 編号:7499 名字:ALLEN 工資:2450.0 編号:7521 名字:WARD 工資:1562.0 編号:7566 名字:JONES 工資:7200.0 編号:7654 名字:MARTIN 工資:1500.0 --新的需要,要求按照薪水從低到高排序,然後取出6-10 過程的執行部分做下改動,如下:
begin
--執行部分
v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||' order by sal) t1 where rownum&lt;='||v_end||') where rn&gt;='||v_begin; 重新執行一次procedure,java不用改變,運作,控制台輸出: rowNum=19 總頁數:4 編号:7900 名字:JAMES 工資:950.0 編号:7876 名字:ADAMS 工資:1100.0
Oracle 筆記
55
編号:7521 名字:WARD 工資:1250.0 編号:7654 名字:MARTIN 工資:1250.0 編号:7934 名字:MILLER 工資:1300.0
21.例外處理 例外處理 ? 例外的分類 oracle将例外分為預定義例外,非預定義例外和自定義例外三種。 預定義例外用于處理常見的oracle錯誤 非預定義例外用于處理預定義例外不能處理的例外 自定義例外用于處理與oracle錯誤無關的其它情況 ? 例外傳遞 如果不處理例外我們看看會出現什麼情況: 案例,編寫一個過程,可接收雇員的編号,并顯示該雇員的姓名。 問題是,如果輸入的雇員編号不存在,怎樣去處理呢?
--例外案例
declare
--定義
v_ename emp.ename%type;
begin
--
select ename into v_ename from emp where empno=&amp;gno;
dbms_output.put_line('名字:'||v_ename)
/ 執行,彈出框,看圖: 随便輸個不在的編号,回車,會抛出異常,顯示: ORA-01403: 未找到資料 ORA-06512: 在line 6
declare
--定義
v_ename emp.ename%type;
begin
--
select ename into v_ename from emp where empno=&amp;gno;
dbms_output.put_line('名字:'||v_ename)
exception
when no_data_found then
dbms_output.put_line('編号沒有!');
/
執行,輸入一個不存在的編号,回車,顯示: 編号沒有! ? 處理預定義例外 預定義例外是由pl/sql所提供的系統例外。當pl/sql應用程式違反了oracle 規定的限制時,則會隐含的觸發一個内部例外。pl/sql為開發人員提供了二十多個預定義例外。我們給大家介紹常用的例外。
Oracle 筆記
56
? 預定義例外 case_not_found 在開發pl/sql塊中編寫case語句時,如果在when子句中沒有包含必須的條件分支,就會觸發case_not_found的例外:
create or replace procedure sp_pro6(spno number) is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno = spno;
case
when v_sal &lt; 1000 then
update emp set sal = sal + 100 where empno = spno;
when v_sal &lt; 2000 then
update emp set sal = sal + 200 where empno = spno;
end case;
exception
when case_not_found then
dbms_output.put_line('case語句沒有與' || v_sal || '相比對的條件');
end; ? 預定義例外 cursor_already_open 當重新打開已經打開的遊标時,會隐含的觸發例外cursor_already_open
declare
cursor emp_cursor is select ename, sal from emp;
begin
open emp_cursor;
for emp_record1 in emp_cursor loop
dbms_output.put_line(emp_record1.ename);
end loop;
exception
when cursor_already_open then
dbms_output.put_line('遊标已經打開');
end;
/ ? 預定義例外 dup_val_on_index 在唯一索引所對應的列上插入重複的值時,會隐含的觸發例外dup_val_on_index例外
begin
insert into dept values (10, '公關部', '北京');
exception
when dup_val_on_index then
dbms_output.put_line('在deptno列上不能出現重複值');
end; ? 預定義例外 invalid_cursor 當試圖在不合法的遊标上執行操作時,會觸發該例外 例如:試圖從沒有打開的遊标提取資料,或是關閉沒有打開的遊标。則會觸發該例外
declare
cursor emp_cursor is select ename, sal from emp;
emp_record emp_cursor%rowtype;
begin
Oracle 筆記
57
--open emp_cursor; --打開遊标
fetch emp_cursor into emp_record;
dbms_output.put_line(emp_record.ename);
close emp_cursor;
exception
when invalid_cursor then
dbms_output.put_line('請檢測遊标是否打開');
end; ? 預定義例外 invalid_number 當輸入的資料有誤時,會觸發該例外 比如:數字100寫成了loo就會觸發該例外
begin
update emp set sal= sal + 'loo';
exception
when invalid_number then
dbms_output.put_line('輸入的數字不正确');
end; 預定義例外 no_data_found 下面是一個pl/sql塊,當執行select into 沒有傳回行,就會觸發該例外
declare
v_sal emp.sal%type;
begin
select sal into v_sal from emp
when ename='&amp;name';
exception
when no_data_found then
dbms_output.put_line('不存在該員工');
end; ? 預定義例外 too_many_rows 當執行select into語句時,如果傳回超過了一行,則會觸發該例外。
declare
v_ename emp.ename%type;
begin
select ename into v_ename from emp;
exception
when too_many_rows then
dbms_output.put_line('傳回了多行');
end; ? 預義例外 zero_divide 當執行2/0語句時,則會觸發該例外。 ? 預定義例外 value_error 當在執行指派操作時,如果變量的長度不足以容納實際資料,則會觸發該例外value_error,比如:
declare
v_ename varchar2(5);
begin
Oracle 筆記
58
select ename into v_ename from emp where empno = &amp;no1;
dbms_output.put_line(v_ename);
exception
when value_error then
dbms_output.put_line('變量尺寸不足');
end; ? 其它預定義例外(這些例外不是在pl/sql裡觸發的,而是在用oracle時觸發的,是以取名叫其它預定義例外) 1.login_denied 當使用者非法登入時,會觸發該例外 2.not_logged_on 如果使用者沒有登入就執行dml操作,就會觸發該例外 3.storage_error 如果超過了記憶體空間或是記憶體被損壞,就觸發該例外 4.timeout_on_resource 如果oracle在等待資源時,出現了逾時就觸發該例外 ? 非預定義例外 非預定義例外用于處理與預定義例外無關的oracle錯誤。使用預定義例外隻能處理21個oracle錯誤,而當使用pl/sql開發應用程式時,可能會遇到其它的一些oracle錯誤。比如在pl/sql塊中執行dml語句時,違反了限制規定等等。在這樣的情況下,也可以處理oracle的各種例外,因為非預定義例外用的不多,這裡我就不舉例了。 ? 處理自定義例外 預定義例外和自定義例外都是與oracle錯誤相關的,并且出現的oracle錯誤會隐含的觸發相應的例外;而自定義例外與oracle錯誤沒有任何關聯,它是由開發人員為特定情況所定義的例外. 問題:請編寫一個pl/sql塊,接收一個雇員的編号,并給該雇員工資增加1000元,如果該雇員不存在,請提示。
--自定義例外
create or replace procedure ex_test(spNo number)
is
begin
--更新使用者sal
update emp set sal=sal+1000 where empno=spNo;
end;
/ 運作,該過程被成功建立。 SQL&gt; exec ex_test(56); PL/SQL過程被成功完成 這裡,編号為56是不存在的,剛才的報異常了,為什麼現在不報異常呢? 因為剛才的是select語句 怎麼解決這個問題呢? 修改代碼,如下:
--自定義例外
create or replace procedure ex_test(spNo number)
is
--定義一個例外
myex exception;
begin
--更新使用者sal
update emp set sal=sal+1000 where empno=spNo;
Oracle 筆記
59
--sql%notfound這是表示沒有update
--raise myex;觸發myex
if sql%notfound then
raise myex;
end if;
exception
when myex then
dbms_output.put_line('沒有更新任何使用者');
end;
/ 現在再測試一次: SQL&gt; exec ex_test(56); 沒有更新任何使用者
22.oracle的視圖 oracle的視圖 ? 介紹 視圖是一個虛拟表,其内容由查詢定義,同真實的表一樣,視圖包含一系列帶有名稱的列和行資料。但是,視圖并不在資料庫中以存儲的資料值集形式存在。行和列資料來自由定義視圖的查詢所引用的表,并且在引用視圖時動态生成。(視圖不是真實存在磁盤上的) 看圖: 視與表的差別 ? 視圖與表的差別 1.表需要占用磁盤空間,視圖不需要 2.視圖不能添加索引(是以查詢速度略微慢點) 3.使用視圖可以簡化,複雜查詢 比如:學生選課系統 4.視圖的使用利于提高安全性 比如:不同使用者檢視不同視圖 建立/修改視圖 ? 建立視圖 create view 視圖名 as select 語句 [with read only] ? 建立或修改視圖 create or replace view 視圖名 as select 語句 [with read only] ? 删除視圖 drop view 視圖名 當表結構國語複雜,請使用視圖吧! --建立視圖,把emp表的sal&lt;1000的雇員映射到該視圖(view)
create view myview as select * from emp where sal&lt;1000; --為簡化操作,用一個視圖解決 顯示雇員編号,姓名和部門名稱
create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno; 視圖之間也可以做聯合查詢</pre>
<p> </p>
<pre name="code" >一、基礎
1、說明:建立資料庫
CREATE DATABASE database-name 
2、說明:删除資料庫
drop database dbname
3、說明:備份sql server
--- 建立 備份資料的 device
USE master
EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
--- 開始 備份
BACKUP DATABASE pubs TO testBack 
4、說明:建立新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根據已有的表建立新表: 
A:create table tab_new like tab_old (使用舊表建立新表)
B:create table tab_new as select col1,col2… from tab_old definition only
5、說明:删除新表
drop table tabname 
6、說明:增加一個列
Alter table tabname add column col type
注:列增加後将不能删除。DB2中列加上後資料類型也不能改變,唯一能改變的是增加varchar類型的長度。
7、說明:添加主鍵: Alter table tabname add primary key(col) 
說明:删除主鍵: Alter table tabname drop primary key(col) 
8、說明:建立索引:create [unique] index idxname on tabname(col….) 
删除索引:drop index idxname
注:索引是不可更改的,想更改必須删除重建立。
9、說明:建立視圖:create view viewname as select statement 
删除視圖:drop view viewname
10、說明:幾個簡單的基本的sql語句
選擇:select * from table1 where 範圍
插入:insert into table1(field1,field2) values(value1,value2)
删除:delete from table1 where 範圍
更新:update table1 set field1=value1 where 範圍
查找:select * from table1 where field1 like ’%value1%’ ---like的文法很精妙,查資料!
排序:select * from table1 order by field1,field2 [desc]
總數:select count as totalcount from table1
求和:select sum(field1) as sumvalue from table1
平均:select avg(field1) as avgvalue from table1
最大:select max(field1) as maxvalue from table1
最小:select min(field1) as minvalue from table1
11、說明:幾個進階查詢運算詞
A: UNION 運算符 
UNION 運算符通過組合其他兩個結果表(例如 TABLE1 和 TABLE2)并消去表中任何重複行而派生出一個結果表。當 ALL 随 UNION 一起使用時(即 UNION ALL),不消除重複行。兩種情況下,派生表的每一行不是來自 TABLE1 就是來自 TABLE2。 
B: EXCEPT 運算符 
EXCEPT 運算符通過包括所有在 TABLE1 中但不在 TABLE2 中的行并消除所有重複行而派生出一個結果表。當 ALL 随 EXCEPT 一起使用時 (EXCEPT ALL),不消除重複行。 
C: INTERSECT 運算符
INTERSECT 運算符通過隻包括 TABLE1 和 TABLE2 中都有的行并消除所有重複行而派生出一個結果表。當 ALL 随 INTERSECT 一起使用時 (INTERSECT ALL),不消除重複行。 
注:使用運算詞的幾個查詢結果行必須是一緻的。 
12、說明:使用外連接配接 
A、left (outer) join: 
左外連接配接(左連接配接):結果集幾包括連接配接表的比對行,也包括左連接配接表的所有行。 
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
B:right (outer) join: 
右外連接配接(右連接配接):結果集既包括連接配接表的比對連接配接行,也包括右連接配接表的所有行。 
C:full/cross (outer) join: 
全外連接配接:不僅包括符号連接配接表的比對行,還包括兩個連接配接表中的所有記錄。
12、分組:Group by:
 	一張表,一旦分組 完成後,查詢後隻能得到組相關的資訊。
	組相關的資訊:(統計資訊) count,sum,max,min,avg  分組的标準)
    在SQLServer中分組時:不能以text,ntext,image類型的字段作為分組依據
	在selecte統計函數中的字段,不能和普通的字段放在一起;
13、對資料庫進行操作:
	分離資料庫: sp_detach_db; 附加資料庫:sp_attach_db 後接表明,附加需要完整的路徑名
14.如何修改資料庫的名稱:
sp_renamedb 'old_name', 'new_name' 


二、提升
1、說明:複制表(隻複制結構,源表名:a 新表名:b) (Access可用)
法一:select * into b from a where 1&lt;&gt;1(僅用于SQlServer)
法二:select top 0 * into b from a
2、說明:拷貝表(拷貝資料,源表名:a 目标表名:b) (Access可用)
insert into b(a, b, c) select d,e,f from b;
3、說明:跨資料庫之間表的拷貝(具體資料使用絕對路徑) (Access可用)
insert into b(a, b, c) select d,e,f from b in ‘具體資料庫’ where 條件
例子:..from b in '"&amp;Server.MapPath(".")&amp;"\data.mdb" &amp;"' where..
4、說明:子查詢(表名1:a 表名2:b)
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
5、說明:顯示文章、送出人和最後回複時間
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
6、說明:外連接配接查詢(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
7、說明:線上視圖查詢(表名1:a )
select * from (SELECT a,b,c FROM a) T where t.a &gt; 1;
8、說明:between的用法,between限制查詢資料範圍時包括了邊界值,not between不包括
select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 數值1 and 數值2
9、說明:in 的使用方法
select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)
10、說明:兩張關聯表,删除主表中已經在副表中沒有的資訊 
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
11、說明:四表聯查問題:
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
12、說明:日程安排提前五分鐘提醒 
SQL: select * from 日程安排 where datediff('minute',f開始時間,getdate())&gt;5
13、說明:一條sql 語句搞定資料庫分頁
select top 10 b.* from (select top 20 主鍵字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主鍵字段 = a.主鍵字段 order by a.排序字段
具體實作:
關于資料庫分頁:
  declare @start int,@end int 
  @sql  nvarchar(600)
  set @sql=’select top’+str(@[email protected]+1)+’+from T where rid not in(select top’+str(@str-1)+’Rid from T where Rid&gt;-1)’
  exec sp_executesql @sql


注意:在top後不能直接跟一個變量,是以在實際應用中隻有這樣的進行特殊的處理。Rid為一個辨別列,如果top後還有具體的字段,這樣做是非常有好處的。因為這樣可以避免 top的字段如果是邏輯索引的,查詢的結果後實際表中的不一緻(邏輯索引中的資料有可能和資料表中的不一緻,而查詢時如果處在索引則首先查詢索引)
14、說明:前10條記錄
select top 10 * form table1 where 範圍
15、說明:選擇在每一組b值相同的資料中對應的a最大的記錄的所有資訊(類似這樣的用法可以用于論壇每月排行榜,每月熱銷産品分析,按科目成績排名,等等.)
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)
16、說明:包括所有在 TableA 中但不在 TableB和TableC 中的行并消除所有重複行而派生出一個結果表
(select a from tableA ) except (select a from tableB) except (select a from tableC)
17、說明:随機取出10條資料
select top 10 * from tablename order by newid()
18、說明:随機選擇記錄
select newid()
19、說明:删除重複記錄
1),delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)
2),select distinct * into temp from tablename
  delete from tablename
  insert into tablename select * from temp
評價: 這種操作牽連大量的資料的移動,這種做法不适合大容量但資料操作
3),例如:在一個外部表中導入資料,由于某些原因第一次隻導入了一部分,但很難判斷具體位置,這樣隻有在下一次全部導入,這樣也就産生好多重複的字段,怎樣删除重複字段
alter table tablename
--添加一個自增列
add  column_b int identity(1,1)
 delete from tablename where column_b not in(
select max(column_b)  from tablename group by column1,column2,...)
alter table tablename drop column column_b
20、說明:列出資料庫裡所有的表名
select name from sysobjects where type='U' // U代表使用者
21、說明:列出表裡的所有的列名
select name from syscolumns where id=object_id('TableName')
22、說明:列示type、vender、pcs字段,以type字段排列,case可以友善地實作多重選擇,類似select 中的case。
select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
顯示結果:
type vender pcs
電腦 A 1
電腦 A 1
CD光牒 B 2
CD光牒 A 2
手機 B 3
手機 C 3
23、說明:初始化表table1
TRUNCATE TABLE table1
24、說明:選擇從10到15的記錄
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
三、技巧
1、1=1,1=2的使用,在SQL語句組合時用的較多
“where 1=1” 是表示選擇全部    “where 1=2”全部不選,
如:
if @strWhere !='' 
begin
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where ' + @strWhere 
end
else 
begin
set @strSQL = 'select count(*) as Total from [' + @tblName + ']' 
end 
我們可以直接寫成
錯誤!未找到目錄項。
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where 1=1 安定 '+ @strWhere 2、收縮資料庫
--重建索引
DBCC REINDEX
DBCC INDEXDEFRAG
--收縮資料和日志
DBCC SHRINKDB
DBCC SHRINKFILE
3、壓縮資料庫
dbcc shrinkdatabase(dbname)
4、轉移資料庫給新使用者以已存在使用者權限
exec sp_change_users_login 'update_one','newname','oldname'
go
5、檢查備份集
RESTORE VERIFYONLY from disk='E:\dvbbs.bak'
6、修複資料庫
ALTER DATABASE [dvbbs] SET SINGLE_USER
GO
DBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCK
GO
ALTER DATABASE [dvbbs] SET MULTI_USER
GO
7、日志清除
SET NOCOUNT ON
DECLARE @LogicalFileName sysname,
 @MaxMinutes INT,
 @NewSize INT


USE tablename -- 要操作的資料庫名
SELECT  @LogicalFileName = 'tablename_log', -- 日志檔案名
@MaxMinutes = 10, -- Limit on time allowed to wrap log.
 @NewSize = 1  -- 你想設定的日志檔案的大小(M)
Setup / initialize
DECLARE @OriginalSize int
SELECT @OriginalSize = size 
 FROM sysfiles
 WHERE name = @LogicalFileName
SELECT 'Original Size of ' + db_name() + ' LOG is ' + 
 CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' + 
 CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'
 FROM sysfiles
 WHERE name = @LogicalFileName
CREATE TABLE DummyTrans
 (DummyColumn char (8000) not null)


DECLARE @Counter    INT,
 @StartTime DATETIME,
 @TruncLog   VARCHAR(255)
SELECT @StartTime = GETDATE(),
 @TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'
DBCC SHRINKFILE (@LogicalFileName, @NewSize)
EXEC (@TruncLog)
-- Wrap the log if necessary.
WHILE @MaxMinutes &gt; DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired
 AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)  
 AND (@OriginalSize * 8 /1024) &gt; @NewSize  
 BEGIN -- Outer loop.
SELECT @Counter = 0
 WHILE   ((@Counter &lt; @OriginalSize / 16) AND (@Counter &lt; 50000))
 BEGIN -- update
 INSERT DummyTrans VALUES ('Fill Log') DELETE DummyTrans
 SELECT @Counter = @Counter + 1
 END
 EXEC (@TruncLog)  
 END
SELECT 'Final Size of ' + db_name() + ' LOG is ' +
 CONVERT(VARCHAR(30),size) + ' 8K pages or ' + 
 CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'
 FROM sysfiles 
 WHERE name = @LogicalFileName
DROP TABLE DummyTrans
SET NOCOUNT OFF 
8、說明:更改某個表
exec sp_changeobjectowner 'tablename','dbo'
9、存儲更改全部表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch
@OldOwner as NVARCHAR(128),
@NewOwner as NVARCHAR(128)
AS
DECLARE @Name    as NVARCHAR(128)
DECLARE @Owner   as NVARCHAR(128)
DECLARE @OwnerName   as NVARCHAR(128)
DECLARE curObject CURSOR FOR 
select 'Name'    = name,
   'Owner'    = user_name(uid)
from sysobjects
where user_name(uid)[email protected]
order by name
OPEN   curObject
FETCH NEXT FROM curObject INTO @Name, @Owner
WHILE(@@FETCH_STATUS=0)
BEGIN     
if @[email protected] 
begin
   set @OwnerName = @OldOwner + '.' + rtrim(@Name)
   exec sp_changeobjectowner @OwnerName, @NewOwner
end
-- select @name,@NewOwner,@OldOwner
FETCH NEXT FROM curObject INTO @Name, @Owner
END
close curObject
deallocate curObject
GO


10、SQL SERVER中直接循環寫入資料
declare @i int
set @i=1
while @i&lt;30
begin
    insert into test (userid) values(@i)
    set @[email protected]+1
end
案例:
有如下表,要求就裱中所有沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:
	Name     score
	Zhangshan	80
	Lishi       59
	Wangwu      50
	Songquan	69
while((select min(score) from tb_table)&lt;60)
begin
update tb_table set score =score*1.01 
where score&lt;60
if  (select min(score) from tb_table)&gt;60
  break
 else
    continue
end


資料開發-經典


1.按姓氏筆畫排序:
Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //從少到多
2.資料庫加密:
select encrypt('原始密碼')
select pwdencrypt('原始密碼')
select pwdcompare('原始密碼','加密後密碼') = 1--相同;否則不相同 encrypt('原始密碼')
select pwdencrypt('原始密碼')
select pwdcompare('原始密碼','加密後密碼') = 1--相同;否則不相同
3.取回表中字段:
declare @list varchar(1000),
@sql nvarchar(1000) 
select @[email protected]+','+b.name from sysobjects a,syscolumns b where a.id=b.id and a.name='表A'
set @sql='select '+right(@list,len(@list)-1)+' from 表A' 
exec (@sql)
4.檢視硬碟分區:
EXEC master..xp_fixeddrives
5.比較A,B表是否相等:
if (select checksum_agg(binary_checksum(*)) from A)
     =
    (select checksum_agg(binary_checksum(*)) from B)
print '相等'
else
print '不相等'
6.殺掉所有的事件探察器程序:
DECLARE hcforeach CURSOR GLOBAL FOR SELECT 'kill '+RTRIM(spid) FROM master.dbo.sysprocesses
WHERE program_name IN('SQL profiler',N'SQL 事件探查器')
EXEC sp_msforeach_worker '?'
7.記錄搜尋:
開頭到N條記錄
Select Top N * From 表
-------------------------------
N到M條記錄(要有主索引ID)
Select Top M-N * From 表 Where ID in (Select Top M ID From 表) Order by ID   Desc
----------------------------------
N到結尾記錄
Select Top N * From 表 Order by ID Desc
案例
例如1:一張表有一萬多條記錄,表的第一個字段 RecID 是自增長字段, 寫一個SQL語句, 找出表的第31到第40個記錄。
 select top 10 recid from A where recid not  in(select top 30 recid from A)
分析:如果這樣寫會産生某些問題,如果recid在表中存在邏輯索引。
	select top 10 recid from A where……是從索引中查找,而後面的select top 30 recid from A則在資料表中查找,這樣由于索引中的順序有可能和資料表中的不一緻,這樣就導緻查詢到的不是本來的欲得到的資料。
解決方案
1,	用order by select top 30 recid from A order by ricid 如果該字段不是自增長,就會出現問題
2,	在那個子查詢中也加條件:select top 30 recid from A where recid&gt;-1
例2:查詢表中的最後以條記錄,并不知道這個表共有多少資料,以及表結構。
set @s = 'select top 1 * from T   where pid not in (select top ' + str(@count-1) + ' pid  from  T)'
print @s      exec  sp_executesql  @s
9:擷取目前資料庫中的所有使用者表
select Name from sysobjects where xtype='u' and status&gt;=0
10:擷取某一個表的所有字段
select name from syscolumns where id=object_id('表名')
select name from syscolumns where id in (select id from sysobjects where type = 'u' and name = '表名')
兩種方式的效果相同
11:檢視與某一個表相關的視圖、存儲過程、函數
select a.* from sysobjects a, syscomments b where a.id = b.id and b.text like '%表名%'
12:檢視目前資料庫中所有存儲過程
select name as 存儲過程名稱 from sysobjects where xtype='P'
13:查詢使用者建立的所有資料庫
select * from master..sysdatabases D where sid not in(select sid from master..syslogins where name='sa')
或者
select dbid, name AS DB_NAME from master..sysdatabases where sid &lt;&gt; 0x01
14:查詢某一個表的字段和資料類型
select column_name,data_type from information_schema.columns
where table_name = '表名' 
15:不同伺服器資料庫之間的資料操作
--建立連結伺服器 
exec sp_addlinkedserver   'ITSV ', ' ', 'SQLOLEDB ', '遠端伺服器名或ip位址 ' 
exec sp_addlinkedsrvlogin  'ITSV ', 'false ',null, '使用者名 ', '密碼 ' 
--查詢示例 
select * from ITSV.資料庫名.dbo.表名 
--導入示例 
select * into 表 from ITSV.資料庫名.dbo.表名 
--以後不再使用時删除連結伺服器 
exec sp_dropserver  'ITSV ', 'droplogins ' 


--連接配接遠端/區域網路資料(openrowset/openquery/opendatasource) 
--1、openrowset 
--查詢示例 
select * from openrowset( 'SQLOLEDB ', 'sql伺服器名 '; '使用者名 '; '密碼 ',資料庫名.dbo.表名) 
--生成本地表 
select * into 表 from openrowset( 'SQLOLEDB ', 'sql伺服器名 '; '使用者名 '; '密碼 ',資料庫名.dbo.表名) 


--把本地表導入遠端表 
insert openrowset( 'SQLOLEDB ', 'sql伺服器名 '; '使用者名 '; '密碼 ',資料庫名.dbo.表名) 
select *from 本地表 
--更新本地表 
update b 
set b.列A=a.列A 
 from openrowset( 'SQLOLEDB ', 'sql伺服器名 '; '使用者名 '; '密碼 ',資料庫名.dbo.表名)as a inner join 本地表 b 
on a.column1=b.column1 
--openquery用法需要建立一個連接配接 
--首先建立一個連接配接建立連結伺服器 
exec sp_addlinkedserver   'ITSV ', ' ', 'SQLOLEDB ', '遠端伺服器名或ip位址 ' 
--查詢 
select * 
FROM openquery(ITSV,  'SELECT *  FROM 資料庫.dbo.表名 ') 
--把本地表導入遠端表 
insert openquery(ITSV,  'SELECT *  FROM 資料庫.dbo.表名 ') 
select * from 本地表 
--更新本地表 
update b 
set b.列B=a.列B 
FROM openquery(ITSV,  'SELECT * FROM 資料庫.dbo.表名 ') as a  
inner join 本地表 b on a.列A=b.列A 


--3、opendatasource/openrowset 
SELECT   * 
FROM   opendatasource( 'SQLOLEDB ',  'Data Source=ip/ServerName;User ID=登陸名;Password=密碼 ' ).test.dbo.roy_ta 
--把本地表導入遠端表 
insert opendatasource( 'SQLOLEDB ',  'Data Source=ip/ServerName;User ID=登陸名;Password=密碼 ').資料庫.dbo.表名 
select * from 本地表  
SQL Server基本函數
SQL Server基本函數
1.字元串函數 長度與分析用 
1,datalength(Char_expr) 傳回字元串包含字元數,但不包含後面的空格
2,substring(expression,start,length) 取子串,字元串的下标是從“1”,start為起始位置,length為字元串長度,實際應用中以len(expression)取得其長度
3,right(char_expr,int_expr) 傳回字元串右邊第int_expr個字元,還用left于之相反
4,isnull( check_expression , replacement_value )如果check_expression為空,則傳回replacement_value的值,不為空,就傳回check_expression字元操作類 
5,Sp_addtype 自定義數據類型
例如:EXEC sp_addtype birthday, datetime, 'NULL'
6,set nocount {on|off}
使傳回的結果中不包含有關受 Transact-SQL 語句影響的行數的資訊。如果存儲過程中包含的一些語句并不傳回許多實際的資料,則該設定由于大量減少了網絡流量,是以可顯著提高性能。SET NOCOUNT 設定是在執行或運作時設定,而不是在分析時設定。
SET NOCOUNT 為 ON 時,不傳回計數(表示受 Transact-SQL 語句影響的行數)。
SET NOCOUNT 為 OFF 時,傳回計數
常識


在SQL查詢中:from後最多可以跟多少張表或視圖:256
在SQL語句中出現 Order by,查詢時,先排序,後取
在SQL中,一個字段的最大容量是8000,而對于nvarchar(4000),由于nvarchar是Unicode碼。  
	
SQLServer2000同步複制技術實作步驟
一、 預備工作
1.釋出伺服器,訂閱伺服器都建立一個同名的windows使用者,并設定相同的密碼,做為釋出快照檔案夾的有效通路使用者
--管理工具
--計算機管理
--使用者群組
--右鍵使用者
--建立使用者
--建立一個隸屬于administrator組的登陸windows的使用者(SynUser)
2.在釋出伺服器上,建立一個共享目錄,做為釋出的快照檔案的存放目錄,操作:
我的電腦--D:\ 建立一個目錄,名為: PUB
--右鍵這個建立的目錄
--屬性--共享
--選擇"共享該檔案夾"
--通過"權限"按紐來設定具體的使用者權限,保證第一步中建立的使用者(SynUser) 具有對該檔案夾的所有權限


--确定
3.設定SQL代理(SQLSERVERAGENT)服務的啟動使用者(釋出/訂閱伺服器均做此設定)
開始--程式--管理工具--服務
--右鍵SQLSERVERAGENT
--屬性--登陸--選擇"此賬戶"
--輸入或者選擇第一步中建立的windows登入使用者名(SynUser)
--"密碼"中輸入該使用者的密碼
4.設定SQL Server身份驗證模式,解決連接配接時的權限問題(釋出/訂閱伺服器均做此設定)
企業管理器
--右鍵SQL執行個體--屬性
--安全性--身份驗證
--選擇"SQL Server 和 Windows"
--确定
5.在釋出伺服器和訂閱伺服器上互相注冊
企業管理器
--右鍵SQL Server組
--建立SQL Server注冊...
--下一步--可用的伺服器中,輸入你要注冊的遠端伺服器名 --添加
--下一步--連接配接使用,選擇第二個"SQL Server身份驗證"
--下一步--輸入使用者名和密碼(SynUser)
--下一步--選擇SQL Server組,也可以建立一個新組
--下一步--完成
6.對于隻能用IP,不能用計算機名的,為其注冊伺服器别名(此步在實施中沒用到)
 (在連接配接端配置,比如,在訂閱伺服器上配置的話,伺服器名稱中輸入的是釋出伺服器的IP)
開始--程式--Microsoft SQL Server--用戶端網絡實用工具
--别名--添加
--網絡庫選擇"tcp/ip"--伺服器别名輸入SQL伺服器名
--連接配接參數--伺服器名稱中輸入SQL伺服器ip位址
--如果你修改了SQL的端口,取消選擇"動态決定端口",并輸入對應的端口号
二、 正式配置
1、配置釋出伺服器
打開企業管理器,在釋出伺服器(B、C、D)上執行以下步驟:
(1) 從[工具]下拉菜單的[複制]子菜單中選擇[配置釋出、訂閱伺服器和分發]出現配置釋出和分發向導 
(2) [下一步] 選擇分發伺服器 可以選擇把釋出伺服器自己作為分發伺服器或者其他sql的伺服器(選擇自己)
(3) [下一步] 設定快照檔案夾
采用預設\\servername\Pub
(4) [下一步] 自定義配置 
可以選擇:是,讓我設定分發資料庫屬性啟用釋出伺服器或設定釋出設定
否,使用下列預設設定(推薦)
(5) [下一步] 設定分發資料庫名稱和位置 采用預設值
(6) [下一步] 啟用釋出伺服器 選擇作為釋出的伺服器
(7) [下一步] 選擇需要釋出的資料庫和釋出類型
(8) [下一步] 選擇注冊訂閱伺服器
(9) [下一步] 完成配置
2、建立出版物
釋出伺服器B、C、D上
(1)從[工具]菜單的[複制]子菜單中選擇[建立和管理釋出]指令
(2)選擇要建立出版物的資料庫,然後單擊[建立釋出]
(3)在[建立釋出向導]的提示對話框中單擊[下一步]系統就會彈出一個對話框。對話框上的内容是複制的三個類型。我們現在選第一個也就是預設的快照釋出(其他兩個大家可以去看看幫助)
(4)單擊[下一步]系統要求指定可以訂閱該釋出的資料庫伺服器類型,
SQLSERVER允許在不同的資料庫如 orACLE或ACCESS之間進行資料複制。
但是在這裡我們選擇運作"SQL SERVER 2000"的資料庫伺服器
(5)單擊[下一步]系統就彈出一個定義文章的對話框也就是選擇要出版的表
注意: 如果前面選擇了事務釋出 則再這一步中隻能選擇帶有主鍵的表
(6)選擇釋出名稱和描述
(7)自定義釋出屬性 向導提供的選擇:
是 我将自定義資料篩選,啟用匿名訂閱和或其他自定義屬性
否 根據指定方式建立釋出 (建議采用自定義的方式)
(8)[下一步] 選擇篩選釋出的方式 
(9)[下一步] 可以選擇是否允許匿名訂閱
1)如果選擇署名訂閱,則需要在釋出伺服器上添加訂閱伺服器
方法: [工具]-&gt;[複制]-&gt;[配置釋出、訂閱伺服器和分發的屬性]-&gt;[訂閱伺服器] 中添加
否則在訂閱伺服器上請求訂閱時會出現的提示:改釋出不允許匿名訂閱
如果仍然需要匿名訂閱則用以下解決辦法 
[企業管理器]-&gt;[複制]-&gt;[釋出内容]-&gt;[屬性]-&gt;[訂閱選項] 選擇允許匿名請求訂閱
2)如果選擇匿名訂閱,則配置訂閱伺服器時不會出現以上提示
(10)[下一步] 設定快照 代理程式排程
(11)[下一步] 完成配置
當完成出版物的建立後建立出版物的資料庫也就變成了一個共享資料庫
有資料 
srv1.庫名..author有字段:id,name,phone, 
srv2.庫名..author有字段:id,name,telphone,adress 


要求: 
srv1.庫名..author增加記錄則srv1.庫名..author記錄增加 
srv1.庫名..author的phone字段更新,則srv1.庫名..author對應字段telphone更新 
--*/ 


--大緻的處理步驟 
--1.在 srv1 上建立連接配接伺服器,以便在 srv1 中操作 srv2,實作同步 
exec sp_addlinkedserver 'srv2','','SQLOLEDB','srv2的sql執行個體名或ip' 
exec sp_addlinkedsrvlogin 'srv2','false',null,'使用者名','密碼' 
go
--2.在 srv1 和 srv2 這兩台電腦中,啟動 msdtc(分布式事務處理服務),并且設定為自動啟動
。我的電腦--控制台--管理工具--服務--右鍵 Distributed Transaction Coordinator--屬性--啟動--并将啟動類型設定為自動啟動 
go 




--然後建立一個作業定時調用上面的同步處理存儲過程就行了 


企業管理器 
--管理 
--SQL Server代理 
--右鍵作業 
--建立作業 
--"正常"項中輸入作業名稱 
--"步驟"項 
--建立 
--"步驟名"中輸入步驟名 
--"類型"中選擇"Transact-SQL 腳本(TSQL)" 
--"資料庫"選擇執行指令的資料庫 
--"指令"中輸入要執行的語句: exec p_process 
--确定 
--"排程"項 
--建立排程 
--"名稱"中輸入排程名稱 
--"排程類型"中選擇你的作業執行安排 
--如果選擇"反複出現" 
--點"更改"來設定你的時間安排 




然後将SQL Agent服務啟動,并設定為自動啟動,否則你的作業不會被執行 


設定方法: 
我的電腦--控制台--管理工具--服務--右鍵 SQLSERVERAGENT--屬性--啟動類型--選擇"自動啟動"--确定. 




--3.實作同步處理的方法2,定時同步 


--在srv1中建立如下的同步處理存儲過程 
create proc p_process 
as 
--更新修改過的資料 
update b set name=i.name,telphone=i.telphone 
from srv2.庫名.dbo.author b,author i 
where b.id=i.id and
(b.name &lt;&gt; i.name or b.telphone &lt;&gt; i.telphone) 


--插入新增的資料 
insert srv2.庫名.dbo.author(id,name,telphone) 
select id,name,telphone from author i 
where not exists( 
select * from srv2.庫名.dbo.author where id=i.id) 


--删除已經删除的資料(如果需要的話) 
delete b 
from srv2.庫名.dbo.author b 
where not exists( 
select * from author where id=b.id)
go