1. 程式人生 > >Oracle中的 DML, DDL,DCL

Oracle中的 DML, DDL,DCL

DML:資料操作語言,SQL中處理資料等操作統稱為資料操縱語言

       它們是SELECT、UPDATE、INSERT、DELETE,就象它的名字一樣,這4條命令是用來對資料庫裡的資料進行操作的語言,不修改表的結構,只修改表的內容

需要commit 才能真正被執行

DDL:資料定義語言,用於定義和管理 SQL 資料庫中的所有物件的語言

       DDL比DML要多,主要的命令有CREATE、ALTER、DROP等,DDL主要是用在定義或改變表(TABLE)的結構,資料型別,表之間的連結和約束等初始化工作上,他們大多在建立表時使用

DCL:資料控制語言,用來授予或回收訪問資料庫的某種特權,並控制資料庫操縱事務發生的時間及效果,對資料庫實行監視等

 DML(Data Manipulation Language,資料操作語言):用於檢索或者修改資料。

    DML包括:  SELECT:用於檢索資料;         INSERT:用於增加資料到資料庫;         UPDATE:用於從資料庫中修改現存的資料          DELETE:用於從資料庫中刪除資料。

 DDL(Data Definition Language,資料定義語言): 用於定義資料的結構,比如 建立、修改或者刪除資料庫物件。         DDL包括:DDL語句可以用於建立使用者和重建資料庫物件。下面是DDL命令:         CREATE TABLE:建立表         ALTER TABLE         DROP TABLE:刪除表         CREATE INDEX         DROP INDEX

 DCL(Data Control Language,資料控制語言):用於定義資料庫使用者的許可權。

    DCL包括:         ALTER PASSWORD          GRANT          REVOKE          CREATE SYNONYM

一:DCL(資料控制語言)     1、建立使用者test2,密碼也是test2(記得最有以分;號結束):         create user test2 identified by test2;

    2、給test2授權:create session;(允許使用者登陸Oracle):         grant create session to test2;

    3、給test2分配建立表的許可權;         grant create table to test2;

    4、給test2分配表空間的使用許可權;         grant unlimited tablespace to test2;

二:DDL(資料定義語言練習)     1、建立表:SQL> create table t_user(                 userid number(30) not null primary key,                 username varchar(20) not null,                 age number(3),                 sex varchar(2),                 departid number(30) not null,                 foreign key(departid) references t_depart(departid)             );     ★alter table student add primary key(userid)這樣用alter也可以建立關聯主外來鍵。

    2、刪除表:SQL> drop table t_depart;          3、建立序列:         create sequence seq_a minvalue 1000 maxvalue 99999999 start with 1000 increment by 1 nocache; 

