oracle練習題-scott實例


Oracle系列《一》:簡單SQL與單行函數

使用scott/密碼用戶下的emp表和dept表完成下列練習,表的結構說明如下

emp員工表(empno員工號/ename員工姓名/job工作/mgr上級編號/hiredate受雇日期/sal薪金/comm佣金/deptno部門編號)

dept部門表(deptno部門編號/dname部門名稱/loc地點)

工資 = 薪金 + 佣金


【1】登錄Oracle數據庫
sqlplus/nolog
conn scott/密碼
若是使用SYS的賬號進行登錄的話,則使用以下語句
conn / as sysdba

【2】顯示當前用戶
show user;

【3】查看當前用戶的所有表
SELECT * FROM tab;


【4】EMP表內容查詢
SELECT * FROM emp;
出錯,原因是沒有找到該表,因為該表時SCOTT用戶的表,所以查詢時應該加上scott.emp就可以了


【5】查詢一張表的結構,例如dept表
desc dept;

【6】在雇員表中查詢雇員的編號、姓名、工作
SELECT empno,ename,job FROM emp;

【7】可以為列名取別名,在Linux下Oracle如果英文別名不加上雙引號則會變成大寫
SELECT empno 編號,ename 姓名,job 工作 FROM emp;

【8】查詢所有的工作
SELECT DISTINCT job FROM emp;
工作可能會重復,加上DISTINCT關鍵字

【9】練習:若要求按照以下的格式進行結果輸出,如 NO:7469,Name:SMITH,Job:CLERK
SELECT'NO:'||empno||',Name:'||ename||',Job:'||job FROM emp;

【10】要求列出每個雇員的姓名及年薪
SELECT ename,sal*12 income FROM emp;
這里年薪最好用別名進行標識,可以一眼就能明白

【11】查看每月可以得到獎金的雇員信息
SELECT * FROM emp WHERE comm is NOT NULL;

【12】要求基本工資大於1500,同時可以領取獎金的雇員信息
SELECT * FROM emp WHERE sal>1500 AND commis NOT NULL;
如果是或的是關系,則使用 OR

【13】查詢基本工資不大於1500,同時不可以領取獎金的雇員信息
SELECT * FROM emp WHERE NOT(sal>1500 ANDcomm is NOT NULL);

【14】查詢在1981年雇佣的全部雇員信息,BETWEEN .. AND 包含等於的情況
SELECT * FROM emp
WHERE hiredate BETWEEN '01-JAN-81' AND '31-DEC-81';

【15】Oracle對大小敏感,所以查詢時名字要區分大小寫

【16】要求查詢出雇員編號不是 7369、7499的雇員信息
SELECT * FROM emp
WHERE empno NOT IN(7369,7499);

【17】SQL中LIKE語句要注意通配符 % 和 _
SELECT * FROM emp
WHERE hiredate LIKE '%81%';

【18】查看雇員編號不是7369的雇員信息,使用<>或!=
SELECT * FROM emp
WHERE empno<>7369;

【19】要求對雇員的工資由低到高進行排序,升序為默認(ASC),降序(DESC)
SELECT * FROM emp
order BY sal;

【20】查看出部門號為10的雇員信息,查詢的信息按照工資從高到低,若工資相等則按雇用日期從早到晚排列
SELECT * FROM emp
WHERE deptno=10
order BY sal DESC,hiredate ASC;

數據庫系統中,每個數據庫之間區別最大的就是在函數的支持上,單行函數是最簡單的函數,單行函數分為
1、字符函數:接受字符輸入並且返回字符或數值
2、數值函數:接受數值輸入並返回數值
3、日期函數:對日期型數據進行操作
4、轉換函數:將一種數據類型轉換為另一種數據類型
5、通用函數:NVL、DECODE 函數

字符函數:
【1】大小寫轉換 UPPER 和 LOWER
SELECT UPPER('smith') FROM dual;
【2】將雇員姓名變為開頭字母大寫,INITCAP
SELECT INITCAP(ename) FROM emp;

字符函數中有連接函數CONCAT,但不如 || 好用,還有字符串處理的一些函數
字符串截取:substr()
字符串長度:length()
內容替換:replace()
SELECT substr('hello',1,3),length('hello'),replace('hello','l','x') FROM dual;
這里注意的是Oracle中字符串截取從0和從1開始都是一樣的,謹防面試提問

【3】要求顯示所有雇員的姓名及姓名的后3個字符
SELECT ename,SUBSTR(ename,LENGTH(ename)-2)FROM emp;
以上操作顯得較為麻煩,substr()函數是可以倒着截取
SELECT ename,SUBSTR(ename,-3,3) FROM emp;

數值函數:
1、四舍五入:ROUND()
2、截斷小數位:TRUNC()
3、取余(取模):MOD
SELECT ROUND(789.536) FROM dual;
【1】保留2位小數,(如果是-2則對整數進行四舍五入,變為800了)
SELECT ROUND(783.56,2) FROM dual;
【2】使用MOD()函數進行取余操作
SELECT MOD(10,3) FROM dual;

