oracle面試


部分常見ORACLE面試題以及SQL注意事項

一、表的創建:
一個通過單列外鍵聯繫起父表和子表的簡單例子如下:
CREATE TABLE parent(id INT NOT NULL,
PRIMARY KEY (id)
)
CREATE TABLE child(id INT, parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id) REFERENCES parent(id)
ON DELETE CASCADE
)
建表時注意不要用關鍵字當表名或字段名,如insert,use等。
CREATE TABLE parent(id INT NOT NULL,
PRIMARY KEY (id)
) TYPE=INNODB;
InnoDB Tables 概述
InnoDB給MySQL提供了具有事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。
InnoDB 提供了行鎖(locking on row level),提供與 Oracle 類型一致的不加鎖讀取(non-locking read in SELECTs)。這些特性均提高了多用戶併發操作的性能表現。在InnoDB表中不需要擴大鎖定(lock escalation),
因爲 InnoDB 的列鎖定(row level locks)適宜非常小的空間。
InnoDB 是 MySQL 上第一個提供外鍵約束(FOREIGN KEY constraints)的表引擎。
InnoDB 的設計目標是處理大容量數據庫系統,它的CPU利用率是其它基於磁盤的關係數據庫引擎所不能比的。

從一個表中查詢出數據插入到另一個表中的方法:
select * into destTbl from srcTbl ;

insert into destTbl(fld1, fld2) select fld1, 5 from srcTbl ;

以上兩句都是將 srcTbl 的數據插入到 destTbl,但兩句又有區別的。

第一句(select into from)要求目標表(destTbl)不存在,因爲在插入時會自動創建。

第二句(insert into select from)要求目標表(destTbl)存在,由於目標表已經存在,所以我們除了插入源表(srcTbl)的字段外,還可以插入常量,如例中的:5。

如果只想要結構而不要數據。
create table s_emp_42 as select * from s_emp where 1=2;//永假式

SQL查詢練習題
1.
表1:book表,字段有id(主鍵),name (書名);
表2:bookEnrol表(圖書借出歸還登記),字段有id,bookId(外鍵),dependDate(變更時間),state(1.借出 2.歸還)。
id name
1 English
2 Math
3 JAVA

id bookId dependDate state
1 1 2009-01-02 1
2 1 2009-01-12 2
3 2 2009-01-14 1
4 1 2009-01-17 1
5 2 2009-02-14 2
6 2 2009-02-15 1
7 3 2009-02-18 1
8 3 2009-02-19 2

要求查詢結果應爲:(被借出的書和被借出的日期)

Id Name dependDate
1 English 2009-01-17
2 Math 2009-02-15

Select e.bookId,b.name,e.dependDate from book b,bookEnrol e where

第二個表是用來登記的,不管你是借還是還,都要添加一條記錄。
請寫一個SQL語句,獲取到現在狀態爲已借出的所有圖書的相關信息。

參考語句:
select book.id,book.name,max(dependDate)
from book inner join bookEnrol on book.id=bookEnrol.bookid AND booker.state=1
group by book.id ;

2
第(1)題練習使用group by /having 子句。類似的筆試題還有:
表一:各種產品年銷售量統計表 sale
年 產品 銷量
2005 a 700
2005 b 550
2005 c 600
2006 a 340
2006 b 500
2007 a 220
2007 b 350

要求得到的結果應爲:
年 產品 銷量
2005 a 700
2006 b 500
2007 b 350
即:每年銷量最多的產品的相關信息。
參考答案:
Select * from sale a where not exists(select * from sale where 年=a.年 and 銷量>a.銷量);
--or:
select * from sale a inner join (select 年,max(銷量) as 銷量from sale group by 年) b
on a.年=b.年 and a.銷量=b.銷量
3.查詢語句排名問題:
名次 姓名 月積分(char) 總積分(char)
1 WhatIsJava 1 99
2 水王 76 981
3 新浪網 65 96
4 牛人 22 9
5 中國隊 64 89
6 北林信息 66 66
7 加太陽 53 66
8 中成藥 11 33
9 西洋參 25 26
10 大拿 33 23