三:DML(資料操作語言):     1、insert插入SQL:         (1)insert into t_depart (departid,departname,createdate)            values (1,'市場部',sysdate);         (2)insert into t_user values (seq_user.nextval,'馬文濤',23,'男');

    2、delete刪除SQL:         (1)delete t_user;(太可怕了,如果在刪除時不加條件,則把此表中的所有資料都會刪除!)         (2)delete t_user where userid = 3;

    3、update更新SQL:         (1) update t_user set username = '爭偉',sex = '男';             (太恐怖了,更新時不加條件表中所有行記錄的姓名都被修改了!)         (2)update t_user set username = '文濤' where userid = 7;     ★小結:我發現在增、刪、改的SQL語句中用不到from關鍵字。          4、select查詢SQL:格式——>select···from···where···group by···having···order by···;         (1)查詢所有的使用者:select * from t_user;          ★在oracle中這裡的表明用別名時不能加as關鍵字          如:    select * from t_user u;正確             select * from t_user as u;錯誤

        (2)查詢指定的列: select username,sex from t_user;

        (3)as給列以別名顯示:select username as 使用者名稱 from t_user;(這裡的as關鍵字可以省略)

        (4)distinct去掉重複的行:select distinct username from t_user;

        (5)使用運算子:select age+10 from t_user;(給每個人的年齡都加10歲)

        (6)連線字串: select '使用者名稱:' || username from t_user;(Oracle用||做連線字串操作符)

        (7)where子句:select * from t_user where username = '寶寶';

        (8)between and在···之間:             select * from t_user where userid between 9 and 10;這也等價於下面這條SQL:             select * from t_user where userid >=9 and userid <=10;

        (9)in匹配集合中的任意值:select * from t_user where username in('馬文濤','寶寶');

        (10)like模糊查詢:%匹配0個或多個任意字串,_匹配1個任意字串。

            select * from t_user where username like '%濤%';

        (11)null判斷某列為空:select * from t_user where sex is null;             (這裡用is,不能用=,如果要返回不為null的記錄就可以用is not null)                      (12)order by排序:ASC: 升序排列(可以省略),DESC: 降序排列             升序:select u.userid,u.username from t_user u order by u.userid;             降序:select u.userid,u.username from t_user u order by u.userid desc;

        (13)系統函式(對一組資料進行處理,返回一個值):             AVG–求平均值,COUNT–統計記錄數,MAX–最大值,MIN–最小值,SUM–求和             <1>返回最小和最大的使用者編號: select min(userid),max(userid) from t_user;             <2>返回總記錄數: select count(*) from t_user;             <3>返回某個欄位不為空的記錄數: select count(sex) from t_user;             <4>返回不為空且不重複的記錄數: select count(distinct sex) from t_user;

        (14)group by分組(分組了就不能直接返回*,經常和聚合函式count(age)一起使用):              <1>按姓名分組,並統計每組人數:select count(*),username from t_user group by username;              <2>根據多個欄位分組: select username,age,count(*) from t_user group by username,age;         ◆group by有一個原則,就是 select 後面的所有列中,沒有使用聚合函式的列,必須出現在 group by 後面。

        (15)having過濾分組:select username from t_user group by username having count(*) > 2;

        (16)子查詢(子查詢自身只能返回一個單獨的值):             <1>子查詢放在select後面,作為其中的一個欄位返回。                 select u.username,(select d.departname from t_depart d where d.departid = u.departid) from t_user u;                 (返回使用者和所屬的部門,這中子查詢理論上先執行外面的查詢,只是我的感覺哦,嘿嘿!)             <2>子查詢放在from後面,作為一張臨時表。                 select * from (select username,sex s from t_user where departid=1)                  where s = '男';                 (這種子查詢應該先執行裡面)             <3>子查詢放在where後面,作為條件的一部分。                 select * from t_user where departid = (select departid from t_depart where departname = '財務部');                 (這種子查詢也應該先執行裡面)

        (17)聯合查詢(當n張表連線時, 需要n-1個連線條件):             <1>等值連線(內連線):select u.username,d.departname from t_user u,t_depart d                      where u.departid = d.departid;             <2>外連線:即把不滿足條件的記錄也返回,用個+就行了,             (+)操作符在哪邊就代表另外一邊不滿足聯合條件的記錄可以被輸出。這個感覺不太常用。                 select b.book_id,b.book_name from book_info as b,book_click_num as c                  where b.book_id = c.book_id(+);

四、觸發器trigger:當特定事件發生時自動執行的程式碼塊。     這些事件包括:     (1)DML語句(INSERT,UPDATE,DELETE):before在DML語句被執行前觸發操作,after在DML語句被執行後觸發操作。     (2)DDL語句(CREATE 及 ALTER)     (3)系統事件,例如啟動/關閉[startup/shutdown]、錯誤[error]     (4)使用者事件, 例如登入/退出[logon/logoff] ★兩個特殊的變數——>:new新的記錄值,:old保留原來的記錄值     簡單示例:create or replace trigger update_depart_trigger              after update on t_depart for each row            begin update t_user u set u.departid = :new.departid              where u.departid = :old.departid;           end update_depart_trigger;     此示例的作用:當部門的id改變後,由於使用者中有外來鍵引用了部門,所以使用者的departid這個外來鍵自動執行更新操作。     (這個觸發器很奇怪,在黑視窗用sqlplus就不能建立,用plsql Developer工具就可以建立,很有意思,嘿嘿!)