日期函數:
1、日期 - 數字 = 日期
2、日期 + 數字 = 日期
3、日期 - 日期 = 數字(天數)
4、日期 - 日期 = 數字(月數)
---日期 - 日期 = 數字(月數
select months_between('19-12月-1999','19-3月-1999') from dual;
select months_between(to_date('2000-05-20','yyyy-mm-dd'),to_date('2005-05-20','yyyy-mm-dd')) from dual;
---日期 - 日期 = 數字(天數)
select to_date('20170611', 'yyyymmdd') - to_date('20170507', 'yyyymmdd')
from dual;
select ceil((To_date('2017-05-02 00:00:00', 'yyyy-mm-dd hh24-mi-ss') -
To_date('2016-04-30 23:59:59', 'yyyy-mm-dd hh24-mi-ss'))) "相差天數"
FROM DUAL;


【1】求出當前日期
SELECT SYSDATE FROM dual;

Oracle提供了以下的日期函數支持:
MONTHS_BETWEEN():求出給定日期范圍的月數
ADD_MONTHS():在指定日期上加上指定的月數,求出之后的日期
NEXT_DAY():下一個的今天的日期
LAST_DAY():求出給定日期的最后一天日期

【2】求出從雇用日期到今天所有雇員的雇員編號、姓名和月數
SELECT empno,ename,ROUND(MONTHS_BETWEEN(SYSDATE,hiredate)) FROM emp;

【3】驗證 ADD_MONTHS()、NEXT_DAY()、LAST_DAY()
SELECT ADD_MONTHS(SYSDATE,4) FROM DUAL;
SELECT NEXT_DAY(SYSDATE,'MON') FROM DUAL;
SELECT LAST_DAY(SYSDATE) FROM DUAL;

轉換函數:
1、TO_CHAR(): 將日期或數值轉換成字符串
2、TO_NUMBER():將字符串轉換成數字
3、TO_DATE(): 將字符串轉換成日期

【1】將年月日進行分開,要指定拆分的通配符,yyyy-mm-dd
SELECT empno,ename,TO_CHAR(hiredate,'yyyy')datetime FROM emp;

【2】將薪水的數字進行格式化,'$99,999'表示美元,'L99,999'表示當地貨幣
SELECT empno,ename,TO_CHAR(sal,'99,999') salary FROM emp;

【3】TO_NUMBER()驗證
SELECT TO_NUMBER('123')+TO_NUMBER('123') FROM DUAL;

【4】TO_DATE()驗證,如下例子執行后顯示為 11-JUL-11
SELECT TO_DATE('2011-7-11','yyyy-mm-dd')FROM DUAL;

通用函數:
【1】求出每個雇員的年薪(應算上獎金)
SELECT empno,ename,(sal+comm)*12 FROM emp;
由於comm中有NULL,NULL值計算后還是NULL,正確如下:
SELECT empno,ename,NVL(comm,0),(sal+NVL(comm,0))*12income FROM emp;
NVL可以理解為將NULL值轉換為具體的內容,這里是0

【2】DECODE()函數,該函數類似於 IF ... ELSEIF...ELSE
語法如下:
DECODE(col/expression,選擇1,結果1[,選擇2,結果2,...,默認])
驗證DECODE()函數
SELECT empno,ename,hiredate,
DECODE(job,'CLERK','業務員','SALESMAN','銷售人員','MANAGER','經理','ANALYST','分析員','PRESIDENT','總裁') 職位
FROM emp;

SQL簡單語句練習:

【1】找出佣金高於薪金的60%的員工
SELECT * FROM emp WHERE comm>sal*0.6

【2】找出部門10中所有經理(MANAGER)和部門20中所有辦事員(CLERK)的詳細資料
SELECT * FROM emp
WHERE (deptno=20 AND job='MANAGER')
OR (deptno=10 AND job='CLERK');

【3】找出既不是經理又不是辦事員但其薪金大於或等於2000的所有員工的資料
SELECT * FROM emp
WHERE job NOT IN('MANAGER','CLERK') AND sal >=2000;

【4】找出有獎金的員工的不同國祚
SELECT DISTINCT job FROM emp
WHERE comm IS NOT NULL;

【5】找出各月倒數第3天受雇的所有員工
SELECT * FROM emp
WHERE LAST_DAY(hiredate)-2=hiredate;

【6】找出早於12年前受雇的員工
SELECT * FROM emp
WHERE MONTHS_BETWEEN(sysdate,hiredate)/12 > 12;

【7】顯示剛好為5個字符的員工的姓名
SELECT ename FROM emp
WHERE length(ename)=5;

【8】顯示不帶有"R"的員工的姓名
SELECT ename FROM emp
WHERE ename NOT LIKE '%R%';

【9】顯示員工的姓名和受雇日期,將最老的員工排在最前
SELECT * FROM emp
order BY hiredate;

【10】顯示所有員工的姓名,加入公司的年份和月份,按受雇日期所在月排序,若月份相同則按年份排序
SELECT ename,TO_CHAR(hiredate,'yyyy')year,TO_CHAR(hiredate,'mm') month FROM emp
ORDER BY month,year;

【11】找出在2月受聘的員工
SELECT * FROM emp
WHERE TO_CHAR(hiredate,'mm')=2;

【12】以年月日方式顯示所有員工服務年限
SELECTename,TRUNC(MONTHS_BETWEEN(sysdate,hiredate)/12) year,
TRUNC(MOD(MONTHS_BETWEEN(sysdate,hiredate),12)) month,
TRUNC(MOD(sysdate-hiredate,30)) day
FROM emp;


Oracle系列《二》:多表復雜查詢和事務處理
多表查詢應該注意去除笛卡爾積,一般多個表時會為表起個別名

【1】要求查詢雇員的編號、姓名、部門編號、部門名稱及部門位置
SELECT e.empno,e.ename,d.deptno,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno = d.deptno;

【2】要求查詢每個雇員的姓名、工作、雇員的直接上級領導的姓名(表自關聯)
SELECT e.ename,e.job,m.ename
FROM emp e,emp m
WHERE e.mgr = m.empno;

【3】對【2】進行擴充,將雇員所在部門名稱同時列出
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;

【4】查詢每個雇員的姓名、工資、部門名稱,工資在公司的等級(salgrade),及其領導的姓名所在公司的等級
<1>先確定工資等級表的內容
SELECT * FROM salgrade;

<2>查詢每個雇員的姓名、工資、部門名稱和工資在公司的等級
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 ANDs.hisal;

<3>查詢其領導姓名及工資所在公司的等級
SELECTe.ename,e.sal,d.dname,s.grade,m.ename,m.sal,ms.grade
FROM emp e,dept d,salgrade s,emp m,salgrade ms
WHERE e.deptno = d.deptno AND e.sal BETWEEN s.losalAND s.hisal
AND e.mgr = m.empno AND m.sal BETWEEN ms.losal ANDms.hisal;

【5】左連接與右連接的概念,"+"在等號左邊表示右連接,反之,左連接
查詢雇員的編號、姓名及其領導的編號、姓名
SELECT e.empno,e.ename,m.empno,m.ename
FROM emp e,emp m
WHERE e.mgr = m.empno(+);
就發現將KING的那條記錄也連過來了

SQL1999語法中有如下幾種連接(了解)
1、交叉連接CROSS JOIN,產生笛卡爾積
SELECT * FROM emp CROSS JOIN dept;
2、自然連接NATURAL JOIN,自動進行關聯字段的匹配
SELECT * FROM emp NATURAL JOIN dept;
3、使用USING子句,直接關聯操作列
SELECT * FROM emp JOIN dept USING(deptno)
WHERE deptno=30;
4、使用ON子句,用戶自己編寫的條件
SELECT * FORM emp JOIN dept ON(emp.deptno =dept.deptno)
WHERE deptno=30;
5、左連接(左外連接、LEFT (OUTER) JOIN)、右連接(右外連接、RIGHT (OUTER) JOIN)

組函數及分組統計
1、COUNT():求出全部記錄數
2、MAX():求出一組中最大值
3、MIN():求出最小值
4、AVG():求出平均值
5、SUM():求和

【1】求出每個部門的雇員數量
SELECT deptno,count(empno)
FROM emp
GROUP BY deptno;

【2】按部門分組,並顯示部門的名稱,及每個部門的員工數
SELECT d.dname,COUNT(e.empno)
FROM emp e,dept d
WHERE e.deptno=d.deptno
GROUP BY d.dname;

【3】要求顯示平均工資大於2000的部門編號和平均工資
SELECT deptno,AVG(sal)
FROM emp
WHERE AVG(sal)>2000
GROUP BY deptno;
出錯,WHERE子句中不能出現分組函數的條件,要使用HAVING子句
上述語句應該改為如下
SELECT deptno,AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal)>2000

