pg电子游戏软件,类似车行168的软件,单机游戏内购破解平台,今日打牌财神方位查询老黄历

oracle的sql語句

時間:2023-01-21 16:24:55 Oracle認證 我要投稿

oracle的sql語句

  Oracle WDP 全稱為Oracle Workforce Development Program,是Oracle (甲骨文)公司專門面向學生、個人、在職人員等群體開設的職業發展力課程。下面是小編整理的關于oracle的sql語句,歡迎大家參考!

  首先,以超級管理員的身份登錄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函數就可以了

  


 

  

 

 

  

第一次

 

  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)-->表示數字,長度為4

  varchar2(10)-->表示的是字符串,只能容納10個長度

  date-->表示日期

  number(7,2)-->表示數字,小數占2位,整數占5位,總共7位

  第二次

  1、SQL語句

  1.1 準備工作--熟悉scott賬戶下的四張表及表結構

  第一張表emp-->雇員表,用于存儲雇員信息

  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-->部門表,用于存儲部門信息

  deptno number(2) 部門編號

  dname varchar2(14) 部門名稱

  loc varchar2(13) 部門位置

  第三張表salgrade-->工資等級表,用于存儲工資等級

  grade number 等級名稱

  losal number 此等級的最低工資

  hisal number 此等級的最高工資

  第四張表bonus-->獎金表,用于存儲一個雇員的工資及獎金

  ename varchar2(10) 雇員姓名

  job varchar2(9) 雇員工作

  sal number 雇員工資

  comm number 雇員獎金

  1.2、SQL簡介

  什么是SQL?

  SQL(Structured Query Language,結構查詢語言)是一個功能強大的數據語言。SQL通常用于與數據庫的通訊。SQL是關系數據庫管理系統的標準語言。SQL功能強大,概括起來,分為以下幾組:

  |-DML-->Data Manipulation Language,數據操縱語言,用于檢索或者修改數據,即主要是對數據庫表中的數據的操作。

  |-DDL-->Data Definition Language,數據定義語言,用于定義數據的結構,如創建、修改或者刪除數據庫對象,即主要是對表的操作。

  |-DCL-->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>1500;

  下面的操作是查詢出可以得到獎金的雇員信息(也就是獎金列不為空的記錄)

  select * from emp where comm is not null;

  很顯然,查詢沒有獎金的操作就是

  select * from emp where comm is null;

  我們來點復雜的查詢,查詢出工資在1500之上,并且可以拿到獎金的雇員信息。這里的限定條件不再是一個了,當所有的限定條件需要同時滿足時,我們采用and關鍵字將多個限定條件進行連接,表示所有的限定條件都需要滿足,所以,該查詢可以這么進行:

  select * from emp where sal>1500 and comm is not null;

  現在的需求發生了變化,要求查詢出工資在1500之上,或者可以領取到獎金的雇員信息。這里的限定條件也是兩個,但是有所不同的是,我們不需要同時滿足著兩個條件,因為需求中寫的是

  “或者”,所以在查詢時,只需要滿足兩個條件中的一個就行。那么,我們使用關鍵字or來實現“或者”的功能。

  select * from emp where sal>1500 or comm is not null;

  需求再次發生變化,查詢出工資不大于1500(小于或等于1500),同時不可以領取獎金的雇員信息,可想這些雇員的工資一定不怎么高。之前我們使用not關鍵字對限定條件進行了取反,那么,這里就相當于對限定條件整體取反。我們分析下,工資不大于1500同時不可以領取獎金的反面含義就是工資大于1500同時可以領取獎金,所以,我們這樣操作:

  select * from emp where sal>1500 and comm is not null;

  這是原始需求取反后的查詢語句,那么為了達到最終的查詢效果,我們將限定條件整體取反,即

  select * from emp where not(sal>1500 and comm is not null);

  在這里,我們通過括號將一系列限定條件包含起來表示一個整體的限定條件。

  我們在數學中學過這樣的表達式:100<a<200,那么在數據庫中如何實現呢?一樣的,我們現在要查詢出工資在1500之上,但是在3000之下的全部雇員信息,很顯然,兩個限定條件,同時要滿足才行。

  select * from emp where sal>1500 and sal<3000;

  這里不要異想天開的寫成select * from emp where 1500<sal<3000;()試試吧,絕對會報錯。 很簡單,數據庫軟件不支持這樣的寫法,至少現在的數據庫沒有誰去支持這樣的寫法。

  在SQL語法中,提供了一種專門指定范圍查詢的過濾語句:between x and y,相當于a>=x and a<=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主要使用的兩種通配符:

  |-“%”-->可以匹配任意長度的內容,包括0個字符;

  |-“_”-->可以匹配一個長度的內容。

  下面我們看這樣一個需求,查詢所有雇員姓名中第二個字母包含“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%';

  在操作條件中還可以使用:>、>=、=、<、<=等計算符號

  對于不等于符號,有兩種方式:<>、!=

  現在需要我們查詢雇員編號不是7369的雇員信息

  select * from emp where empno<>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()-->求出給定日期范圍的月數

  add_months()-->在指定日期上加上指定的月數,求出之后的日期

  next_day()-->下一個的今天是哪一個日期

  last_day()-->求出給定日期的最后一天日期

  查詢出所有雇員的編號,姓名,和入職的月數

  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()-->轉換成字符串

  to_number()-->轉換成數字

  to_date()-->轉換成日期

  我們先看看前面做的一個范例,查詢所有雇員的雇員編號,姓名和雇傭時間

  select empno,ename,hiredate from emp;

  但是現在的要求是講年、月、日進行拆分,此時我們就需要使用to_char()函數進行拆分,拆分的時候必須指定拆分的通配符:

  年-->y,年是四位數字,所以使用yyyy表示

  月-->m,月是兩位數字,所以使用mm表示

  日-->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-->表示Local的縮寫,以本地的語言進行金額的顯示

  $-->表示美元

  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-->列名或表達式

  search1.search2......-->為用于比較的條件

  result1、result2......-->為返回值

  如果col/expression和search i 相比較,相同的話返回result i ,如果沒有與col/expression相匹配的結果,則返回默認值default。

  select decode(1,1,'內容是1',2,'內容是2',3,'內容是3') from dual;

  那么,如何在對表查詢時使用decode()函數呢?我們來定義一個需求,

  現在雇員的工作職位有:

  CLERK-->業務員

  SALESMAN-->銷售人員

  MANAGER-->經理

  ANALYST-->分析員

  PRESIDENT-->總裁

  要求我們查詢出雇員的編號,姓名,雇傭日期及工作,將工作替換為上面的中文

  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>sal;

  此查詢為單個限定條件的查詢

  找出傭金高于工資的60%的雇員信息

  select * from emp where comm>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>=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<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>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>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()-->求出全部的記錄數

  max()-->求出一組數據中的最大值

  min()-->求出一組數據中的最小值

  avg()-->求出平均值

  sum()-->求和

  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)>2000 group by deptno;

  程序報錯,提示avg(sal)>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)>2000;

  下面我們看一個這樣的需求:顯示非銷售人員工作名稱以及從事同一工作的雇員的月工資的總和,并且要滿足從事同一工作的雇員的月工資合計大于5000,輸出結果按照月工資的合計升序排列

  ·-首先我們查詢出全部的非銷售人員,限定條件job<>'SALESMAN'

  select * from emp where job<>'SALESMAN';

  ·-按照工作名稱分組,并且求出每組的工資總和

  select job,sum(sal) from emp

  where job<>'SALESMAN'

  group by job;

  ·-對分組的調價進行限制,工資總和大于5000

  select job,sum(sal) from emp

  where job<>'SALESMAN'

  group by job

  having sum(sal)>5000;

  ·-對查詢結果按照月工資的合計升序排列

  select job,sum(sal) from emp

  where job<>'SALESMAN'

  group by job

  having sum(sal)>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>(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>(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操作符的功能完全一樣)、>any(比里面最小的值要大)、<any(比里面最大的值要小)

  select * from emp

  where sal=any(select min(sal) from emp group by deptno);

  all操作符的一般用法:>all(比最大值要大)、<all(比最小值要小)

  select * from emp

  where sal>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-->修改全部

  update myemp set comm=1000;

  將編號為7899的雇員的工資修改為5000-->指定了更新條件

  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)>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>(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<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<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)>1500;

  --工作就出來了,之后再求全部的雇傭人數

  select e.job,count(e.empno)

  from emp e

  where e.job in(

  select job from emp

  group by job having min(sal)>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>(select avg(sal) from emp);

  --與部門表關聯,查出所在部門的信息

  select e.*,d.dname,d.loc from emp e,dept d

  where sal>(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>(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>(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部門工作的所有雇員的工資的雇員姓名和工資,部門名稱

  --在之前的程序上進行修改,使用>all,比最大的還要大

  select ename,sal

  from emp where sal>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>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>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-->表示的是一個字符串,有長度限制,255,

  number-->number(n):表示一個整數,數字的長度是n,可以使用int

  number(m,n):表示一個小數,數字小數長度為n,整數長度為m-n,可以使用float

  date-->表示日期的類型,日期要按照標準的日期格式進行存放

  clob-->大對象,表示大文本數據,一般可以存放4G的文本

  blob-->大對象,表示二進制數據,最大可以存放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 表名稱;

  思考下面的問題:現在有一張國家表,里面只有一個國家名稱的字段,內容如下:“中國、美國、巴西、荷蘭“,現在要求通過查詢實現對戰功能:

  中國->美國

  中國->巴西

  中國->荷蘭

  美國->中國

  美國->巴西

  美國->荷蘭

  ......

  分析:本程序只能使用笛卡爾積完成

  首先,建立一張表

  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<>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-->主鍵字段_pk

  --unique-->字段_uk

  --check-->字段_ck

  --foreign key-->父字段_子字段_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<=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<=10) temp where temp.m>5;

  如果現在要求輸出最后的4條呢?

  select * from (select rownum m,empno,ename,job,sal,hiredate from emp where rownum<=15) temp where temp.m>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張表。本程序中的所有代碼都是按照標準范式完成的,所以此時出現了以上的問題。

  在開發中減少多表查詢的方法可以通過冗余數據完成。

 

  

 

 

  

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>@ d:\a.sql或是sql>start d:\a.sql 2.edit 說明: 該命令可以編輯指定的sql腳本 案例: sql>edit d:\a.sql,這樣會把d:\a.sql這個文件打開 3.spool 說明: 該命令可以將sql*plus屏幕上的內容輸出到指定文件中去。 案例: sql>spool d:\b.sql 并輸入 sql>spool off 交互式命令 1.& 說明:可以替代變量,而該變量在執行時,需要用戶輸入。 select * from emp where job='&job'; 2.edit 說明:該命令可以編輯指定的sql腳本 案例:SQL>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> alter user 用戶名 identified by 新密碼 刪除用戶 概述:一般以dba的身份去刪除某個用戶,如果用其它用戶去刪除用戶則需要具有drop user的權限。 比如 drop user 用戶名 【cascade】 在刪除用戶時,注意: 如果要刪除的用戶,已經創建了表,那么就需要在刪除的時候帶一個參數cascade; 用戶管理綜合案例 概述:創建的新用戶是沒有任何權限的,甚至連登陸的數據庫的權限都沒有,需要為其指定相應的權限。給一個用戶賦權限使用命令grant,回收權限使用命令revoke。 為了給講清楚用戶的管理,這里我給大家舉一個案例。 SQL> conn xiaoming/m12; ERROR: ORA-01045: user XIAOMING lacks CREATE SESSION privilege; logon denied 警告: 您不再連接到 ORACLE。 SQL> show user; USER 為 "" SQL> conn system/p; 已連接。 SQL> grant connect to xiaoming; 授權成功。 SQL> conn xiaoming/m12; 已連接。 SQL> 注意: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> conn scott/tiger; 已連接。 SQL> grant select on scott.emp to xiaoming with grant option; 授權成功。 SQL> conn system/p; 已連接。 SQL> create user xiaohong identified by m123; 用戶已創建。 SQL> grant connect to xiaohong; 授權成功。 SQL> conn xiaoming/m12; 已連接。 SQL> grant select on scott.emp to xiaohong; 授權成功。 --如果是系統權限。 system給xiaoming權限時: grant connect to xiaoming with admin option 問題:如果scott把xiaoming對emp表的查詢權限回收,那么xiaohong會怎樣? 答案:被回收。 下面是我的操作過程: SQL> conn scott/tiger; 已連接。 SQL> revoke select on emp from xiaoming; 撤銷成功。 SQL> conn xiaohong/m123; 已連接。 SQL> 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> create profile lock_account limit failed_login_attempts 3 password_lock_time 2; SQL> alter user scott profile lock_account; 2.給賬戶(用戶)解鎖 SQL> alter user tea account unlock; 3.終止口令 為了讓用戶定期修改密碼可以使用終止口令的指令來完成,同樣這個命令也需要dba的身份來操作。 例子:給前面創建的用戶tea創建一個profile文件,要求該用戶每隔10天要修改自己的登陸密碼,寬限期為2天。看看怎么做。 SQL> create profile myprofile limit password_life_time 10 password_grace_time 2; SQL> alter user tea profile myprofile; 口令歷史 概述:如果希望用戶在修改密碼時,不能使用以前使用過的密碼,可使用口令歷史,這樣oracle就會將口令修改的信息存放到數據字典中,這樣當用戶修改密碼時,oracle就會對新舊密碼進行比較,當發現新舊密碼一樣時,就提示用戶重新輸入密碼。 例子: 1)建立profile SQL>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> 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>ALTER TABLE student add (classId NUMBER(2)); ? 修改一個字段的長度 SQL>ALTER TABLE student MODIFY (xm VARCHAR2(30)); ? 修改字段的類型/或是名字(不能有數據) 不建議做 SQL>ALTER TABLE student modify (xm CHAR(30)); ? 刪除一個字段 不建議做(刪了之后,順序就變了。加就沒問題,應為是加在后面) SQL>ALTER TABLE student DROP COLUMN sal;

  Oracle 筆記

  6

  ? 修改表的名字 很少有這種需求 SQL>RENAME student TO stu; ? 刪除表 SQL>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 > 3000; 問題:如何查找1982.1.1后入職的員工? SELECT ename,hiredate FROM emp WHERE hiredate >'1-1月-1982'; 問題:如何顯示工資在2000到3000的員工? SELECT ename,sal FROM emp WHERE sal >=2000 AND sal <= 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 >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 > (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) < 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) < 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>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 > all (SELECT sal FROM emp WHERE deptno = 30); 擴展要求: 大家想想還有沒有別的查詢方法。 SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30); 執行效率上, 函數高得多 ? 在多行子查詢中使用any操作符 問題:如何顯示工資比部門30的任意一個員工的工資高的員工姓名、工資和部門號? SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30); 擴展要求: 大家想想還有沒有別的查詢方法。 SELECT ename, sal, deptno FROM emp WHERE sal > (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 > 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 > 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<10000) where rn>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<10000 and rk>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<10000) where rn>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<=10)where rn>=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 <= 10; 如果后面加上rownum>=6是不行的, 4. 然后查出6-10條記錄 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM <= 10) WHERE rn >= 6; 5. 幾個查詢變化 a. 指定查詢列,只需要修改最里層的子查詢 只查詢雇員的編號和工資 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp) e WHERE ROWNUM <= 10) WHERE rn >= 6; b. 排序查詢,只需要修改最里層的子查詢 工資排序后查詢6-10條數據 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp ORDER by sal) e WHERE ROWNUM <= 10) WHERE rn >= 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 >2500 UNION SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 2).union all 該操作符與union相似,但是它不會取消重復行,而且不會排序。 SELECT ename, sal, job FROM emp WHERE sal >2500 UNION ALL SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';

  Oracle 筆記

  13

  該操作符用于取得兩個結果集的并集。當使用該操作符時,會自動去掉結果集中重復行。 3). intersect 使用該操作符用于取得兩個結果集的交集。 SELECT ename, sal, job FROM emp WHERE sal >2500 INTERSECT SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 4). minus 使用改操作符用于取得兩個結果集的差集,他只會顯示存在第一個集合中,而不存在第二個集合中的數據。 SELECT ename, sal, job FROM emp WHERE sal >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();

  }

  }

  }

  在得到連接那里,要去配置數據源,點擊控制面板-->系統和安全-->管理工具-->數據源(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.<init>(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> select lower(ename) from emp; 問題:將所有員工的名字按大寫的方式顯示。 SQL> select upper(ename) from emp; 問題:顯示正好為5個字符的員工的姓名。 SQL> select * from emp where length(ename)=5; 問題:顯示所有員工姓名的前三個字符。

  Oracle 筆記

  19

  SQL> select substr(ename,1,3) from emp; 問題:以首字母大寫,后面小寫的方式顯示所有員工的姓名。 SQL> select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename)-1)) from emp; 問題:以首字母小寫,后面大寫的方式顯示所有員工的姓名。 SQL> select lower(substr(ename,1,1)) || upper(substr(ename,2,length(ename)-1)) from emp; 問題:顯示所有員工的姓名,用“我是老虎”替換所有“A” SQL> 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> select trunc(sal/30), ename from emp; or SQL> 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> select * from emp where sysdate>=add_months(hiredate,8); 問題:顯示滿10年服務年限的員工的姓名和受雇日期。

  Oracle 筆記

  20

  SQL> select ename, hiredate from emp where sysdate>=add_months(hiredate,12*10); 問題:對于每個員工,顯示其加入公司的天數。 SQL> select floor(sysdate-hiredate) "入職天數",ename from emp; or SQL> select trunc(sysdate-hiredate) "入職天數",ename from emp; 問題:找出各月倒數第3天受雇的所有員工。 SQL> 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');-->這樣oracle會自動的將'10' -->10 create table t2 (id varchar2(10)); insert into t2 values(1); -->這樣oracle就會自動的將1 -->'1'; 我們要說的是盡管oracle可以進行隱含的數據類型的轉換,但是它并不適應所有的情況,為了提高程序的可靠性,我們應該使用轉換函數進行轉換。 ? to_char 你可以使用select ename, hiredate, sal from emp where deptno = 10;顯示信息,可是,在某些情況下,這個并不能滿足你的需求。 問題:日期是否可以顯示 時/分/秒 SQL> select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss') from emp; 問題:薪水是否可以顯示指定的貨幣符號 SQL> yy:兩位數字的年份 2004-->04 yyyy:四位數字的年份 2004年 mm:兩位數字的月份 8月-->08 dd:兩位數字的天 30號-->30 hh24: 8點-->20 hh12:8點-->08 mi、ss-->顯示分鐘\秒 9:顯示數字,并忽略前面0 0:顯示數字,如位數不足,則用0補齊 .:在指定位置顯示小數點 ,:在指定位置顯示逗號 $:在數字前加美元 L:在數字前面加本地貨幣符號 C:在數字前面加國際貨幣符號 G:在指定位置顯示組分隔符、 D:在指定位置顯示小數點符號(.) 問題:顯示薪水的時候,把本地貨幣單位加在前面 SQL> select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss'), to_char(sal,'L99999.99') from emp; 問題:顯示1980年入職的所有員工 SQL> select * from emp where to_char(hiredate, 'yyyy')=1980;

  Oracle 筆記

  21

  問題:顯示所有12月份入職的員工 SQL> 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>sysoper>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/tiger@myoral tables=(emp,dept) file=d:\e1.dmp 2.導出其它方案的表 如果用戶要導出其它方案的表,則需要dba的權限或是exp_full_database的權限,比如system就可以導出scott的表 E:\oracle\ora92\bin>exp userid=system/manager@myoral tables=(scott.emp) file=d:\e2.emp 特別說明:在導入和導出的時候,要到oracle目錄的bin目錄下。 3. 導出表的結構 exp userid=scott/tiger@accp tables=(emp) file=d:\e3.dmp rows=n 4. 使用直接導出方式 exp userid=scott/tiger@accp tables=(emp) file=d:\e4.dmp direct=y 這種方式比默認的常規方式速度要快,當數據量大時,可以考慮使用這樣的方法。 這時需要數據庫的字符集要與客戶端字符集完全一致,否則會報錯... ? 導出方案 導出方案是指使用export工具導出一個方案或是多個方案中的所有對象(表,索引,約束...)和數據。并存放到文件中。 1. 導出自己的方案 exp userid=scott/tiger@myorcl owner=scott file=d:\scott.dmp 2. 導出其它方案 如果用戶要導出其它方案,則需要dba的權限或是exp_full_database的權限,比如system用戶就可以導出任何方案 exp userid=system/manager@myorcl owner=(system,scott) file=d:\system.dmp ? 導出數據庫 導出數據庫是指利用export導出所有數據庫中的對象及數據,要求該用戶具有dba的權限或者是exp_full_database權限 增量備份(好處是第一次備份后,第二次備份就快很多了) exp userid=system/manager@myorcl 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/tiger@myorcl tables=(emp) file=d:\xx.dmp 2. 導入表到其它用戶 要求該用戶具有dba的權限,或是imp_full_database imp userid=system/tiger@myorcl tables=(emp) file=d:\xx.dmp touser=scott 3. 導入表的結構

  Oracle 筆記

  24

  只導入表的結構而不導入數據 imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp rows=n 4. 導入數據 如果對象(如比表)已經存在可以只導入表的數據 imp userid=scott/tiger@myorcl 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> 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> 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> alter tablespace sp01 add datafile ‘d:\test\sp01.dbf’ size 20m; 2. 增加數據文件的大小 SQL> alter tablespace 表空間名 ‘d:\test\sp01.dbf’ resize 20m; 這里需要注意的是數據文件的大小不要超過500m。 3. 設置文件的自動增長。 SQL> 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> create table goods(goodsId char(8) primary key, --主鍵 goodsName varchar2(30), unitprice number(10,2) check(unitprice>0), category varchar2(8), provider varchar2(30) ); SQL> 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> 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> alter table goods modify goodsName not null; 2. 增加身份證也不能重復 SQL> alter table customer add constraint xxxxxx unique(cardId); 3. 增加客戶的住址只能是’海淀’,’朝陽’,’東城’,’西城’,’通州’,’崇文’,’昌平’; SQL> 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 --------->ken ---------->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> conn system/manager; SQL> select distinct privilege from dba_tab_privs; SQL> 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> conn scott/tiger SQL> grant alter on emp to blake; 當然也可以用system,sys來完成這件事。 4.授予execute權限 如果用戶想要執行其它方案的包/過程/函數,則須有execute權限。 比如為了讓ken可以執行包dbms_transaction,可以授予execute權限。 SQL> conn system/manager SQL> grant execute on dbms_transaction to ken; 5.授予index權限 如果想在別的方案的表上建立索引,則必須具有index對象權限。 如果為了讓black可以在scott.emp表上建立索引,就給其index的對象權限 SQL> conn scott/tiger SQL> grant index on scott.emp to blake; 6.使用with grant option選項 該選項用于轉授對象權限。但是該選項只能被授予用戶,而不能授予角色 SQL> conn scott/tiger; SQL> grant select on emp to blake with grant option; SQL> conn black/shunping SQL> grant select on scott.emp to jones; ? 回收對象權限 在oracle9i中,收回對象的權限可以由對象的所有者來完成,也可以用dba用戶(sys,system)來完成。 這里要說明的是:收回對象權限后,用戶就不能執行相應的sql命令,但是要注意的是對象的權限是否會被級聯收回?【級

  Oracle 筆記

  34

  聯回收】 如:scott------------->blake-------------->jones select on emp select on emp select on emp SQL> conn scott/tiger@accp SQL> 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> conn system/manager; SQL> grant create session to 角色名 with admin option SQL> conn scott/tiger@myoral; SQL> grant select on scott.emp to 角色名; SQL> grant insert, update, delete on scott.emp to 角色名; 通過上面的步驟,就給角色授權了。 2.分配角色給某個用戶 一般分配角色是由dba來完成的,如果要以其它用戶身份分配角色,則要求用戶必須具有grant any role的系統權限。 SQL> conn system/manager; SQL> grant 角色名 to blake with admin option; 因為我給了with admin option選項,所以,blake可以把system分配給它的角色分配給別的用戶。 ? 刪除角色 使用drop role,一般是dba來執行,如果其它用戶則要求該用戶具有drop any role系統權限。 SQL> conn system/manager; SQL> drop role 角色名; 問題:如果角色被刪除,那么被授予角色的用戶是否還具有之前角色里的權限? 答案:不具有了 ? 顯示角色信息 1.顯示所有角色 SQL> select * from dba_roles; 2.顯示角色具有的系統權限 SQL> select privilege, admin_option from role_sys_privs where role='角色名'; 3.顯示角色具有的對象權限 通過查詢數據字典視圖dba_tab_privs可以查看角色具有的對象權限或是列的權限。 4.顯示用戶具有的角色,及默認角色 當以用戶的身份連接到數據庫時,oracle會自動的激活默認的角色,通過查詢數據字典視圖dba_role_privs可以顯示某個用戶具有的所有角色及當前默認的角色

  Oracle 筆記

  36

  SQL> 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=&aa;

  dbms_output.put_line('雇員名:'||v_ename);

  end;

  / 如果要把薪水也顯示出來,那么執行部分就應該這么寫:

  select ename,sal into v_ename,v_sal from emp where empno=&aa;

  相關說明: & 表示要接收從控制臺輸入的變量。 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=&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:thin@127.0.0.1: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> var income number

  SQL> call annual_incomec('scott') into: income;

  SQL> 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> 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=&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=&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<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<>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<=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;

  <<end_loop>>

  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 = &no;

  if v_sal < 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:thin@127.0.0.1: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:thin@127.0.0.1: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:thin@127.0.0.1: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:thin@127.0.0.1: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<=10;

  --在分頁時,大家可以把下面的sql語句當做一個模板使用

  select * from

  (select t1.*, rownum rn from (select * from emp) t1 where rownum<=10)

  where rn>=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<='||v_end||') where rn>='||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:thin@127.0.0.1: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<='||v_end||') where rn>='||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=&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=&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 < 1000 then

  update emp set sal = sal + 100 where empno = spno;

  when v_sal < 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='&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 = &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> 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> 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<1000的雇員映射到該視圖(view)

  create view myview as select * from emp where sal<1000; --為簡化操作,用一個視圖解決 顯示雇員編號,姓名和部門名稱

  create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno; 視圖之間也可以做聯合查詢

 

  

 

 

  