五、遊標cursor:以迴圈取SQL語句的SELECT內容,它是存放結果集的資料物件,使用遊標,我們只能逐條記錄地得到查詢結果。      作用:查詢資料庫,獲取記錄集合(結果集)的指標,可以讓開發者一次訪問一行結果集,在每條結果集上作操作。     使用:用遊標有四種基本的步驟:宣告遊標(declare)、開啟遊標(open)、提取資料(fetch)、關閉遊標(close)。      ★當你要往每一行插入一個數據只能用遊標,或者更新結果集中的每行記錄時也可用遊標,用儲存過程返回一個結果集。     ★觸發器和儲存過程會和資料庫繫結,即一直儲存在資料庫中,而遊標不會,它是任意時刻建立再開啟再執行再關閉,       與資料庫沒有任何直接關係。     ★在Oracle中,不需要顯示銷燬遊標.因為在Oracle中,很多東西是由JAVA寫的.Oracle會自動銷燬遊標。

    簡單示例:             -- 定義一個遊標         declare            cursor cursor_user              is               select username,age                 from t_user;            //變數的定義也可以放到遊標定義上面            a t_user.username%type;//定義個a變數,型別是t_user表中username列的型別。            b t_user.age%type;//同上         begin//SQL中可執行程式碼都在begin和end之間。           -- 開啟遊標           open cursor_user;                      -- 遍歷遊標           loop//迴圈抓取資料(loop是其中一種迴圈方式)              fetch cursor_user into a,b; -- 將一行記錄放入到變數中             dbms_output.put_line(a || '   ' || b);列印到輸出控制檯              exit when cursor_user%notfound; -- 當沒有記錄時退出迴圈           end loop;//退出迴圈           -- 關閉遊標           close cursor_user;         end;

        加if條件判斷遊標示例:             declare                cursor cursor_user                  is                   select username,age                     from t_user;                a t_user.username%type;                b t_user.age%type;             begin               open cursor_user;               loop                  fetch cursor_user into a,b;                     if a='寶寶'and b=43 then                      dbms_output.put_line(a || '   ' || b);                     end if;                  exit when cursor_user%notfound;               end loop;               close cursor_user;             end;