【4】顯示非銷售人員工作名稱以及從事同一工作雇員的月工資總和,並且要求從事同一工作的雇員月工資合計大於$5000,
輸出結果按月工資的合計升序排序
<1>按工作分組,求出非銷售人員的月工資總和
SELECT job,SUM(sal)
FROM emp
WHERE job<>'SALESMAN'
GROUP BY job;
<2>對分組條件進行限制,然后進行排序,HAVING子句不能使用別名
SELECT job,SUM(sal) totalSal
FROM emp
WHERE job<>'SALESMAN'
GROUP BY job
HAVING SUM(sal) > 5000
ORDER BY totalSal;

【3】分組函數可以嵌套使用,但是在SELECT列中就不能再出現該分組條件的列名了
SELECT deptno,MAX(AVG(sal))
FROM emp
GROUP BY deptno;
出錯!修改如下
SELECT MAX(AVG(sal))
FROM emp
GROUP BY deptno;

【4】查詢出比7654工資要高的全部雇員的信息
<1>首先要查詢雇員編號7654的工資
SELECT sal FROM emp WHERE empno=7654;
<2>以上述條件的結果最后后續查詢的依據
SELECT * FROM emp
WHERE sal>(SELECT sal FROM emp WHERE empno=7654);

子查詢在操作中分為以下三類:
1、單列子查詢:返回的結果是一列的內容
2、單行子查詢:返回多個列,也可能是一條記錄
3、多行子查詢:返回多個記錄

