oracle學習筆記(基礎版)
一、 Oracle支援表示式 包括:+ - * /
dual(虛表,用於簡單的輸出實驗用)
1.SELECT 5+3,5-3,5*3,5/2 FROM dual;
2.SELECT 'hello,world',100 FROM dual;
3.查員工編號,姓名,工資,新工資(=原始工資上浮25%) (列值可以直接加減運算,產生的是臨時結果)
SELECT employee_id,last_name,salary,salary*1.25
FROM employees;
4.查員工編號,姓名,工資,12月總工資(=原始工資+100)*12
SELECT employee_id,last_name,salary,(salary+100)*12
FROM employees;
Oracle資料庫中,空值是無效的,未指定的,未知的或不可預知的值
空值不是空格或者0
在Oracle中,null和空字串是等價的
包含空值的數學表示式的值都為空值
5.SELECT 5+NULL FROM dual;查詢結果為空
6.列的別名(用於衍生列) 有兩種方式 一種是 AS; 一種是加空格
如果別名要是非法識別符號,可以使用雙引號
7.拼接字串 ( || )
SELECT 'hello' || 'world' FROM dual; helloworld
SELECT 'hello' || 123 FROM dual; hello123
SELECT 123 || 123 FROM dual; 123123
SELECT '200' + '100' FROM dual; 300
SELECT first_name || '·' || last_name as ename
FROM employees; 查詢得到1列 格式為 姓·名;
8.多個重複行併成一行
SELECT DISTINCT department_id FROM employees;
9.通過dual生成訂單編號(getorderno('') 引號中為訂單型別 可以為空 但必須加引號)
select getorderno('apple') from dual
二、Oracle常用資料型別
1.字元型:varchar2(n):變長字串,n代表允許的最大位元組長度,最大4000位元組
char(n):同上,定長字串,最大2000位元組,長度不夠會填充半形空格,
查詢效率高 用於(手機號、身份證號等確定長度的)
clob:大字串資料,最大4G,預設資料在4000位元組內,儲存在表段空間中,超過4000位元組會用LOB段儲存,查詢效率低
2.數字型別:number:儲存整型或浮點型,最大38位精度
number(n):僅存整數,n代表最大位數 number(4) 取值範圍: -9999~9999
number(p,s):存浮點型別,P代表最大精度(小數位精度和整數精度和的精度),s代表小數位
3.日期:date:儲存年月日時分秒,精確到秒
timestamp(n) 時間戳,精確到納秒 很少用
4.blob :大二進位制資料,最大4G 可以存圖片、視訊、音樂等等
三,Oracle過濾語句 where
1.加了where,資料查詢出來就做了比較,所以比不帶where的效率要低
2.查詢工資超過10000的員工
SELECT * FROM employees WHERE salary >= 90
3.操作符
=
>
>=
<
<=
<> 不等於 (其實!=也可以用)如果值為空值也查不出來
4. 如果需要查詢無條件為真 可以用
SELECT * FROM employees WHERE 1==1;
無條件為假
SELECT * FROM employees WHERE 1==0;
5.查詢員工編號,姓名,工資,新工資(只看新工資超過10000的員工)
SELECT employee_id,last_name,salary,salary*1.25 AS new_sal
WHERE salary*1.25 >=10000;
值得注意的是WHERE後面不能用別名
6.日期型別比較,日期格式敏感,預設的日期格式是DD-MON-RR,沒有常量。
查詢所有在90年以前入職的員工
SELECT * FROM employees WHERE hire_date < '1-1月-90';
有中文,在其他平臺會出問題
7.特殊比較運算子
BETWEEN...AND... 在兩個值之間 包含邊界 可以是日期型別(查不出來空值)
IN(set) 等於值列表中的一個(查不出來空值)
LIKE 模糊查詢
IS NULL 空值
查詢所有有部門的員工
SELECT last_name , manager_id FROM employees WHERE dapartment_id IS NOT NULL;
查詢工資在5000-10000之間的員工
SELECT * FROM employees WHERE salary BETWEEN 5000 AND 10000 ;(有邊界)
查詢工資不在5000-10000之間的員工
SELECT * FROM employees WHERE salary NOT BETWEEN 5000 AND 10000 ;(沒有邊界)
查詢部門不是10,20,50號員工
SELECT * FROM employees WHERE department_id NOT IN (10,20,50);
注意,如果IN後面的值有個為NULL,那麼所有資料都查不出來。
四、在oracle中模糊查詢的關鍵字是like
1.其中‘%’代表含有0到多個 ‘_’代表佔一個位
如果查詢中要查詢倒數第5個是下劃線的可以使用ESCAPE關鍵字
其中'\'是自定義的,可以是任何符號
SELECT * FROM employee WHERE job_id LIKE '%\_____' ESCAPE '\';
其中後四個'_'佔四個位置,倒數第五個'_'代表它本來的意思'_';
2.查詢工資超過5000且last_name以s結尾的員工
SELECT *
FROM employees
WHERE salary>=5000
AND last_name LIKE '%s';
3.查詢部門是10,20,以及沒有部門的員工
SELECT *
FROM employees
WHERE department IN (10,20)
OR department IS NULL;
4.單引號轉義 如果查詢帶單引號的字串時 , 要多加一個單引號對其單引號進行轉義
例如查詢 HELLO'WORLD :
SELECT 'HELLO''WORLD' FROM dual;
資料庫中單引號要做處理 ,防止別人SQL注入
5.查詢員工編號,姓名,工資,新工資,部門編號,按工資升序排列
SELECT employee_id,last_name,salary,salary*1.25 new_sal
FROM employees
ORDER BY salary;
6.查詢員工編號,姓名,工資,新工資,部門編號,按工資降序排列
SELECT employee_id,last_name,salary,salary*1.25 new_sal
FROM employees
ORDER BY salary DESC;
7.排序可以是別名
SELECT employee_id,last_name,salary,salary*1.25 new_sal
FROM employees
ORDER BY new_sal DESC;
8.排序可以是表示式
SELECT employee_id,last_name,salary,salary*1.25 new_sal
FROM employees
ORDER BY salary*1.25 DESC;
9.排序可以是列索引,2代表第二列 也就是說按 last_name這一列排序
SELECT employee_id,last_name,salary,salary*1.25 new_sal
FROM employees
ORDER BY 2 DESC;
10.查詢員工編號,姓名,工資,入職日期,部門編號(多排序表示式)
按部門升序,工資降序,入職日期升序
SELECT employee_id,last_name,salary,hire_date,department_id
FROM employees
ORDER BY department_id,salary DESC,hire_date;
11.排序表示式可以不是列列表中的列
SELECT employee_id,last_name,salary,hire_date,department_id
FROM employees
ORDER BY job_id;
12.查詢50號部門的員工,按工資降序
子句是有順序的,先過濾,後排序
SELECT *
FROM employees
WHERE department_id = 50
ORDER BY salary DESC;
13.大資料排序的問題(非常耗費資源,容易造成伺服器宕機)
排序就是兩兩比較,排序預設產生的臨時資料放到排序區的記憶體中,
如果排序區不夠用,就會利用臨時表空間(排序區預設128K很小)
大排序之前一定要做資料庫優化 (怎麼優化目前不太清楚。。繼續學習中!)
rownum和rowid是三大偽列中的其中兩個,是最容易搞混的兩個
偽列和虛表差不多,看不到,卻可以使用
五、rownum偽列
1.SELECT rownum,employee_id,last_name,salary
FROM employees
WHERE department_id = 50;
查詢結果是多了一列名為ROWNUM的列,這一列資料從1開始一直遞增。
2.查詢某表中的前5條資料(有其他欄位的時候查詢所有列要在前面加表名.*)
SELECT rownum,employees.*
FROM employees
WHERE rownum<=5;
3.
rownum在以下條件一定為假,查不出來資料
rownum>n
rownum>=n
rownum=1以外的值
4.rowid偽列
表資料行的實體地址
在插入資料時生成
在資料庫彙總是唯一的
SELECT ROWID,employees.*
FROM employees
六、函式(和帶返回值的方法一樣)分為兩類
單行函式 和 多行函式
1.單行函式 upper() 將小寫變成大寫 傳入一行
用於 字元 通用 轉換 日期 數值
SELECT last_name,upper(last_name)
FROM employees;
2.多行函式 傳入多行 得到一個結果
SELECT count(last_name)
FROM enployees;
3.單行函式-字元函式
lower,upper:轉換大小寫
SELECT lower(last_name),upper(last_name)
FROM employees;
4.initcap:單詞首字母大寫,其餘小寫
SELECT initcap('This IS a book')
FROM dual ;
查詢結果 This Is A Book
5. concat(字串1,字串2):拼接字串
SELECT concat('hello','world')
FROM dual;
查詢結果 helloworld
6.substr(字串,起始位置,擷取個數) :擷取一個字元的子串,起始位置可以是負數(右數第N位)
SELECT substr('abcdefg',3) FROM dual; 結果:cdefg
SELECT substr('abcdefg',3,2) FROM dual; 結果:cd
SELECT substr('abcdefg',-3) FROM dual; 結果:efg
SELECT substr('abcdefg',-3,2) FROM dual; 結果:ef
7.length:返回字串長度
SELECT length('abcd') FROM dual; 結果:4
SELECT length('') FROM dual; 結果:null(不返回0)
8.instr(字串,查詢子串[,起始位置[,第幾次出現]]);
查詢字串中子串的起始位置,如果找不到返回0
起始位置可以為負數(從右向左反向搜尋)
SELECT inset('abcdefg','cd') FROM dual; 結果:3
SELECT inset('abcdefg','cdf') FROM dual; 結果:0
SELECT inset('abcdefgcdefg','cd') FROM dual; 結果:3
SELECT inset('abcdefgcdefg','cd',4) FROM dual; 結果:8
SELECT inset('abcdefgcdefg','cd',-1) FROM dual; 結果:8
SELECT inset('abcdefgcdefg','cd',1,2) FROM dual; 結果:8
9.lpad(字串,固定長度,填充字元):左填充
rpad:同上,右填充
SELECT lpad('abcd',7,'#') FROM dual; 結果:###abcd
SELECT lpad('abcd',3,'#') FROM dual;結果:abc
SELECT rpad('abcd',7,'#') FROM dual;結果:abcd###
SELECT lpad('',7.'*') FROM dual; 結果:null 給空字串填充結果還是null
SELECT lpad(' ',7 ,'*') FROM dual; 結果: ******空格佔一個位
SELECT lpad('abcd',0,9,'*') FROM dual;結果:null 0.9算0 ,1.9算1
10.trim(關鍵字 from 字串): 修建字串兩邊的關鍵字
SELECT trim('a' FROM 'aabcdaaxyza') FROM dual; 結果 bcdaaxyz(兩邊的a沒了)
SELECT 123||ltrim(' abcd ') ||456 FROM dual; 結果:123abcd 456(修剪左邊空格)
SELECT 123||rtrim(' abcd ') ||456 FROM dual; 結果:123 abcd456(修剪右邊空格)
SELECT rtrim('aabcdaaxyza','a') FROM dual; 結果:aabcdaaxyz(修剪右邊a)
SELECT ltrim('aabcdaaxyza','a') FROM dual; 結果:bcdaaxyza(修剪左邊a)
11.replace(字串,查詢字串[,替換字串])
替換字串中的子串,預設替換為空的字串
SELECT replace('abcdefgabcd','cd') FROM dual; 結果:abefgab
SELECT replace('abcdefgabcd','cd','#') FROM dual; 結果:ab#efgab#
12.chr:把編碼轉化字元
SELECT chr(65) FROM dual; 結果 A
13.ascii:把字元轉換為編碼
SELECT ascii('A') FROM dual; 結果:65
SELECT ascii('國') FROM dual;結果:47610
14.查詢員工姓和名字數相等的員工
SELECT *
FROM employees
WHERE length(first_name) = length(last_name);
15.查詢last_name以s結尾的員工(不用like)
SELECT *
FROM employees
WHERE substr(last_name,-1) = 's';
16.查詢所偶遇員工姓和名,輸出以下格式s.king
SELECT substr(first_name,1,1)||'.'||last_name
FROM employees ;
17.查詢所有的電話號碼,把分隔符“.”換成“-”之後再輸出
SELECT replace(phone_number,'.','-')
FROM employees ;
18.使用者輸入一個任意編號,查詢此編號的員工
(&後面的input是變數,input可以改成任意值,執行此SQL語句時Oracle會提示你輸入一個值)
SELECT *
FROM employees
WHERE employee_id = &input;
19.使用者輸入一個關鍵字,查詢last_name包含此關鍵字的員工(不用like)
SELECT *
FROM employees
WHERE instr(last_name,'&input')>0;
用這個方法好處是使用者查詢帶%的資料不用轉義
20.自定義方法,用自動生成用註釋做別名的查詢發放
CREATE OR REPLACE FUNCTION F_COLCOM(TNAME IN VARCHAR2) RETURN VARCHAR2 IS
RESULT VARCHAR2(4000);
TSQL VARCHAR2(4000);
BEGIN
DECLARE
CURSOR C_JOB IS
SELECT COLUMN_NAME, COMMENTS
FROM USER_COL_COMMENTS
WHERE UPPER(TABLE_NAME) = UPPER(TNAME);
C_ROW C_JOB%ROWTYPE;
BEGIN
FOR C_ROW IN C_JOB LOOP
TSQL := TSQL || C_ROW.COLUMN_NAME || ' "' || C_ROW.COMMENTS || '|' || C_ROW.COLUMN_NAME || '",';
END LOOP;
TSQL := SUBSTR(TSQL, 1, LENGTH(TSQL) - 1);
TSQL := 'select ' || TSQL || ' from ' || TNAME || ';';
END;
RESULT := TSQL;
RETURN(RESULT);
END F_COLCOM;
呼叫方法:SELECT f_colcom('bz_projectcase') FROM dual;
如果只要註釋,不要列名:
CREATE OR REPLACE FUNCTION F_COLCOM(TNAME IN VARCHAR2) RETURN VARCHAR2 IS
RESULT VARCHAR2(4000);
TSQL VARCHAR2(4000);
BEGIN
DECLARE
CURSOR C_JOB IS
SELECT COLUMN_NAME, COMMENTS
FROM USER_COL_COMMENTS
WHERE UPPER(TABLE_NAME) = UPPER(TNAME);
C_ROW C_JOB%ROWTYPE;
BEGIN
FOR C_ROW IN C_JOB LOOP
TSQL := TSQL || C_ROW.COLUMN_NAME || ' "' || C_ROW.COMMENTS || '",';
END LOOP;
TSQL := SUBSTR(TSQL, 1, LENGTH(TSQL) - 1);
TSQL := 'select ' || TSQL || ' from ' || TNAME || ';';
END;
RESULT := TSQL;
RETURN(RESULT);
END F_COLCOM;
七、常用的數學函式和日期函式
1.round:(數字【,小數位數】):按照指定小數位數,四捨五入,預設到整數位
SELECT round(3.1415927) FROM dual; 結果--3
SELECT round(3.5415927) FROM dual; 結果--4
SELECT round(3.5415927,2) FROM dual; 結果--3.54
2.trunc:(數字【,小數位數】):截斷到指定位數,不四捨五入,預設保留到整數位
SELECT trunc(3.1415927) FROM dual; 結果:3
SELECT trunc(3.5415927) FROM dual; 結果:3
SELECT trunc(3.5415927,2) FROM dual; 結果3.54
SELECT trunc(3.5) FROM dual; 結果:3
3.floor:返回不大於本身的最大整數
SELECT floor(-3.5) FROM dual; 結果-4
4.ceil(數字):進位取整
SELECT ceil(3.000001) FROM dual; 結果:4
SELECT ceil(3.0) FROM dual; 結果:3
5.mod:(被除數,除數):求模
SELECT mod(5,3) FROM dual; 結果:2
6.sysdate:返回當前系統的日期時間
SELECT sysdate FROM dual;
7.日期型別和數字型別可以做加減運算:一個日期加減一個數字返回的還是一個日期(單位是天)
SELECT sysdate+3 FROM dual;
SELECT sysdate-100 FROM dual;
SELECT sysdate+1/24/60*25 FROM dual; +25分鐘
8.一個日期減去另外一個日期返回的是兩個日期間隔的天數
日期加減會有小數,可以用數學函式進行截斷
SELECT hire_date,trunc(sysdate-hire_date) AS 間隔天數 FROM employees;
9.months_between(日期1,日期2):返回兩個日期間隔多少月 hire_date為入職日期
查詢每個員工的編號,姓名,入職日期,工齡
SELECT employee_id,last_name,hire_date,trunc(months_between(sysdate,hire_date)/12) 工齡
FROM employees ;
10.add_months(日期,N):給一個日期加減若干個月,返回一個新日期
N為正數是加,為負數是減
SELECT add_months(sysdate,-15) FROM dual;
11.查詢入職日期超過20年的員工資訊(months_between和add_months兩種方式)
SELECT *
FROM employees
WHERE trunc(months_between(sysdate,hire_date)/12)>=20;
SELECT *
FROM employees
WHERE add_months(hire_date,20 * 12)<=sysdate;
12.next_day(日期,星期幾):返回以指定日期為準,一個最近的星期幾的日期
SELECT next_day(sysdate,'星期五') FROM dual;
可以用數字1-7代表日—六 1代表星期日
SELECT next_day(sysdate,6) FROM dual; 下週五
13. last_day(日期):返回指定日期的月最後一天的日期
SELECT last_day(sysdate) FROM dual;
14.round(日期【,日期單位】):對日期進行四捨五入 從12點開始
SELECT round(sysdate) FROM dual;
SELECT round(sysdate,'month') FROM dual; 超過半月就是下一個月
SELECT round(sysdate,'year') FROM dual ; 超過半年就是下一年
15.trunc(日期【,日期單位】):對日期進行截斷
SELECT trunc(sysdate) FROM dual; 返回當天日期 月分秒都會被捨去
SELECT trunc(sysdate,'month') FROM dual ; 返回月初日期
SELECT trunc(sysdate,'year') FROM dual ; 返回年初日期
oracle轉換函式主要轉換3種類型,日期,數字,字串
分隱式和顯示轉換 日期和數字都可以自由轉化字串
但是日期不能轉換為數字
16.SELECT '100' + '50' FROM dual; 結果:150
17.SELECT *
FROM employees
WHERE hire_date<='1-1月-90'; 字元型別自動轉化成日期型別
18.SELECT 100||'hello' FROM dual; 結果100hello 轉化成字元型別
19.SELECT ’現在的時間:‘||sysdate FROM dual; 查詢結果為 現在時間:10-10月-16
20.顯示轉化 3個函式
TO_NUMBER
TO_DATE
TO_CHAR
21.to_char(日期|數字,'模式'):把一個日期或者數字按照指定模式轉化為字串
SELECT '現在時間:'||sysdate FROM dual; 結果:現在時間:10-OCT-16
SELECT '現在時間:'||to_char(sysdate,'yyyy-mm-dd') FROM dual; 結果:現在時間:2016-10-10
SELECT '現在時間:'||to_char(sysdate,'dd/mm/yyyy') FROM dual; 結果:現在時間:10/10/2016
SELECT '現在時間:'||to_char(sysdate,'dd/mm/yyyy hh24:mi:ss') FROM dual; 結果:時間:10/10/2016 21:26:22
SELECT '現在時間:'||to_char(sysdate,'dd/mm/yyyy day') FROM dual; 結果:現在時間:10/10/2016 monday
SELECT '現在時間:'||to_char(sysdate,'dd/mm/yyyy d') FROM dual; 結果:現在時間:10/10/2016 2 (2代表星期一)
SELECT '現在時間:'||to_char(sysdate,'year-month-ddspth day') FROM dual; 結果:現在時間:twenty sixteen-october -tenth monday
(單詞性質的日期)
SELECT '現在時間:'||to_char(sysdate,'yyyy"年"mm"月"dd"日"') FROM dual; 結果:現在時間:2016年10月10日 注意:要雙引號轉義!
SELECT '現在時間:'||to_char(ADD_MONTHS(sysdate,-1),'fmyyyy-mm-dd') FROM dual
結果:現在時間:2016-9-10 fm去除月或者日前面的0.
SELECT '數字:'|| to_char(&input,'fm9990.99') FROM dual; 最大4位整數,兩位小數,個數位必須有一個數字
SELECT '數字:'|| to_char(&input,'fm9990.0099') FROM dual; 最大4位整數,四位小數,個數位必須有一個數字,小數位有兩位小數
SELECT '數字:'|| to_char(&input,'fmL9990.0099') FROM dual; L為本地貨幣符號
SELECT '數字:'|| to_char(&input,'fmL9,990.0099') FROM dual;多一個千分為 :1.001.0052
22.查詢17號入職的員工
SELECT *
FROM employees
WHERE to_char(hire_date , 'dd') = '17';
23,查詢7,8月份入職的員工
SELECT *
FROM employees
WHERE to_char(hire_date,'mm') IN (7,8);
24.to_date(日期字串,’模式‘):把日期字串按一定模式解析為一個日期型別
查詢95年以前入職員工
SELECT *
FROM employees
WHERE hire_date<=to_date('1995-1-1','yyyy-mm-dd');
25,計算世界末日之後過了多少天
SELECT sysdate - to_date('2012-12-21','yyyy-mm-dd') FROM dual;
26.to_number(數字字串,’模式‘):把一個字串解析為一個數字型別
SELECT *
FROM employees
WHERE salary>to_number('$5,600','$9,999');
SELECT *
FROM employees
WHERE salary>to_number(¥5,600','¥9,999');
八、通用函式,適合所有資料型別
1.nvl(引數1,引數2):如果引數1不為空,返回引數1,如果為空,返回引數2
SELECT nvl(1,2) FROM dual; 結果1
SELECT nvl(null,2) FROM dual; 結果2
2.nvl2(引數1,引數2,引數3):如果引數1不為空,返回引數2,如果引數1為空,返回引數3
SELECT nvl2(1,2,3) FROM dual; 結果:2
SELECT nvl2(null,2,3) FROM dual;結果:3
3.nullif(引數1,引數2): 引數1不等於引數2,返回引數1,如果相等,返回空
SELECT nullif(1,2) FROM dual; 結果:1
SELECT nullif(1,2) FROM dual; 結果:NULL
4.coalesce(引數1,引數2,引數3...) :返回第一個非空值,如果都為空,則返回空
SELECT coalesce(1,2,3,4,5) FROM dual; 結果:1
SELECT coalesce(NULL,NULL,3,4,5) FROM dual;
5.查詢員工編號,姓名,工資,獎金金額,實發工資(工資+獎金)
(獎金有可能是空 直接加NULL結果是空 還有運算時不能用別名)
SELECT employee_id , last_name , salary , salary*nvl(commission_pct , 0) AS comm,
salary+salary*nvl(commission_pct , 0) AS money
FROM employees;
6.查詢10號 , 20號 和沒有部門的員工(不用is null ,is not null實現)
SELECT *
FROM employees
WHERE nvl(department_id,-1) IN (10,20,-1);
7. 用case表示式做等值判斷
case 表示式
when 值1 then 返回值1
when 值2 then 返回值2
... ...
CASE department_id
WHEN 90 THEN 'NEC'
WHEN 50 THEN 'HSW'
WHEN 60 THEN 'USO'
WHEN 80 THEN 'NEC'
[else 預設返回值]
end
查詢員工編號,姓名,工資,部門編號,部門名稱
部門編號:
90 HEC
50 HSW
60 USO
80 NEC
其他 ICSS
SELECT employee_id,last_name,salary,
department_id,
CASE department_id
WHEN 90 THEN 'NEC'
WHEN 50 THEN 'HSW'
WHEN 60 THEN 'USO'
WHEN 80 THEN 'NEC'
ELSE 'ICSS'
END AS department_name
FROM employees
--查詢員工編號,姓名,工資,工資級別,部門編號
工資級別:
>=17000 A
>=10000 B
>=5000 C
其他 D
SELECT employee_id , last_name,salary,
CASE
WHEN salary>=17000 THEN 'A'
WHEN salary>=10000 THEN 'B'
WHEN salary>=5000 THEN 'C'
ELSE 'D'
END AS 工資級別
department_id
FROM employees;
8.decode(表示式,值1,返回值1,值2,返回值2,....【,預設返回值】)做等值判斷
查詢員工編號,姓名,工資,部門編號,部門名稱
部門編號:
90 HEC
50 HSW
60 USO
80 NEC
其他 ICSS
SELECT employee_id,last_name,salary,department_id,
decode(department_id,90,'NEC',50,'HSW',60,'USO',80,'GE','ICSS') AS department_name
FROM employees
RDBMS:關係型資料庫管理系統
表和表之間有引用關係,可以減少資料冗餘,方便後期維護
九、關係表的概念名詞
主表:被從表引用的表 有主鍵 唯一 不重複 不為空
從表:引用其他表的表 有外來鍵 外來鍵允許重複 允許為空 必須是主表中存在的值
資料庫中三大關係:
一對多 一條記錄匹配多條記錄(最常見的)
一對一 一條記錄匹配一條記錄
多對多 一個表的多條記錄匹配另外一個表的多條記錄(間接形成 使用者許可權會用到)
關係表三正規化(可以違反提高效率,主要看需求)
表不可以分割,表要有主鍵,表只引用其它表的主鍵
1.查詢員工編號,姓名,部門名稱(SQL1992)(笛卡爾集)
SELECT employee_id , last_name,department_name
FROM employees,departments;
笛卡爾集產生條件:
省略連線條件
連線條件無效
所有表中的所有行互相連線
2.查詢員工編號,姓名,部門名稱
SELECT employee_id , last_name,department_name
FROM employees,departments
WHERE employees.department_id = departments.department_id;
這樣寫得話有一個缺點 , 如果部門值為空的就查不出來
連線n個表,至少需要n-1個連線條件 起別名要用空格不能用AS
連線表查詢,首先要弄清表關係!
3.查詢所有部門的編號,部門名稱,部門經理ID,部門經理名稱,部門所在城市及地區
SELECT d.department_id,
d.department_name,
e.employee_id,
e.last_name,
l.city,
c.country_name,
r.region_name
FROM departments d,
employees e,
locations l,
countyies c,
regions r
WHERE d.manager_id=e.employee_id
AND d.location_id=l.location_id
AND l.country_id=c.country_id
AND c.region_id=r.region_id;
4.檢視員工職務變更歷史記錄:(表多的話兩個兩個來)
員工編號,姓名,起始日期,終止日期,職務名稱,部門名稱
SELECT e.employ_id,
e.last_name,
h.start_date,
h.end_date,
j.job_title,
d.department_name
FROM employees e,
job_history h,
jobs j,
department d
WHERE e.employee_id=h.employee_id
AND h.job_id=j.job_id
AND h.department_id=d.department_id
5.非等值連線(級別不存在相交,蠻少用)
查詢每個員工編號,姓名,工資,工資級別
SELECT e,employee_id,
e.employee_name,
e.salary,
g.grade_level
FROM employee e,
job_grades g
WHERE e.salary BETWEEN g.lowest_sal AND g.highest_sal
ORDER BY e.employee_id
6.內連線:查詢僅滿足連線條件的(連線查詢容易漏掉NULL值的條件)
外連線:不僅返回滿足連線條件的記錄,不滿足連線條件的也返回 返回空值
查詢員工編號,姓名,部門名稱(外連線,沒有部門的員工也返回)
SELECT e.employee_id ,
e.last_name,
d.department_name
FROM employees e,
departments d
WHERE e.department_id=d.department_id(+);
查詢員工編號,姓名,部門名稱(外連線,沒有員工的部門也返回)
SELECT e.employee_id ,
e.last_name,
d.department_name
FROM employees e,
departments d
WHERE e.department_id(+)=d.department_id;
7.查詢每個部門的編號,部門名稱,部門經理ID,部門經理姓名 (沒有部門經理的部門也返回)
SELECT d.department_id,
d.department_name,
e.employee_id,
e.employee_name
FROM departments d,
employees e
WHERE e.manager_id=e.employee_id(+);
8.自連線查詢(把它當作兩個表)
查詢員工編號,姓名,員工管理者編號,員工管理者姓名
SELECT e.employee_id,
e.last_name,
m.employee_id MGR_ID,
m.last_name MGR_NAME
FROM employees e,
employees m
WHERE e.manager_id=m.employee_id(+);
9.查詢誰的工資比Abel高
SELECT e1.employee_id,
e1.last_name,
e1.salary,
e2.last_name,
e2.salary
FROM employees e1,
employees e2
WHERE e1.salary>e2.salary
AND e2.last_name='Abel'
十、SQL1999語法(效率比SQL1992的效率要高)
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)];
1.SQL1999連線語法
查詢員工編號,姓名,部門編號,部門名稱(叉表 查詢笛卡爾集 沒啥用)
SELECT e.employee_id,
e.last_name,
d.department_id,
d.department_name
FROM employees e
CROSS JOIN departments d
2.內連線:INNER JOIN
外連線:
左外連線 LEFT OUTER JOIN
右外連線 RIGHT OUTER JOIN
滿外連線 FULL OUTER JOIN
3.查詢員工編號,姓名,部門編號,部門名稱,職務編號,職務名稱(內連線 查不出來空值)
SELECT e.employee_id,
e.last_name,
d.department_id,
d.department_name,
j.job_id,
j.job_title
FROM employees e
INNER JOIN departments d ON e.department_id=d.department_id
INNER JOIN jobs j ON e.job_id=j.job_id
WHERE e,salary>=5000
ORDER BY e,salary DESC;
4. 查詢員工編號,姓名,部門編號,部門名稱(左外連線 LEFT OUTER左邊不滿足連線條件的也返回 返回employees資料)
SELECT e.employee_id,
e.last_name,
d.department_id,
d.department_name,
FROM employees e LEFT OUTER JOIN departments d ON e.department_id=d.department_id;
5. 查詢員工編號,姓名,部門編號,部門名稱(右外連線 RIGHT OUTER右邊不滿足連線條件的也返回 返回departments資料)
SELECT e.employee_id,
e.last_name,
d.department_id,
d.department_name,
FROM employees e RIGHT OUTER JOIN departments d ON e.department_id=d.department_id;
6. 查詢員工編號,姓名,部門編號,部門名稱(滿外連線 部門為空的員工和員工為空的部門都返回)
SELECT e.employee_id,
e.last_name,
d.department_id,
d.department_name,
FROM employees e FULL OUTER JOIN departments d ON e.department_id=d.department_id;
十一、組函式及分析函式
1.組函式作用於一組資料,並對一組資料返回一個值。
查詢所有工資的總和
SELECT SUM(salary) FROM employees;
2.組函式(如果是0行資料,count返回0 其他返回null)
SELECT SUM(salary),AVG(salary),MAX(salary),MIN(salary),COUNT(salary)
FROM employees
WHERE department_id=50;
3.所有組函式都是忽略空值
SELECT count(commission_pct) FROM employees;
4.查詢所有沒有獎金的人數
SELECT COUNT(*)-COUNT(commission_pct) FROM employees;
5.查詢部門總數(統計不重複的計數)
SELECT COUNT(DISTINCT department_id) FROM employees;
6.查詢每個部門的ID,員工工資總和,最高工資(三大子句同時使用)
SELECT department_id,
SUM(salary) SAL_SUM,
MAX(salary)
FROM employees
WHERE department_id IS NOT NULL
GROUP BY department_id
ORDER BY sal_sum DESC;
7. 多個分組表示式(兩個欄位完全相同分成一組)
SELECT department_id,
job_id,
SUM(salary)
FROM employees
GROUP BY department_id,job_id;
8.查詢每個部門的名稱.人數
SELECT d.department_name , count(e.employee_id) emp_count
FROM employees e
INNER JOIN departments d ON e.department_id=d.department_id
GROUP BY d.department_name;
9.統計每年入職的人數:年份,人數
SELECT to_char(hire_date,'yyyy') 年份,count(*) 人數
FROM employees
GROUP BY to_char(hire_date,'yyyy')
ORDER BY 1;
10 .統計每年入職的人數:年份,人數(僅返回不少於2人的年份的資料)
用HAVING還是用WHERE 主要看需要的過濾的結果是分組之前的,還是分組之後的
SELECT to_char(hire_date,'yyyy') 年份,count(*) 人數
FROM employees
GROUP BY to_char(hire_date,'yyyy')
HAVING COUNT(*)>=2
ORDER BY 1;
11.分析函式
over函式連續求和
over1列資料是根據員工id進行累加求和(每一行結果是上行累加工資總和加這行工資)
over2總工資
SELECT employee_id,
salary,
department_id,
SUM(salary) over(ORDER BY employee_id) over1,
SUM(salary) over() over2
FROM employees;
12.連續求和 分組求和 將相同部門工資求一個總和 (相同組結果一樣)
SELECT employee_id,
salary,
department_id,
SUM(salary) over(PARTITION BY department_id) over1,
FROM employees;
13. 連續求和 over1和12一樣 over2是分組之後累加(相同組結果一樣)
over3將相同部門進行累計求和
SELECT employee_id,
salary,
department_id,
SUM(salary) over(PARTITION BY department_id) over1,
SUM(salary) over(ORDER BY employee_id) over2,
SUM(salary) over(PARTITION BY department_id ORDER BY employee_id) over3
FROM employees;
14.按照部門編號做排名
row_number()通過部門ID排序做累加 從1開始 1,2,3,4,5,6.....(沒有並列)
dense_rank()通過部門ID分組後排序做累加 相同部門公用1個值 從1開始 1,2,2,3,3,3,4,5,5,6.....
rank()通過部門ID分組後排序做累加 相同部門公用1個值 從1開始 空出被佔的名次 1,2,2,4,4,4,4,4,9,9......
SELECT row_number() over(ORDER BY department_id) row_number,
dense_rank() over(ORDER BY department_id) dense_rank,
rank() over(ORDER BY department_id) rank,
department_id,
employee_id,
last_name
FROM employees;
15.按照部門編號降序做排名 降序空值排第一位
SELECT rank() over(ORDER BY department_id DESC) rank,
department_id,
employee_id,
last_name
FROM employees;
十二、彙總(ANY、相關子查詢、EXISTS、WITH)
1查詢工資最高的前5名員工
SELECT *
FROM (SELECT *
FROM employees
ORDER BY salary DESC)
WHERE ROWNUMBER <=5;
2.查詢員工表中第6到第12條資料
SELECT *
FROM (SELECT ROWNUM rnum ,e.* FROM employees e WHERE ROWNUM<=12)
WHERE rnum > =6 ;
3,查詢工資最高的第6到12條員工
SELECT *
FROM (SELECT ROWBUM rnum, e.*
FROM (SELECT *
FROM employees
ORDER BY salary DESC) e
WHERE ROWNUM<=12)
where rnum>=6;
4.查詢所有不是部門經理的員工
SELECT *
FROM employees
WHERE employee_id NOT IN (SELECT manager_id FROM department WHERE manager_id IS NOT NULL)
5 ANY 邏輯或比較 ALL邏輯與比較(可以用MAX MIN 取代)
6.相關子查詢(內外互動式相關子查詢)
按照一行接一行的順序執行,主查詢的每執行一行都執行一次子查詢
子查詢用到主查詢的資料
查詢員工編號,姓名,部門編號,工資,本部門的工資總和
SELECT employee_id,
last_name,
department_id,salary,
(SELECT SUM(salary)
FROM employees
WHERE department_id = e.department_id)
FROM employees e;
7查詢所有工資超過本部門平均工資的員工
SELECT *
FROM employees e
WHERE salary>(SELECT AVG(salary) FROM employees WHERE department_id = e.department_id);
8.查詢是本部門入職最早的但不是部門經理的員工
SELECT *
FROM employees e
WHERE hire_date=(SELECT MIN(hire_date)
FROM employees
WHERE department_id=e.department_id)
AND employee_id NOT IN (SELECT manager_id
FROM employees
WHERE manager_id IS NOT NULL)
9.EXISTS查詢(EXISTS後面的子查詢如果查得出資料,那麼主查詢才查得出來資料)
SELECT *
FROM employees
WHERE EXISTS(SELECT * FROM departments WHERE 1=0)
10.查詢所有是部門經理的員工(代替in語法 提高效率 X代表任意資料)
SELECT *
FROM employees e
WHERE EXISTS(SELECT 'X'
FROM departments d
WHERE e.employee_id = d,manager_id);
11.查詢所有不是部門經理的員工(代替in語法 提高效率 X代表任意資料)
SELECT *
FROM employees e
WHERE NOT EXISTS(SELECT 'X'
FROM departments d
WHERE e.employee_id = d,manager_id);
12.查詢工資最高的前5的員工(WITH子句)
WITH new_emp as (SELECT * FROM employees ORDER BY salary DESC)
SELECT * FROM new_emp WHERE ROWNUM<=5;
13.WITH子句 定義子查詢作為一個表起別名 然後在後面的查詢中呼叫(可以定義多個表)
WITH dept_costs AS
(SELECT d.department_name,
SUM(e.salary) AS dept_total)
FROM employees e,
departments d
WHERE e,department_id = d.department_id
GROUP BY d.department_name),
avg_cost AS
(SELECT SUM(dept_total) / COUNT(*) AS dept_avg
FROM dept_costs)
SELECT *
FROM dept_costs
WHERE dept_total > (SELECT dept_avg
FROM avg_cost)
ORDER BY department_name;
十三、樹狀結構分級查詢
1.分級查詢(遍歷樹結構的資料)(通過子節點查詢父節點 通過父節點查詢子節點)
CONNECT BY PRIOR cloumn1 = column2
從頂到底 cloumn1 = Parent Key
cloumn2 = Child Key
從底到頂 cloumn1 = Child key
cloumn2 = Parent Key
2.查詢206號員工所有的上級管理者(包括管理者的管理者)
<level>代表層次 從1開始 可以並列
SELECT level,employee_id,last_name,manager_id
FROM employees
START WITH employee_id = 206
CONNECT BY PRIOR manager_id = employee_id;
3.查詢101員工所有的下級員工(從上向下)
SELECT level , employee_id,last_name,manager_id
FROM employees
START WITH employee_id = 101
CONNECT BY PRIOR employee_id =manager_id;
4.統計101員工的所有的手下的人數
(WHERE子句過濾單個節點)
SELECT COUNT(*)
FROM employees
WHERE employee_id<>101
START WITH employee_id = 101
CONNECT BY PRIOR employee_id = manager_id;
5.過濾整個分支(將205整個分支過濾掉)
SELECT COUNT(*)
FROM employees
START WITH employee_id = 101
CONNECT BY PRIOR employee_id = manager_id AND employee_id <>205;
6. DML(增刪改)
插入資料 insert in 表名 【(列1,列2,...)】 values (值1,值2,...) ;
省略列列表,預設就是表中的所有列
列和值必須要個數,順序,型別相同
7.增加一個新部門
INSERT INTO departments (department_id,department_name,manager_id,localtion_id)
VALUES (120,'NEC',206,1700);
8,查詢結果儲存為表(快速創表)
CREATE TABLE new_emp
AS
SELECT employee_id,last_name,salary
FROM employees;
(建立空表)
CREATE TABLE new_dept
AS
SELECT * FROM departments WHERE 1=0;
9.插入多行資料(底層資料庫維護用處比較多)
INSERT INTO new_dept SELECT * FROM departments;
我們經常寫的update語句其實是被簡寫過的,如果需要給更新語句起別名,參考這種寫法:
UPDATE T SET T.TID=1,T.TNAME='Name',T.TClass=1 FROM [TABLE] T WHERE T.ID=10
10.更新資料 update 表名 set 列1=值1,列2=值,...[where 子句](不加where更新所有資料)
UPDATE new_emp SET first_name='三',last_name='張' WHERE employee_id = 100
11.修改60號部門員工的工資上浮50元
UPDATE new_emp SET salary = salary+50 WHERE department_id = 60;
12.修改103號員工的工資和100號員工相同
UPDATE new_emp SET salary = (SELECT salary FROM new_emp = WHERE employee_id = 100)
WHERE employee_id = 103;
13.刪除資料 delete from 表名 [where 子句]
刪除部門名稱為IT的部門的員工
DELECT FROM new_emp
WHERE department_id = (SELECT department_id
FROM departments
WHERE department_name = 'IT');
14合併語句merge 解決效率問題 做資料同步 (同步修改 新增)
按照指定的條件執行插入或跟新操作
如果滿足條件的行存在,執行跟新操作,否則執行插入操作
避免多次重複執行插入和刪除操作
提高效率而且使用方便
在資料倉庫用的比較多
建立倆個表 修改部分資料
CREATE TABLE emp1
AS
SELECT employee_id,last_name,salary
FROM employees;
CREATE TABLE emp2
AS
SELECT employee_id,last_name,salary
FROM employees;
MERGE INTO emp2 e2
USING emp1 e1 ON(e1.employee_id = e2.employee_id)
WHEN MATCHED THEN
UPDATE SET e2.last_name = e1.last_name,e2.salary=e1.salary
WHEN NOT MATCHED THEN
INSERT VALUES (e1.employee_id,e1.last_name, e1.salary)
十三、oracle鎖
oracle鎖一般都是預設加,當一個事務開始的時候預設加鎖,當一個事務結束的時候,預設取消鎖。當然也可以人為加鎖。
一.oracle鎖按照顆粒劃分可以分為行鎖和表鎖。
1.行鎖是鎖住一行(DML語句中,增,刪,改等都是加的行鎖)。
2.表鎖是鎖住一個表,比如(DDL語句一般加的都是表鎖)。
二.oracle鎖按照顯隱可以劃分為顯示鎖和隱式鎖
1.隱式鎖是預設加的鎖(DML語句中,增,刪,改等都是加的都是隱式鎖);
2.顯示鎖是人工手動加鎖。一般查詢語句是不會加鎖的,但是也可以手動加鎖(sql語句後面加 for update 鎖行)
還有一種情況是手動鎖表,手動鎖表分為兩種:lock table 表 in share | exclusive mode;
share模式:禁止其他會話對錶做DML操作,但是允許其他會話也對錶加share鎖
exclusive模式:禁止其他會話對錶進行DML操作,也禁止其他會話對錶加任何鎖
三.oracle鎖按型別分可以分為獨佔鎖和共享鎖
1.獨佔鎖
2.共享鎖
(DML語句對錶中行加的是獨佔鎖,對錶加的是共享鎖) 也就是說,事務執行增,刪,改操作操作的時候,鎖住了表的一行,
其他的事物對這一行不能進行操作,可以對該表的其他行進行操作。
(加了共享鎖的表不能再加獨佔鎖) 事務執行增,刪,改操作操作的時候,給表加上了共享鎖,那麼該表就不能執行DDL語句,
也就是說不能對該表進行刪除表等操作
四.oracle死鎖(兩個事務互相鎖)
舉個例子。A事務和B事務同時執行操作a,b兩行,首先A事務鎖住了a行,然後B事務鎖住了b行,A事務還要操作b行,
但是b行被B事務鎖住了,所以A事務等待B事務解鎖。而B事務還要操作a行,但是現在a行被A事務鎖住,所以B事務要等待A事務
對a行解鎖。然後兩個事務就發生了死鎖(互相等待別的事務解鎖)。
死鎖是不可避免的,但是oracle會對死鎖進行檢查,如果檢測到死鎖會丟擲一個異常,這裡可以用JAVA捕獲異常的機制捕獲死鎖異常
回滾其中一個事務,就能解決死鎖問題了。
五.oracle強行解鎖
1.下面的語句用來查詢哪些物件被鎖:
select object_name,machine,s.sid,s.serial#
from v$locked_object l,dba_objects o ,v$session s
where l.object_id = o.object_id and l.session_id=s.sid;
2.下面的語句用來殺死一個程序:
alter system kill session '24,111'; (其中24,111分別是上面查詢出的sid,serial#)
【注】以上兩步,可以通過Oracle的管理控制檯來執行。
3.如果利用上面的命令殺死一個程序後,程序狀態被置為"killed",但是鎖定的資源很長時間沒有被釋放,那麼可以在os一級再殺死相應的程序(執行緒),首先執行下面的語句獲得程序(執行緒)號:
select spid, osuser, s.program
from v$session s,v$process p
where s.paddr=p.addr and s.sid=24 (24是上面的sid)
4.在OS上殺死這個程序(執行緒):
1)在unix上,用root身份執行命令:
#kill -9 12345(即第3步查詢出的spid)
2)在windows(unix也適用)用orakill殺死執行緒,orakill是oracle提供的一個可執行命令,語法為:
orakill sid thread
其中:
sid:表示要殺死的程序屬於的例項名
thread:是要殺掉的執行緒號,即第3步查詢出的spid。
oracle鎖一般都是預設加,當一個事務開始的時候預設加鎖,當一個事務結束的時候,預設取消鎖。當然也可以人為加鎖。
十四、DDL語句
表名和列名:
必須是已字母開頭
必須在1-30個字元之間
必須只能包含A-Z,a-z,0-9,_,$和#
必須不能和使用者定義的其他物件重名
必須不能是Oracle保留字
建立表 CREATE TABLE [schema.] table (column datatype [DEFAULT expr][,...]);
必須具備 CREAT TABLE許可權
儲存空間
必須指定表名,列名,資料型別,尺寸
建立表
CREATE TABLE student
(
stu_id NUMBER(6),
stu_name VARCHAR2(50).
stu_sex CHAR(2),
stu_hiredate DATE
);
刪除表
DROP TABLE student;
建立表(帶預設值 插入時候使用者沒賦值用預設值,插入賦值就用賦的值)
CREATE TABLE student
(
stu_id NUMBER(6),
stu_name VARCHAR2(50).
stu_sex CHAR(2) DEFAULT '男';,
stu_hiredate DATE DEFAULT SYSDATE
);
利用子查詢建立表
CREATE TABLE new_emp2
AS
SELECT employee_id,last_name
FROM employees;
常用的資料字典
SELECT *
FROM user_tables;
SELECT *
FROM user_objects;
SELECT *
FROM user_catalog;
修改列(使用 ALTER TABLE語句)
追加新的列
修改現有的列
為新追加的列定義預設值
刪除一個列
--追加
ALTER TABLE student
ADD (phone VARCHAR2(50),address VARCHAR2(100));
--修改(資料結構要相容)
ALTER TABLE student
MODIFY (address VARCHAR2(200));
--刪除列
ALTER TABLE student
DROP (phone);
--表註釋
COMMENT ON TABLE stu IS '這是我的學生表';
--列註釋
COMMENT ON COLUMN stu.stu_id IS '學生編號';
COMMENT ON COLUMN stu.stu_name IS '學生姓名';
--回收站的資料字典
SELECT * FROM user_recyclebin;
--還原表(閃回)
FLASHBACK TABLE stu TO BEFORE DROP;
--清空回收站
PURGE RECYCLEBIN;
臨時表
建立事務臨時表 : 資料僅在一個事務中存在
CREATE GLOBAL TEMPORARY TABLE temp1
(
id NUMBER ,
name VARCHAR2(50)
)
ON COMMIT DELETE ROWS;
建立會話臨時表:資料僅在一個會話中存在
CREATE GLOBAL TEMPORARY TABLE temp2
(
id NUMBER,
name VARCHAR2(50)
)
ON COMMIT PRESERVE ROWS;
約束(5種)
NOT NULL 非空約束(限制列值不能為NULL)
UNIQUE 唯一值約束
PRIMARY KEY 主鍵約束 (現在列值不允許重複,不能為空,一個表只能有一個)
FOREIGN KEY 外來鍵約束
CHECK 檢查約束
--增加約束
ALTER TABLE 表名
ADD CONSTRAINTS 自定義約束名稱(一般設定表名_列名_pk) 約束設定(列名,...)
--刪除約束
ALTER TABLE newemp
DROP CONSTRAINTS 自定義約束名稱;
oracle鎖一般都是預設加,當一個事務開始的時候預設加鎖,當一個事務結束的時候,預設取消鎖。當然也可以人為加鎖。
資料庫快閃記憶體功能,用來解決正式環境刪錯表的問題,慎用!
-- 查詢指定時間之後更新的資料(dcc_org是表名)
select * from dcc_org as of timestamp to_timestamp('2017-12-10 07:30:00', 'yyyy-mm-dd hh24:mi:ss');
-- 閃回操作前啟用行移動功能(不啟用不可以閃回)
alter table dcc_org enable row movement;
-- 執行閃回
flashback table dcc_org to timestamp to_timestamp('2017-12-10 07:30:00', 'yyyy-mm-dd hh24:mi:ss');