一、基礎

 

  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<>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 '"&Server.MapPath(".")&"\data.mdb" &"' 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 > 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())>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(@end-@start+1)+’+from T where rid not in(select top’+str(@str-1)+’Rid from T where Rid>-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

  光盤 B 2

  光盤 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 > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired

  AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)

  AND (@OriginalSize * 8 /1024) > @NewSize

  BEGIN -- Outer loop.

  SELECT @Counter = 0

  WHILE ((@Counter < @OriginalSize / 16) AND (@Counter < 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)=@OldOwner

  order by name

  OPEN curObject

  FETCH NEXT FROM curObject INTO @Name, @Owner

  WHILE(@@FETCH_STATUS=0)

  BEGIN

  if @Owner=@OldOwner

  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<30

  begin

  insert into test (userid) values(@i)

  set @i=@i+1

  end

  案例:

  有如下表,要求就裱中所有沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:

   Name score

   Zhangshan 80

   Lishi 59

   Wangwu 50

   Songquan 69

  while((select min(score) from tb_table)<60)

  begin

  update tb_table set score =score*1.01

  where score<60

  if (select min(score) from tb_table)>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 @list=@list+','+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>-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>=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 <> 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)如果選擇署名訂閱,則需要在發布服務器上添加訂閱服務器

  方法: [工具]->[復制]->[配置發布、訂閱服務器和分發的屬性]->[訂閱服務器] 中添加

  否則在訂閱服務器上請求訂閱時會出現的提示:改發布不允許匿名訂閱

  如果仍然需要匿名訂閱則用以下解決辦法

  [企業管理器]->[復制]->[發布內容]->[屬性]->[訂閱選項] 選擇允許匿名請求訂閱

  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 <> i.name or b.telphone <> 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

  MERGE INTO TLASTGPS T1 USING (SELECT '3109716' AS deviceid FROM dual) T2 ON (T1.deviceid=T2.deviceid) WHEN MATCHED THEN UPDATE SET status=0,y=693413.854883,x=603015.756594,hight=0,speed=0,direction=13,cartime=to_date('2016-09-01 11:35:20','yyyy-MM-dd hh24:mi:ss') WHEN NOT MATCHED THEN INSERT (status,y,x,hight,speed,direction,cartime,deviceid) values(0,693413.854883,603015.756594,0,0,13,to_date('2016-09-01 11:35:20','yyyy-MM-dd hh24:mi:ss'),'3109716')

【oracle的sql語句】相關文章:

Oracle的sql語句模擬試題及答案08-27

SQL查詢語句大全09-22

sql外鍵語句示范06-21

使用sql語句查詢日期的方法09-17

oracle數據庫基本語句02-08

Oracle數據庫語句大全05-02

Oracle認證:ORACLE綁定變量BINDPEEKING08-26

Oracle認證:Oracle避免全表掃描方式08-26

Oracle認證:Oracle內存結構研究-PGA篇08-26

主站蜘蛛池模板: 洞头县| 汝城县| 万山特区| 汝阳县| 鸡东县| 赤壁市| 论坛| 安化县| 会东县| 黔西县| 涞水县| 伊川县| 平昌县| 晋城| 上虞市| 揭西县| 丹寨县| 阿克| 巴林右旗| 南陵县| 集贤县| 乌审旗| 襄垣县| 汉中市| 营口市| 沁水县| 西宁市| 乌什县| 富源县| 枣阳市| 句容市| 吉林省| 府谷县| 滨海县| 罗定市| 巴马| 百色市| 伊金霍洛旗| 金沙县| 汾西县| 黄浦区|