【1】要求查詢工資比7654高,同時與7788從事相同工作的全部雇員
SELECT * FROM emp
WHERE sal>(SELECT sal FROM emp WHERE empno=7654)
AND job=(SELECT job FROM emp WHERE empno=7788);

【2】要求查詢 部門名稱、部門員工數、部門平均工資,部門的最低收入雇員的姓名
<1>查詢部門員工數、部門平均工資
SELECT deptno,COUNT(empno),AVG(sal)
FROM emp
GROUP BY deptno;
<2>查詢部門的名稱,及最低收入雇員姓名,要進行表關聯(子查詢)
SELECT d.dname,ed.c,ed.a,e.ename
FROM dept d,(
SELECTdeptno,COUNT(empno) c,AVG(sal) a,MIN(sal) min
FROM emp
GROUP BYdeptno) ed, emp e
WHERE d.deptno=ed.deptno AND e.sal = ed.min;

若上述存在兩個最低工資的情況,則會出錯,在子查詢中存在以下3種查詢的操作符號
IN:指定一個查詢范圍,例如查詢每個部門的最低工資(返回值有多個)
SELECT * FROM emp
WHERE sal IN(SELECT MIN(sal) FROM emp GROUP BYdeptno);

ANY:=ANY(與IN操作一樣)、>ANY(比最小大)、<ANY(比最大小)
SELECT * FROM emp
WHERE sal <ANY(SELECT MIN(sal) FROM emp GROUP BYdeptno);

ALL: >ALL(比最大要大)、<ALL(比最小的小),SQL語句類似上面

SQL多列子查詢示例如下
SELECT * FROM emp
WHERE (sal,NVL(comm,-1)) IN
(SELECTsal,NVL(comm,-1) FROM emp WHERE deptno=20);


數據庫更新操作INSERT、UPDATE、DELETE

【1】復制一張表,例如復制EMP表為MYEMP
CREATE TABLE MYTEMP AS SELECT * FROM emp;

【2】將編號為7899的雇員的領導取消
UPDATE myemp SET mgr=null WHERE empno=7899;

【3】更新時,一定要注意不能批量更新(加上WHERE子句),多列更新例子如下
UPDATE myemp SET mgr=null,comm=null WHEREempno IN(7369,8899);

【4】刪除掉全部領取獎金的雇員
DELECT FROM emp WHERE comm is NOT NULL;

事務處理 ACID
A:Atomicity 原子性:事務中的操作或者都完成,或者都取消
C:Consistency 一致性:事務中的操作保證數據庫中的數據不會出現邏輯上不一致的情況
I:Isolation 隔離性:當前的事務與其他未完成的事務是隔離的
D:Durability 持久性:在COMMIT之后,數據永久保存在數據庫中,在此之前,事務的操作都可以回滾

驗證事務過程:
<1>創建一張臨時表,只包含部門10
CREATE TABLE emp10 AS SELECT * FROM emp WHEREempno=10;
<2>刪除emp10中的7782雇員
DELETE FROM emp10 WHERE empno=7782;
再打開另一個窗口,發現數據還存在,此時如果可以使用以下的兩種命令進行事務處理
COMMIT 和 ROLLBACK 提交事務和回滾事務

SQL查詢練習
【1】列出至少一個員工的所有部門
SELECT d.*,ed.cou FROM dept d,(
SELECTdeptno,COUNT(empno) cou FROM emp
GROUP BY deptno
HAVINGCOUNT(empno) > 1) ed
WHERE d.deptno=ed.deptno;

【2】列出部門名稱和這些部門的員工信息,同時列出那些沒有員工的部門
SELECT d.deptno,d.dname,e.empno,e.ename
FROM dept d,emp e
WHERE d.deptno = e.deptno(+);

【3】列出所有"CLERK"(辦事員)的姓名及其部門名稱,部門的人數
<1>關聯dept表
SELECT e.ename,d.dname
FROM emp e,dept d
WHERE e.deptno=d.deptno and e.job='CLERK';
<2>使用GROUP BY 完成部門分組人數
SELECT e.ename,d.dname,ed.cou FROM emp e,deptd,(
SELECTdeptno,COUNT(empno) cou FROM emp
GROUP BY deptno) ed
WHERE job='CLERK' AND e.deptno=d.deptno ANDed.deptno=e.deptno;


Oracle系列《三》:表、(約束)索引、序列、視圖的使用
一、創建、刪除、修改表