如果用總積分做降序排序..因爲總積分是字符型,所以排出來是這樣子(9,8,7,6,5...),要求按照總積分的數字大小排序。
select * from tablename order by cast(總積分 as int) desc

表tb
uid mark
1 7
1 6
2 3
2 2
2 5
3 4
3 3
4 8
4 1
4 3
想查出uid=4的名次:
uid mc
4 3

select uid, sum(mark) as total from tab_name group by uid order by total desc;
4
表A字段如下
month name income
月份 人員 收入
1 a 1000
2 a 2000
3 a 3000
要求用一個SQL語句(注意是一個)的處所有人(不區分人員)每個月及上月和下月的總收入
要求列表輸出爲
月份 當月收入 上月收入 下月收入
2 2000 1000 3000

Select (Select Month From Table Where Month = To_Char(Sysdate, 'mm')) 月份,
(Select Sum(Income) From Table Where Month = To_Char(Sysdate, 'mm')) 當月收入,
(Select Sum(Income) From Table Where To_Number(Month) = To_Number(Extract(Month From Sysdate)) - 1) 上月收入,
(Select Sum(Income) From Table Where To_Number(Month) = To_Number(Extract(Month From Sysdate)) + 1) 下月收入
From Dual


5.刪除重複記錄

方法原理:
1、Oracle中,每一條記錄都有一個rowid,rowid在整個數據庫中是唯一的,
  rowid確定了每條記錄是在ORACLE中的哪一個數據文件、塊、行上。

2、在重複的記錄中,可能所有列的內容都相同,但rowid不會相同,所以只要確定出重複記錄中
  那些具有最大rowid的就可以了,其餘全部刪除。

實現方法:
SQL> create table a (
2 bm char(4), --編碼
3 mc varchar2(20) --名稱
4 )
5 /

SQL> select rowid,bm,mc from a;

ROWID BM MC
------------------ ---- -------
000000D5.0000.0002 1111 1111
000000D5.0001.0002 1112 1111
000000D5.0002.0002 1113 1111
000000D5.0003.0002 1114 1111
000000D5.0004.0002 1111 1111
000000D5.0005.0002 1112 1111
000000D5.0006.0002 1113 1111
000000D5.0007.0002 1114 1111

查詢到8記錄.


查出重複記錄
SQL> select rowid,bm,mc from a where a.rowid!=(select max(rowid) from a b where a.bm=b.bm and a.mc=b.mc);

ROWID BM MC
------------------ ---- --------------------
000000D5.0000.0002 1111 1111
000000D5.0001.0002 1112 1111
000000D5.0002.0002 1113 1111
000000D5.0003.0002 1114 1111

刪除重複記錄
SQL> delete from a a where a.rowid!=(select max(rowid) from a b where a.bm=b.bm and a.mc=b.mc);

刪除4個記錄.

SQL> select rowid,bm,mc from a;

ROWID BM MC
------------------ ---- --------------------
000000D5.0004.0002 1111 1111
000000D5.0005.0002 1112 1111
000000D5.0006.0002 1113 1111
000000D5.0007.0002 1114 1111
其他組合函數
Group by 子句
Distinct 關鍵字
僞列ROWNUM,用於爲子查詢返回的每個行分配序列值

注意:組函數可以處理一組數據,返回一個值。組函數會忽略空值。where 後只能跟單行函數,不能有組函數。

使用TOP-N分析法
TOP-N分析法基於條件顯示錶中最上面N條記錄或最下面N條記錄
TOP-N查詢包含以下內容:
1,一個用於排序數據的內聯視圖
2,使用ORDER BY子句或DESC參數的子查詢
3,一個外層查詢。由它決定最終記錄中行的數目。這包括ROWNUM僞列和用於比較運算符的WHERE子句
//語法:
SELECT ROWNUM,column_list
FROM (SELECT column_list FROM table_name ORDER BY Top-n-column_name)
WHERE ROWNUM <= N
例1:查詢Employee表的頂部10條記錄
//方法1:單表時可以用
select cEmployeeCode,vFirstName,vLastName from employee where rownum <= 10
//方法2:較複雜的查詢,建議使用這種
select * from (select rownum as num,cEmployeeCode,vFirstName,vLastName from employee)
where num <= 10
例2: 查詢Employee表的 第1 到 第10條 記錄,可以用於分頁顯示
//注意:因爲這裏子查詢的rownum需要被外層查詢所使用,因此要使用別名,否則將被認爲是兩個不同的rownum
select * from (select rownum as num,Employee.* from Employee) where num between 10 and 20
select * from (select rownum as num,Employee.* from Employee) where num between 1 and 10