六、儲存過程procedure      概念:其實就是一組存放在資料庫中SQL語句,普通SQL操作都在專案中寫死的,而他只跟資料庫進行繫結。          更準確的說儲存過程是資料庫伺服器端的一段程式,它有兩種型別。一種類似於SELECT查詢,用於檢索資料,檢索到的資料能夠以資料集的形式返回給客戶(oracle儲存過程本身沒返回值,只是用out引數代替)。另一種類似於INSERT或DELETE查詢,它不返回資料,只是執行一個動作。有的伺服器允許同一個儲存過程既可以返回資料又可以執行動作。

    優點:           1、提高效率。儲存過程本身的執行速度非常快,而且,呼叫儲存過程可以大大減少同資料庫的互動次數。         2、提高安全性。假如將SQL語句混合在JSP程式碼中,程式碼外漏以後,也就意味著庫結構外漏。         3、有利於SQL語句的重用。     ★oracle函式有返回值,但儲存過程沒有返回值,它的所有返回值都是通過out引數來替代的。     ★什麼時候需要用儲存過程           如果伺服器定義了儲存過程,應當根據需要決定是否要用儲存過程。儲存過程通常是一些經常要執行的任務,這些任務往往是針對大量的記錄而進行的。在伺服器上執行儲存過程,可以改善應用程式的效能。這是因為:         .伺服器往往具有強大的計算能力和速度。         .避免把大量的資料下載到客戶端,減少網路上的傳輸量。           例如,假設一個應用程式需要計算一個數據,這個資料需要涉及到許多記錄。如果不使用儲存過程的話,把這些資料下載到客戶端,導致網路上的流量劇增。         不僅如此,客戶端可能是一臺老掉牙的計算機,它的運算速度很慢。而改用儲存過程後,伺服器會很快地把資料計算出來,並且只需傳遞一個數據給客戶端,其效率之高是非常明顯的。

    ★儲存過程的引數       要執行伺服器上的儲存過程,往往要傳遞一些引數。這些引數分為四種類型:       第一種稱為輸入引數(in),由客戶程式向儲存過程傳遞值。       第二種稱為輸出引數(out),由儲存過程向客戶程式返回結果。       第三種稱為輸入/輸出引數(in out),既可以由客戶程式向儲存過程傳遞值,也可以由儲存過程向客戶程式返回結果。       第四種稱為狀態引數,由儲存過程向客戶程式返回錯誤資訊。     要說明的是,並不是所有的伺服器都支援上述四種類型的引數,例如,InterBase就不支援狀態引數。

    簡單示例:         1、無返回值儲存過程(插入一個使用者)             create or replace procedure saveuser              (    username in varchar2 ,                  age in number,                 departid in number             //定義兩個輸入引數,引數型別可以是自己寫死,也可以用某個列的型別             比如:username t_user.username%type;             ) as             begin                 insert into t_user (userid,username,age,departid) values (seq_user.nextval,username, age,departid);             end saveuser;             (1)在sql中執行儲存過程call saveuser('文濤',23,1);,也可以用execute和exec。                         (2)在java裡呼叫時就用下面的程式碼:             package com.hyq.src;                           import java.sql.*;             import java.sql.ResultSet;                           public class TestProcedureOne {              public TestProcedureOne() {              }              public static void main(String[] args ){                 String driver = "oracle.jdbc.driver.OracleDriver";                 String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:ORCLA";                 Statement stmt = null;                 ResultSet rs = null;                 Connection conn = null;                 CallableStatement cstmt = null;                               try {                   Class.forName(driver);                   conn = DriverManager.getConnection(strUrl, " hyq ", " hyq ");                   CallableStatement proc = null;                   proc = conn.prepareCall("{ call saveuser(?,?,?) }");                   proc.setString(1, "馬文濤");                   proc.setInt(2,23);                   proc.setInt(3,1);                   proc.execute();                 }                 catch (SQLException ex2) {                   ex2.printStackTrace();                 }                 catch (Exception ex2) {                   ex2.printStackTrace();                 }                 finally{                   try {                 if(rs != null){                   rs.close();                   if(stmt!=null){                     stmt.close();                   }                   if(conn!=null){                     conn.close();                   }                 }                   }                   catch (SQLException ex1) {                   }                 }              }             }

    2、有返回值的儲存過程(oracle儲存過程本身沒返回值)只是用out引數代替(非列表)     //獲得某部門下的所有使用者姓名和年齡     create or replace procedure pro_getUserByDepart//oracle中不區分大小寫,這裡只是為了自己方便。     (    i_departid in t_user.departid%type,         o_username out t_user.username%type,         o_age out t_user.age%type     )as     begin         select username,age into  o_username,o_age from t_user  where  departid = i_departid;      end pro_getUserByDepart;

    ★在pl/sql Developer中右擊儲存過程選擇測試就可以在下面輸入值直接看列印結果了。          ★由於這個儲存過程會返回行記錄集,所有在Developer中為了測試成功就在此過程中加入rownum=1條件判斷,     即:select username,age into  o_username,o_age from t_user  where  departid = i_departid and rownum=1;      如果不加那個rownum=1(當然你也可以讓它等於2),多行記錄會報“實際返回的行數超出請求的行數”這個異常。

    ★其實我們用上面這種儲存過程一般都只返回一行記錄集,如果是返回多行那就要用到要用包pagkage和遊標cursor了。

    ★在利用select...into...語法時(把查詢的結果放入輸出引數中),必須先確保資料庫中有該條記錄,否則會報出"no data found"異常。

    3、返回列表(必須要用包了,package裡包含了遊標),分兩個步驟:         ★為什麼要在儲存過程中用到遊標時,要把此遊標封裝到一個包中呢,個人理解:由於遊標是機開機關的一個           物件,它無法被儲存過程呼叫,而包中恰恰能封裝遊標、函式等這些物件,所有就把遊標放在一個包中。         (1)1, 建一個程式包。如下:             create or replace package userpackage as              type usercursor is ref cursor;             end userpackage;

        (2)建立儲存過程,儲存過程為:             create or replace procedure pro_getalluser             (                     pro_cursor out userpackage.usercursor             )is              begin                 open pro_cursor for select * from t_user;             end pro_getalluser;             可以看到,它是把遊標(可以理解為一個指標),作為一個out 引數來返回值的。

        ★在java裡呼叫時就用下面的程式碼(列出主要程式碼):             package com.mwt.test;

                import java.sql.CallableStatement;                 import java.sql.Connection;                 import java.sql.DriverManager;                 import java.sql.ResultSet;

                import oracle.jdbc.OracleTypes;

                public class TestProcedure {                     public static void main(String...args){                      try{                            Class.forName("oracle.jdbc.driver.OracleDriver");                            String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL9I";                            String user = "test2";                            String password = "test2";                                 Connection con = DriverManager.getConnection(url, user, password);                            String sql = "{call pro_getalluser(?)}";                            CallableStatement cs = con.prepareCall(sql);                            cs.registerOutParameter(1, OracleTypes.CURSOR);                            cs.execute();                                              //返回第一個儲存過程的輸出引數,我只返回了一個遊標也就只有一個輸出引數,即就是獲得第一個返輸出引數getObject(1);                                        ResultSet rs = (ResultSet)cs.getObject(1);                            while(rs.next()){                                System.out.println(rs.getString(1)+"----"+rs.getString(2)+"----"+rs.getString(3));                            }                                              rs.close();                            cs.close();                            con.close();                            }catch(Exception e){                            e.printStackTrace();                            }                          }                 }