建立表:Oracle中主要數據類型 VARCHAR2、NUMBER、DATE、CLOB(大量文本)、BLOB(圖片、音樂、電影)
如果只能復制一張表的結構,但不復制內容,則加上一個不可能成立的條件即可,例如
CREATE TABLE tmp AS (SELECT * FROM emp WHERE 1=2)

例如創建表Person如下:
CREATE TABLE person(
pid VARCHAR2(18),
name VARCHAR2(30),
age NUMBER(3),
birthday DATE,
sex VARCHAR(2) DEFAULT 'M'
);

如果發現創建表后需要添加特定的列,例如address列,則可以使用ALTER TABLE命令
ALTER TABLE person ADD(address VARCHAR2(20));

修改表中的列屬性
ALTER TABLE person MODIFY(address VARCHAR2(30));

在數據庫程序開發中,很少去修改表結構,在IBM DB2中就沒有提供ALTER TABLE命令

在Oracle中提供RENAME命令對表進行重命名
RENAME person to personer;

在Oracle中要清空一張表的數據,但又不需要回滾,需要立即釋放資源(與DELETE區別)
TRUNCATE TABLE personer;
(與DROP TABLE區別:前者刪除內容,后者刪除表)
二、表的約束

約束分類:主鍵約束、唯一約束、檢查約束、非空約束、外鍵約束

添加約束如下:
CREATE TABLE person(
pid VARCHAR2(18),
name VARCHAR2(30) NOT NULL,
age NUMBER(3) CHECK(age BETWEEN 0 AND 150),
birthday DATE,
sex VARCHAR(2) DEFAULT 'M' ,
CONSTRAINTperson_pid_pk PRIMARY KEY(pid),
CONSTRAINT person_name_ukUNIQUE(name),
CONSTRAINT person_sex_ck CHECK(sexIN('M','F'))
);

以上約束可以采取自動命名和手動命名

現在要再添加一張表,使用主-外鍵約束
CREATE TABLEbook(
bid NUMBER PRIMARY KEY,
bname VARCHAR(20),
bprice NUMBER(5,2),
pid VARCHAR2(18),
CONSTRAINT person_book_pid_fk FOREIGN KEY(pid)REFERENCES person(pid)
);

這時候如果要刪除掉person表的話,就會出現錯誤,此時可以使用強制性的刪除手段
DROP TABLEperson CASCADE CONSTRAINT;
但是這種做法一般不用

如果在person 和 book 表中添加記錄,而在person表中進行刪除一條記錄時,假設該記錄的pid被
book表引用,那么會出現刪除錯誤。如果希望一個表中的數據在刪除時,能自動刪除對應字表的記錄,
可以使用級聯刪除的操作

CREATE TABLEbook(
bid NUMBER PRIMARY KEY,
bname VARCHAR(20),
bprice NUMBER(5,2),
pid VARCHAR2(18),
CONSTRAINT person_book_pid_fk FOREIGN KEY(pid)REFERENCES person(pid) ON DELETE CASCADE
);

添加約束語法如下:
ALTER TABLE 表名稱 ADD CONSTRAINT 約束名稱 約束類型(約束字段);
約束類型命名規則:
PRIMARY KEY:主鍵字段_PK
UNIQUE:字段_UK
CHECK:字段_CK
FOREIGN KEY:父子段_子字段_FK

ALTERTABLE person ADD CONSTRAINT person_pid_PK PRIMARY KEY(pid);
ALTERTABLE person ADD CONSTRAINT person_name_UK UNIQUE(name);
ALTERTABLE person ADD CONSTRAINT person_age_CK CHECK(age BETWEEN 0 AND 150);

ALTERTABLE book ADD CONSTRAINT person_book_pid_fk FOREIGN KEY(pid) REFERENCESperson(pid)
ON DELETECASCADE;

刪除約束語法如下:
ALTER TABLE 表名稱 DROP CONSTRAINT 約束名稱;

ALTERTABLE person DROP CONSTRAINT person_age_CK;
ALTERTABLE book DROP CONSTRAINT person_book_pid_fk;

ROWNUM偽列

SELECT ROWNUM,empno,ename FROM emp;
ROWNUM采用自動編號的形式出現

加入只想顯示前5條記錄,那么ROWNUM<=5
SELECT ROWNUM,empno,ename FROM emp;
WHEREROWNUM<=5;

但是如果要查詢5-10條的記錄的話,則查詢不出,只能采用子查詢的方式
SELECT * FROM (SELECT ROWNUM m,empno,ename
FROM emp
WHERE ROWNUM<=10) tmp
WHEREtmp.m>5;

不好的查詢思路:
select ROWNUM,empno,job,mgr from empt where rownum<=10
MINUS
select ROWNUM,empno,job,mgr from empt where rownum<=5
集合操作:在Oracle中提供了3類集合操作:並、交、差
UNION:將多個查詢結果組合到一個查詢結果之中,沒有重復值
UNION ALL:與UNICON不同的是包含重復值
INTERSECT:返回多個查詢結果中相同的部分
MINUS:返回兩個查詢結果的差集