SQL注入 1=1永遠成立,相當於查詢所有記錄
select * from person_zdk where 1=1 or name like '%a%' and age=13;

 


DECODE函數
是ORACLE PL/SQL是功能強大的函數之一,目前還只有ORACLE公司的SQL提供了此函數,其他數據庫廠商的SQL實現還沒有此功能。

decode(條件,值1,翻譯值1,值2,翻譯值2,...值n,翻譯值n,缺省值)

該函數的含義如下:

IF 條件=值1 THEN

RETURN(翻譯值1)

ELSIF 條件=值2 THEN

RETURN(翻譯值2)

......

ELSIF 條件=值n THEN

RETURN(翻譯值n)

ELSE

RETURN(缺省值)

END IF


假設我們想給智星職員加工資,其標準是:工資在8000元以下的將加20%;工資在8000元以上的加15%,用DECODE函數,那麼我們就可以把這些流控制語句省略,通過SQL語句就可以直接完成。如下:select decode(sign(salary - 8000),1,salary*1.15,-1,salary*1.2,salary from employee.

 

SQL中的單記錄函數
1.CONCAT
連接兩個字符串;
SQL> select concat('010-','88888888')||'轉23' 高乾競電話 from dual;

高乾競電話
----------------
010-88888888轉23
2.LTRIM和RTRIM
LTRIM 刪除左邊出現的字符串
RTRIM 刪除右邊出現的字符串
SQL> select ltrim(rtrim(' gao qian jing ',' '),' ') from dual;

LTRIM(RTRIM('
-------------
gao qian jing
3..SUBSTR(string,start,count)
取子字符串,從start開始,取count個
SQL> select substr('13088888888',3,8) from dual;

SUBSTR('
--------
08888888

4日期函數
如:LAST_DAY 返回本月日期的最後一天
具體參見oracle筆記.
其他主要函數:.TRUNC 按照指定的精度截取一個數;SQRT 返回數字n的根;POWER(n1,n2)返回n1的n2次方根;MOD(n1,n2) 返回一個n1除以n2的餘數;FLOOR 對給定的數字取整數;REPLACE('string','s1','s2') string 希望被替換的字符或變量 s1 被替換的字符串 s2 要替換的字符串;LOWER 返回字符串,並將所有的字符小寫;UPPER返回字符串,並將所有的字符大寫;LENGTH
返回字符串的長度。

ORALCE常識 及 SQL 基本語法
1,ORACLE安裝完成後的初始口令?
internal/oracle
sys/change_on_install
system/manager
scott/tiger scott是Oracle的核心開發人員之一,tiger是他家的一隻貓的名字
sysman/oem_temp
例:conn scott/tiger@jspdev;
conn system/manager@jspdev as sysdba;
2,IBM的Codd (Edgar Frank Codd)博士提出《大型共享數據庫數據的關係模型》
3,ORACLE 9i 中的 i (internet)是因特網的意思
4,ORACLE的數據庫的物理結構:數據文件、日誌文件、控制文件
5,ORACLE的數據庫的邏輯結構:表空間--表--段--區間--塊
表空間 類似於SQLSERVER中數據庫的概念
6,SYSDATE 返回當前系統日期(說明:當函數沒有參數時可以省略括號)
7,在SQL PLUS中 執行緩衝區中的SQL命令的方式:
SQL> run
SQL> r
SQL> /
8,在SQL PLUS中 修改當前會話的日期顯示格式
SQL> alter session set nls_date_format = 'YYYY-MM-DD'
9,使用臨時變量,提高輸入效率
SQL> insert into emp(empno,ename,sal) values(&employeeno,'&employeename',&employeesal);
10,從其他表中複製數據並寫入表
SQL> insert into managers(id,name,salary,hiredate)
SQL> select empno,ename,sal,hiredate
SQL> from emp
SQL> where job = 'MANAGER';
11,修改表中的記錄
SQL> update table set column = value [,column = value,......] [where condition];
12,刪除表中的記錄
SQL> delete [from] table [where condition];

13,數據庫事務,事務是數據庫一組邏輯操作的集合
一個事務可能是:
多個DML語句
單個DDL語句
單個DCL語句
14,事務控制使用 savepoint,rollback,commit 關鍵字
SQL> savepoint aaa;
SQL> rollback to aaa;
SQL> commit;
15,查詢表中的數據
select * from table_name;
select column_list from table_name;
16,Number and Date 可以用於算術運算
因爲 Date 類型 其實存儲爲 Number 類型
17,用運算表達式產生新列
SQL> select ename,sal,sal+3000 from emp;
SQL> select ename,sal,12*sal+100 from emp;
18,算術表達式中NULL值錯誤的處理
因爲任何數與NULL運算無意義,所以爲避免錯誤,需要用其他值替換NULL值
例如:
SQL> select ename "姓名",12*sal+comm "年薪" from emp where ename = 'KING';
姓名 薪水
---------- ----------
KING
因爲comm(提成工資)列爲NULL值,結果也出現了NULL值,所以需要用0來替換NULL
注意函數nvl的使用 NVL(原值,新值)
SQL> select ename "姓名",12*sal+NVL(comm,0) "年薪" from emp where ename = 'KING';
員工姓名 員工薪水
---------- ----------
KING 60000
--------------
19,使用友好的列名,有下面三種形式
SQL> select ename as 姓名, sal 月薪, sal*12 "年薪" from emp
20,過濾重複行,使用關鍵字 distinct
SQL> select distinct * from emp;

21,SQL PLUS訪問ORACLE數據庫的原理
SQL*Plus -> Buffer -> Server -> Query Result
22,where 子句中 字符型 是區分大小寫的,最好都轉成大寫
因爲在ORACLE庫中,字符會轉換成大寫來保存
23,比較運算符:等於"=",不等於有兩種"<>"或者"!="
24,複雜的比較運算符:
between ...... and ......
in (......value list......)
like (% 代表匹配至多個任意字符,_ 代表單個任意字符)
null (與NULL進行比較時,需要使用 is null 或者 is not null)
25,邏輯運算符,按優先級從高到低排列
Not , And , Or
26,Order by 子句 中 ( asc 表示 升序,desc 表示降序)
27,ORACLE 函數,分爲
單行函數:每條記錄返回一個結果值
多行函數:多條記錄返回一個結果值
28,字符函數--轉換函數
LOWER:轉爲小寫
UPPER:轉爲大寫
INITCAP:將每個單詞的首字母大寫,其他字母小寫
29,字符函數--操縱函數(注意:ORACLE以UNICODE存儲字符)
CONCAT:連接兩個字符串,與並置運算符"||"類似
SUBSTR:substr(string,position,length) 從string中的position開始取length個字符
LENGTH:返回字符串的長度
INSTR: instr(string,value) 返回 value 在 string 的起始位置
LPAD: lpad(string,number,value) 若string不夠number位,從左起用vlaue字符串填充(不支持中文)
30,四捨五入函數 round(數值,小數位)
SQL> SELECT ROUND(45.923,2),ROUND(45.923,0),ROUND(45.923,-1) FROM DUAL;
ROUND(45.923,2) ROUND(45.923,0) ROUND(45.923,-1)
--------------- --------------- ----------------
45.92 46 50

31,數值截取函數 trunct
SQL> SELECT TRUNC(45.923,2),TRUNC(45.923,0),TRUNC(45.923,-1) FROM DUAL;
TRUNC(45.923,2) TRUNC(45.923,0) TRUNC(45.923,-1)
--------------- --------------- ----------------
45.92 45 40
32,求模函數 MOD(a,b) 返回a被b整除後的餘數
33,Oracle內部默認的日期格式: DD-MON-YY (24-9月 -06)
34,DUAL :啞元系統表,是名義表,只能範圍唯一值
35,Date類型的算術運算,以天爲單位
例如:部門編號爲10的員工分別工作了多少年
SQL> select ename,(sysdate-hiredate)/365 as years from emp where deptno = 10;
ENAME YEARS
---------- ----------
CLARK 25.3108341
KING 24.8697382
MILLER 24.6861766
36,日期函數
MONTHS_BETWEEN 返回兩個日期之間相差多少個月
ADD_MONTHS 在日期上加上月份數
NEXT_DAY 下一個日子 select next_day(sysdate,'星期一') from dual;
LAST_DAY 該月的最後一天
ROUND 四捨五入日期 round(sysdate,'year') 或者 round(sysdate,'month')
TRUNC 截取日期 trunc(sysdate,'year') 或者 trunc(sysdate,'month')
37,數據類型轉換 -- Oracle 可隱式轉換的情況有:
From To
varchar2 or char -- number (當字符串是數字字符時)
varchar2 or char -- date
number -- varchar2
date -- varchar2
38,數據類型轉換 -- Oracle 數據類型轉換函數
to_char
to_number
to_date

39,日期格式模型字符
YYYY 代表完整的年份
YEAR 年份
MM 兩位數的月份
MONTH 月份的完整名稱
DY 每星期中天的三個字符縮寫
DAY 表示星期日--星期六
另外還有 D,DD,DDD 等。。。
40,NVL(value,substitute)
value:是可能有null的列,substitute是缺省值
這個函數的作用就是當出現null值的時候,後缺省值替換null
41,Coalesce(exp_name1,exp_name2......exp_n)
42,Decode 函數: Decode(exp,testvalue1,resultvalue1,testvalue2,resultvalue2)
例如,根據國家名稱顯示相應的國家代碼:
1>創建國家表
create table countrys
(
vCountryName varchar2(50)
);
2>寫入幾行,分別爲中國、日本、韓國
insert into countrys values ('&name');
3>用DECODE函數,進行匹配和顯示
select vCountryName as "國家名稱",
DECODE(vCountryName,'中國','086','日本','116') as "國家編號" from countrys;
國家名稱 國家編號
-------------------------------------------------- ---
中國 086
日本 116
韓國

結果,在DECODE中存在且成功匹配的值將會被顯示,否則顯示爲NULL

SQL語句書可以提高執行效率的方法
1、操作符號: NOT IN操作符
此操作是強列推薦不使用的,因爲它不能應用表的索引。推薦方案:用NOT EXISTS 或(外連接+判斷爲空)方案代替 "IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", "LIKE '%500'",因爲他們不走索引全是表掃描。NOT IN會多次掃描表,使用EXISTS、NOT EXISTS、IN、LEFT OUTER JOIN來替代,特別是左連接,而Exists比IN更快,最慢的是NOT操作。


2、注意union和union all的區別。union比union all多做了一步distinct操作。能用union all的情況下儘量不用union。
如: 兩個表A和B都有一個序號字段ID,要求兩個表中的ID字段最大的值:
select max(id) as max_id
from(
select id from 表A
union all
select id from 表B ) t


3、查詢時儘量不要返回不需要的行、列。另外在多表連接查詢時,儘量改成連接查詢,少用子查詢。

4、儘量少用視圖,它的效率低。對視圖操作比直接對錶操作慢,可以用存儲過程來代替它。特別的是不要用視圖嵌套,嵌套視圖增加了尋找原始資料的難度。
我們看視圖的本質:它是存放在服務器上的被優化好了的已經產生了查詢規劃的SQL。對單個表檢索數據時,不要使用指向多個表的視圖,
直接從表檢索或者僅僅包含這個表的視圖上讀,否則增加了不必要的開銷,查詢受到干擾.爲了加快視圖的查詢,MsSQL增加了視圖索引的功能。

5、創建合理的索引,對於插入或者修改比較頻繁的表,儘量慎用索引。因爲如果表中存在索引,插入和修改時也會引起全表掃描。
索引一般使用於where後經常用作條件的字段上。

6、在表中定義字段或者存儲過程、函數中定義參數時,將參數的大小設置爲合適即可,勿設置太大。這樣開銷很大。

7、Between在某些時候比IN速度更快,Between能夠更快地根據索引找到範圍。用查詢優化器可見到差別。
select * from chineseresume where title in ('男','女')
Select * from chineseresume where between '男' and '女'是一樣的。由於in會在比較多次,所以有時會慢些。

8、在必要是對全局或者局部臨時表創建索引,有時能夠提高速度,但不是一定會這樣,因爲索引也耗費大量的資源。他的創建同是實際表一樣。

9、WHERE後面的條件順序影響
WHERE子句後面的條件順序對大數據量表的查詢會產生直接的影響,如
Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'
以上兩個SQL中dy_dj(電壓等級)及xh_bz(銷戶標誌)兩個字段都沒進行索引,所以執行的時候都是全表掃描,如果dy_dj = '1KV以下'條件在記錄集內比率爲99%,而xh_bz=1的比率只爲0.5%,在進行第一條SQL的時候99%條記錄都進行dy_dj及xh_bz的 比較,而在進行第二條SQL的時候0.5%條記錄都進行dy_dj及xh_bz的比較,以此可以得出第二條SQL的CPU佔用率明顯比第一條低。所以儘量 將範圍小的條件放在前面。。

10、用OR的字句可以分解成多個查詢,並且通過UNION 連接多個查詢。他們的速度只同是否使用索引有關,如果查詢需要用到聯合索引,用 UNION all執行的效率更高.多個OR的字句沒有用到索引,改寫成UNION的形式再試圖與索引匹配。一個關鍵的問題是否用到索引。

11、沒有必要時不要用DISTINCT和ORDER BY,這些動作可以改在客戶端執行。它們增加了額外的開銷。這同UNION和UNION ALL一樣的道理。

12、使用in時,在IN後面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最後面,這樣可以減少判斷的次數

13、當用SELECT INTO時,它會鎖住系統表(sysobjects,sysindexes等等),阻塞其他的連接的存取。創建臨時表時用顯示聲明語句,在另一個連接中 SELECT * from sysobjects可以看到 SELECT INTO 會鎖住系統表, Create table 也會鎖系統表(不管是臨時表還是系統表)。所以千萬不要在事物內使用它!!!這樣的話如果是經常要用的臨時表請使用實表,或者臨時表變量。

14、一般在GROUP BY和HAVING字句之前就能剔除多餘的行,所以儘量不要用它們來做剔除行的工作。他們的執行順序應該如下最優:select 的Where字句選擇所有合適的行,Group By用來分組個統計行,Having字句用來剔除多餘的分組。這樣Group By和Having的開銷小,查詢快.對於大的數據行進行分組和Having十分消耗資源。如果Group BY的目的不包括計算,只是分組,那麼用Distinct更快

15、一次更新多條記錄比分多次更新每次一條快,就是說批處理好

16、慎用臨時表,臨時表存儲於tempdb庫中,操作臨時表時,會引起跨庫操作。儘量用結果集和表變量來代替它。

17、儘量將數據的處理工作放在服務器上,減少網絡的開銷,如使用存儲過程。存儲過程是編譯好、優化過,並且被組織到一個執行規劃裏、且存儲在數據庫中的 SQL語句,是控制流語言的集合,速度當然快。

18、不要在一段SQL或者存儲過程中多次使用相同的函數或相同的查詢語句,這樣比較浪費資源,建議將結果放在變量裏再調用。這樣更快。

19、按照一定的次序來訪問你的表。如果你先鎖住表A,再鎖住表B,那麼在所有的存儲過程中都要按照這個順序來鎖定它們。如果你(不經意的)某個存儲過程中先鎖定表B,再鎖定表A,這可能就會導致一個死鎖。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章