驗證UNION和UNION ALL
CREATE TABLE emp20 AS SELECT * FROM emp WHERE deptno=20; (5條記錄)
SELECT * FROM emp UNION SELECT * FROM emp20; (14條記錄)
SELECT * FROM emp UNION ALL SELECT * FROM emp20; (19條記錄)

驗證MINUS 和 INTERSECT
SELECT * FROM emp MINUS SELECT * FROM emp20; (9條記錄)
SELECT * FROM emp INTERSECT SELECT * FROM emp20; (5條記錄)

案例:
主鍵約束添加刪除
1、創建表的同時創建主鍵約束
create table accounts ( accounts_number number primary key, accounts_balance number );

2、刪除表中已有的主鍵約束
SELECT * FROM USER_CONS_COLUMNS WHERE TABLE_NAME='accounts';
找出主鍵名 ALTER TABLE ACCOUNTS DROP CONSTRAINT SYS_C003063;
3、向表中添加主鍵約束 ALTER TABLE ACCOUNTS ADD CONSTRAINT PK_ACCOUNTS PRIMARY KEY(ACCOUNTS_NUMBER);

Oracle中視圖的操作

1、創建視圖
CREATE VIEW 視圖名稱 AS 子查詢
這條子查詢是非常復雜的語句
CREATE VIEW empv20 AS
SELECT empno,ename,job,hiredate
FROM emp
WHERE deptno=20;
2、查詢視圖
SELECT* FROM empv20;

3、刪除視圖
DROPVIEW empv20;

如果要修改視圖,則要先刪除視圖,在Oracle為了方便用戶修改視圖,提供了一個替換的命令
CREATE ORREPLACE 視圖名稱 AS 子查詢

視圖可以封裝復雜的查詢,例如查詢部門名稱,部門的人數,平均工資以及最低工資的雇員
CREATE OR REPLACE VIEW empv20 AS
SELECT d.dname,ed.c,ed.a,e.ename FROM dept d,(
SELECT deptno,COUNT(empno) c, AVG(sal) a,MIN(sal) minsal
FROM emp
GROUP BY deptno) ed,emp e
WHERE d.deptno=ed.deptno AND e.sal=ed.minsal;

在開中發每次都寫這么長的SQL語句不方便,可以將其建立成視圖

如果對視圖進行更新操作,在視圖中不應該包含真實數據,按以下命令進行操作
UPDATE empv20 SET deptno=30 WHERE empno=7369;
發現視圖已經正常更新,因為emp表中7369編號已經修改為30了,所以在創建視圖是有條件的
SQL提供了兩個重要的參數

WITH CHECKOPTION:不能更新視圖的創建條件
CREATE OR REPLACE VIEW empv20 AS
SELECT * FROM emp WHERE deptno=20
WITH CHECK OPTION;

創建條件不能進行更新了,但其他字段仍然可以更新
UPDATE empv20 SET ename='wilson'WHERE empno=7369;

所以這時可以使用視圖的第2個條件:創建只讀視圖
CREATE OR REPLACE VIEW empv20 AS
SELECT * FROM emp WHERE deptno=20
WITH READ ONLY;

Oracle系列《四》:數據庫的設計分析
一、序列的使用

在很多數據庫系統中都存在一個自動增長的列,如果在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);
將這條SQL執行5次,然后進行查表操作
SELECT * FROM testseq;

可以發現,nextval的內容始終在自動增長,而curr使用取出當前操作的序列的結果,該序列增長幅度為1
如果要進行修改,則加上 INCREMENT BY 長度的語句

DROP SEQUENCE myseq;
CREATE SEQUENCE myseq INCREMENT BY 2;

發現每次取出的結果都是奇數 1,3,5,7,9,序列是從1開始的,我們可以指定序列的開始位置,例如
CREATE SEUENCE myseq MAXVALUE 10 INCREMENT BY 2 START WITH 2 CACHE 2 CYCLE;

二、同義詞的概念(了解)

SELECT SYSDATE FROM dual;
dual是一張虛擬表,該表在SYS用戶下有定義,可以使用以下語句查詢到
SELECT * FROM tab WHERE TNAME='DUAL';
此表在SYS下,但SCOTT用戶卻可以直接通過表名稱訪問,正常情況下我們是需要使用"用戶名.表名稱"
該情況就是同義詞的作用

創建同義詞:
CREATE synonym 同義詞名稱 FOR 用戶名.表名稱;
例如,將scott.emp 定義 emp 的同義詞
CREATE synonym emp FOR scott.emp;

刪除同義詞
DROP synonym emp;
同義詞這種特性只適合於Oracle數據庫

三、用戶管理(*)

創建用戶: CREATE USER 用戶名 IDENTIFIED BY 密碼;
CREATE USER test IDENTIFIED BY test123;

打開一個新的窗口使用test用戶登錄,發現其沒有session權限無法進行登錄,此時要進行授權
GRANT CREATE SESSION TO test;
將創建SESSION權限給test用戶,之后該用戶可以正常登錄,但是其沒有創建表的權限

Oracle中可以將多個權限定義成一組角色,分配該角色給用戶即可
在Oracle中主要提供了兩個角色:CONNECT、RESOURCE,將這兩個角色賦予test用戶
GRANT CONNECT,RESOURCE TO test;

管理員對用戶密碼進行修改:
ALTER USER test IDENTIFIED BY hello;
在一般系統中,在用戶進行第一次登錄時可以修改密碼,可以使用如下方式
ALTER USER 用戶名 PASSWORD EXPIRE;
ALTER USER test PASSWORD EXPIRE;
這時會提示用戶輸入舊口令及新的密碼

鎖住用戶和對用戶解鎖
ALTER USER test ACCOUNT LOCK;
ALTER USER test ACCOUNT UNLOCK;

此時,想查詢SCOTT用戶下的表EMP,發現沒有權限,執行如下命令即可
GRANT SELECT,DELETE ON scott.emp TO test;

收回權限的命令:
REVOKE SELECT,DELETE ON scott.emp FROM test;

數據庫的備份與恢復
數據庫備份:exp
數據庫恢復:imp

嵌套表的概念(了解)

嵌套表:在一個表中還包含另外一個子表
首先為嵌套表指定類型,該類型需要單獨定義
CREATE TYPE project_ty AS OBJECT(
priodNUMBER(4),
pronameVARCHAR2(30),
prodate DATE
);
/
該類型創建成后,不意味着此類型能夠直接使用,要為此類型指定一個名稱
CREATE TYPE project_nt AS TABLE OF project_ty
/
這樣就可以使用project_nt表示project_ty類型,現在根據此類型創建department表
CREATE TABLE department(
deptno NUMBER(2) PRIMARY KEY,
dname VARCHAR2(50) NOT NULL,
projectsproject_nt
)NESTED TABLE projects STORE ASproject_nt_tab_temp;

如果要進行數據插入的話
INSERT INTO department(deptno,dname,projects)VALUES(
1,'tech',
project_nt(
project_ty(1001,'ERP',SYSDATE),
project_ty(1002,'CRM',SYSDATE)
)
);

查詢部門表,可以返回多個項目
SELECT * FROM department;

如果需要查看一個部門的全部項目的話,查詢嵌套表
SELECT * FROM TABLE
(SELECT projectsFROM department WHERE deptno=1);

更新編號為1001的項目名稱
UPDATE TABLE (SELECT projects FROM departmentWHERE deptno=1) pro
SET VALUES(pro)=project_ty('1001','APR',SYSDATE) WHEREpro.proid=1001;

可變數組的概念:是嵌套表的升級版 ... (有用到再了解)

數據庫范式的概念

第一范式:所有的信息都集中在一張表上,例如
CREATE TABLE person(
pid NUMBER(4) PRIMARY KEY,
nameVARCHAR2(50),
infoVARCHAR(200)
);

第一范式會出現問題,例如創建一張學生選課表
CREATE TABLE selectCourse(
stunoVARCHAR2(50),
stunameVARCHAR2(50),
stuage NUMBER,
cnameVARCHAR2(50),
grade NUMBER,
credit NUMBER
);

以上不僅所有的課程信息冗余了,而且還存在以下的問題:
1、沒有學生選該門課,那么該門課就消失了
2、課程本身有編號,按照以上設計,課程編號肯定重復
3、要更改課程信息,則要修改許多記錄

使用第二范式進行修改
CREATE TABLE student(
stuno VARCHAR2(10) PRIMARY KEY,
stunameVARCHAR2(20),
stuage NUMBER
);

CREATE TABLE course(
cid NUMBER(5)PRIMARY KEY,
cnameVARCHAR2(20),
credit NUMBER
);

CREATE TABLE selectCourse(
stunoVARCHAR2(50),
cid NUMBER(5),
grade NUMBER,
設置主-外鍵關系
);

以上設計解決了以下問題:
1、學生不選課,課程不會消失
2、更新課程的時候直接更新課程表
3、所有關聯關系在關系表中體現

這里是完成了多-多關系

使用第三范式:
按照第二范式的設計一張學生表,包括學號、姓名、年齡、所在院校、學院地址、學院電話等
會出現一個學生同時在多個學院同時上課,正常應該是:一個學院包含多個學生,一個學生屬於一個學院C

CREATE TABLE collage(
cid NUMBER(40)PRIMARY KEY,
cnameVARCHAR2(50),
caddressVARCHAR2(20),
ctelVARCHAR2(20)
);

CREATE TABLE student(
stunoVARCHAR2(50) PRIMARY KEY,
stunameVARCHAR2(50),
stuage NUMBER,
cid NUMBER(4),
建立主-外鍵關聯
);
以上是很明確的1對多的關系

其它補充:
Oracle數據庫的創建有兩種方式:
一種是使用CREATE DATABASE命令;
一種是使用DBCA (Database Configuration Assistant),它是基於圖形界面創建的,比較簡單方便。而且,使用DBCA可以詳細地對將要創建的數據庫進行詳細的配置。
數據庫啟動和關閉的幾種方式
數據庫的啟動(STARTUP)
啟動一個數據庫需要三個步驟:
1、 創建一個Oracle實例(非安裝階段)
2、 由實例安裝數據庫(安裝階段)
3、 打開數據庫(打開階段)
在Startup命令中,能夠通過不同的選項來控制數據庫的不同啟動步驟。
1、STARTUPNOMOUNT
NONOUNT選項僅僅創建一個Oracle實例。
2、STARTUPMOUNT
該命令創建實例並且安裝數據庫,但沒有打開數據庫。

3、STARTUP
該命令完成創建實例、安裝實例和打開數據庫的任何三個步驟。
假如采用STARTUP NOMOUNT或是STARTUP MOUNT的數據庫打開命令方式,必須采用ALTER DATABASE命令來執行打開數據庫的操作。例如,假如您以STARTUP NOMOUNT方式打開數據庫,也就是說實例已創建,但是數據庫沒有安裝和打開。這是必須運行下面的兩條命令,數據庫才能正確啟動。
ALTER DATABASE MOUNT;
ALTER DATABASE OPEN;
而假如以STARTUP MOUNT方式啟動數據庫,只需要運行下面一條命令即能夠打開數據庫:
ALTER DATABASE OPEN.
數據庫的關閉(SHUTDOWN)
1、SHUTDOWNNORMAL
這是數據庫關閉SHUTDOWN命令的確省選項。
2、SHUTDOWNIMMEDIATE
這是我們常用的一種關閉數據庫的方式,想很快地關閉數據庫
3、SHUTDOWNTRANSACTIONAL
該選項僅在Oracle 8i后才能夠使用。該命令常用來計划關閉數據庫
4、SHUTDOWNABORT
數據庫處於一種非正常工作狀態,需要立即關閉數據庫;在啟動數據庫實例時碰到問題


Oracle數據庫體系結構
Oracle服務器由 Oracle 實例和 Oracle 數據庫組成,如圖所示:
簡易表示為下圖所示:

每一個Oracle 數據庫都關聯着一個 Oracle 實例。在數據庫服務器上啟動數據庫后,Oracle 軟件會分配一個稱為系統全局區(SGA) 的共享內存區,還會啟動若干個 Oracle 后台進程。這種 SGA 和Oracle 進程的組合就稱為一個 Oracle 實例。
實例啟動后,Oracle 軟件會將實例與特定的數據庫關聯起來。這個過程稱為裝載數據庫。接下來就可以打開數據庫了。在同一台Oracle服務器上可以並發執行多個實例,每一個實 例只訪問自己的物理數據庫。Oracle 數據庫使用內存結構和進程來管理、訪問數據庫。所有內存結構都存在於構成數據庫服務器的計算機的主存中。

卸載Oracle

 在卸載Oracle時刪不干凈,搞的要重裝系統,總結出如下方法。

  1.以Administrators group身份登陸windows系統。

  2.通過Oracle installer 卸載所有orcle產品及組件。

  3.停掉Oracle Service服務。

  4.刪除%ORACLE_base%文件和SYSTEM_DRIVE:programfiles下的oracle文件。

  5.刪除SYSTEM_DRIVE:Documents and SettingsAll Users「開始」菜單程序中的oracle項。

  6.打開注冊表:

  到HKEY_CLASSES_ROOT下,刪除以Oracle,ORA,ORCL開頭的鍵;

  到HKEY_LOCAL_MACHINESOFTWARE下,刪除ORACLE鍵和Apache Group鍵;

  到HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices下,刪除以Oracle開頭的鍵;

  到HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesEventlogApplication下,刪除以Oracle開頭的鍵;

  到HKEY_CURRENT_USER下,刪除Oracle鍵;

  到HKEY_CURRENT_USERSOFTWAREORACLE下,刪除以Oracle 或 Orcl開頭的鍵(如果有的話);關閉注冊表,重啟計算機。

  7.打開系統系統環境變量(我的電腦->右鍵->系統屬性->高級->環境變量),在PATH中刪除所有以%ORACLE_HOME%開始的項。

  8.重啟計算機。

Oracle listener錯誤解決方法

Oracle listener錯誤,可以把安裝目錄下的listener.ora打開察看。如: ..\db1\network\admin\listener.ora。
打開該配置文件后發現如下一段配置信息:
LISTENER =
(DESCRipTION_LIST=
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
)
(ADDRESS_LIST =
(ADDRESS =(PROTOCOL = TCP)(HOST = IBMThinkPad)(PORT = 1521))
)
)
)

當看到這一行HOST=IBMThinkPad的時候,問題解決了。原來是由於幾天裝好Oracle后,又改了Windows的計算機名,而這個 配置文件中記錄的監聽主機名還是原來的名稱,這也就怪不得 TNSListener服務無法啟動了,馬上修改為現在的計算 機名,再次啟動OracleTNSListener服務成功,PL/SQL Developer連接Oracle數據庫成功,不能登陸故障排除。

 

存筆記

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM