ORACLE部分自學筆記整理
--在命令列解鎖賬戶
--使用下面的語句解鎖scott:
alter user scott account unlock;
--解鎖之後可能會要求你該密碼 tiger:
alter user scott identified by tiger;
create table employee(
id number(4),
name varchar2(20) not null,
gender char(1) default 'M',
birth date,
salary number(6,2),
job varchar(30),
deptno number(2)
);
rename employee to myemp;
alter table myemp add (t_table_id number(20));
alter table myemp modify (t_table_id char(10));
alter table myemp drop (t_table_id);
alter table myemp add(birtheate date default sysdate);
--DML 語句,對錶中的資料進行的操作
--伴隨事物控制
INSERT INTO myemp
(id, NAME, salary, deptno)
VALUES
(2, 'lishazi', 100, 10);
SELECT *
FROM myemp
FOR UPDATE;
COMMIT;
--插入日期格式,比較另類
INSERT INTO myemp
(id, NAME, salary, deptno, birtheate)
VALUES
(3, 'cao', 100, 10, to_date('2009-09-01', 'YYYY-MM-DD'));
-- 修改記錄內容
UPDATE myemp
SET NAME = 'ni'
WHERE NAME = 'cao';
-- 查詢出來並修改記錄內容
SELECT *
FROM myemp
FOR UPDATE;
--刪除表中的資料,如果不加條件,是刪除整個表
DELETE FROM myemp;
DELETE FROM myemp
WHERE NAME = 'zoushazi';
truncate myemp; --清空表資料,不受事物控制,不可回滾
---day 03 資料型別
--1,字串型別, char varchar varchar2 long(此型別長度2GB,但是有很多限制,不可作為逐主鍵,不能建索引,不可用於查詢條件,一般不建議使用)
--一般使用 clob 儲存大字串 可儲存4GB 無條件限制
--select子句中使用表示式
--如,查詢工人的年薪
SELECT NAME, salary * 12
FROM myemp
-- --字串函式
concat() --函式,用來連線 兩個 字串
SELECT concat(NAME, salary * 12)
FROM myemp
SELECT concat(concat(NAME, ','), salary)
FROM myemp;
|| --字串拼接符號
SELECT id || ',' || NAME || salary
FROM myemp;
length() --返回變長字串長度
SELECT NAME, length(NAME), length(salary)
FROM myemp;
upper() --全大寫
lower() --全小寫
initcap() --首字母大寫
SELECT upper(NAME), lower(NAME), initcap(NAME)
FROM myemp;
SELECT upper('woshinibaba')
FROM myemp;
--偽表 dual -就是為了查跟表無關係的資料,向上面的語句一樣,必須加表名才可以查詢,所以就有了‘偽 表’
SELECT lower('woshinidie'), initcap('cao')
FROM dual;
SELECT concat(upper('asdfa'), initcap('dsfa'))
FROM dual;
SELECT lower('AFASDF') || '122' || upper('asdf') || initcap('1cao')
FROM dual;
UPDATE myemp
SET salary = 6000.2
WHERE NAME = 'ni';
SELECT lower('ADFASDFASD')
FROM dual;
SELECT upper('nibaba')
FROM dual;
SELECT initcap('asdfasdfa')
FROM dual;
--擷取字串 ,去除字串中兩邊的首個指定重複 字元 (只能去除單個字元)
--注意:如果首字母中不包含要去除的字元,則停止
--trim(c1 from c2) 從C2左右兩邊去除 首個 C1,如果遇到多個C1連續在一起,也連同去掉,直到不再為C1即刻停止去除
--ltrim()僅去除從左邊開始的一個字元
-- rtrim() 僅去除從右邊開始的一個字元
SELECT TRIM('e' FROM 'ieieeiuueuueeiei')
FROM dual;
SELECT ltrim('ieeeraerseeres', 'e')
FROM dual;
SELECT rtrim('asdefefff')
FROM dual;
SELECT TRIM('b' FROM 'eabsdgbag')
FROM dual;
SELECT ltrim('easeaasdfasdfasda', 'baeras')
FROM dual; --多個要去除的字元,會輪流一個一個找,找到就去除,直到遇到要去除字元組中沒有的字元即刻停止
SELECT *
FROM myemp
FOR UPDATE;
INSERT INTO myemp
(id, NAME, salary, birtheate)
VALUES
(4, 'ba', 2015.8, to_date('2018-8-2', 'YYYY-MM-DD'));
--補位函式,用於在字串char1的左端或右端用char2 補足到N 位,char2 可重複多次
lpad(char1,n,char2) --左補位函式
rpad(char1,n,char2) --右補位函式
--例如 在myemp表中使用左補位,將sal用$ 補齊6位
SELECT NAME, lpad(salary, 6, '0') AS sal
FROM myemp;
SELECT NAME, rpad(salary, 7, '$') AS salary
FROM myemp;
SELECT lpad(salary, 2, '$')
FROM myemp; --當 補足到的位數小於原來長度時,會從末尾擷取
SELECT lpad(NAME, 2, '#')
FROM myemp;
--java 的下標預設從 0 開始 ,而Oracle的下標預設從 1 開始
-- 擷取n個字元函式
--substr(char m,n ), 從char 中的m 位開始擷取 n個字元,
--如果 m=0 ,則從首字元開始,如果 m 為負數,則從尾部開始向前數 m個數,繼續向後擷取
--如果沒有設定n,或者 n 的長度超過了char 的長度,則取值到末尾
SELECT substr('asdfasdfasdf', 5, 3)
FROM dual;
SELECT substr(';ladsjfpasdfa', 0, 10)
FROM dual; --但是擷取時如果下標是 0 ,也是從 1 開始
SELECT substr('[oajglk;asj', -5, 100)
FROM dual; --繼續向後擷取,而不是向前
-- instr(char1,char2, n , m ) 返回子串 char2 在源字串char1中的位置
--引數 n :從第n個字元開始檢索
--引數 m :第幾次出現
--m n 不寫預設都是1 ,查詢的是第一次出現的位置
SELECT instr('adfsoafgaf', 'f', 4, 2) AS ini
FROM dual;
SELECT instr('oijaslkfjk;asf', 'k')
FROM dual;
--數值型別
number(m,n)-- m 為長度,n 為小數位 小數位可以從1-38
-- round(m,n) --四捨五入函式 m為任意數字,n 必須為整數
-- n 取正數則四捨五入到小數點後m 位
-- m 取0 值則四捨五入到整數位,不寫預設也是預設 0
-- m 取負數,則四捨五入到小數點前 m 位
select round(15.532) from dual; -- 16
select round(12.444,0) from dual; -- 12
select round(12.233,-1) from dual; -- 10
select round(12.233,-2) from dual; -- 0
--trunc(m,n) 擷取數字
select trunc(45.678,2) from dual; --45.67
select trunc(45.678,0) from dual; --45
select trunc(45.678,-1) from dual; --40
--mod(m,n) 取餘函式, 返回m除以n 後的餘數,
-- n 為0 則直接返回m
select mod(20,3) from dual;
select mod(18,0) from dual; --18
select mod(0,1) from dual;
--cell(n) 向上取整 取大於或等於n的最小整數值
--floor(n) 向下取整 取小於或等於n的最大整數值
select ceil(45.678) from dual;
--TEST
--1,檢視名字只有2 個字母的員工資訊
select * from myemp where length(name)=2;
--2,檢視第三個字母是u的員工資訊
select * from myemp where substr(name,3,1)='u';
--select ename,sal,deptno from emp where length(ename)=5;
--oracle 中的日期型別
-- date() 7 個位元組
--timestamp() 與DATE()的區別就是可以儲存小數 秒,最高精度可以到 NS(納秒)
--sysdate 當前系統時間,精確到秒
select sysdate from dual;
create table student (id number(4), name char(20),register Date default sysdate);
--systimestamp 時間戳型別的時間,11個位元組,精確到毫秒
SELECT systimestamp
FROM dual;
SELECT to_char(systimestamp, 'DD.SS')
FROM dual;
-- 檢視名字只有5 個字母的員工的名字,工資 部門號?
SELECT NAME, salary, bumen_id
FROM emp
WHERE length(NAME) = 5;
-- 檢視第三個字母是A 的員工資訊?
SELECT *
FROM myemp
WHERE substr(NAME, 3, 1) = 'u';
SELECT *
FROM myemp
WHERE instr(NAME, 'u') = 3;
select * from myemp;
select sysdate from dual ;
select systimestamp from dual; --時間戳型別的時間
-- to_date() 函式
可以將字串按照給定的日期格式解析為一個DATE型別的值
SELECT to_date('2001-5-9 20:15:59', 'YYYY-MM-DD HH24:MI:SS')--如果有中文或特殊字元,如“年”“月”“日”要用“ 雙引號”括起來
FROM dual;
--日期的計算
--日期可以與一個數字進行加減法,這相當於加減指定的天數
--兩個日期可以進行減法,差為相差的天數
--檢視每個員工至今入職多少天了?
select name,sysdate-birtheate from myemp
select sysdate-to_date('1993-10-29','YYYY-MM-DD') from DUAL; --活了這些天
select to_date('1993-10-29','YYYY-MM-DD')-sysdate from dual;
--to_char();可以將date()按照給定的格式轉換為字串
select to_char(sysdate,'YYYY-MM-DD HH24:MI:SS') from dual;
--日期格式中 RR 和 YY 的區別
SELECT to_date('50-07-12', 'YY-MM-DD')
FROM dual;
SELECT to_date('50-07-12', 'RR-MM-DD') --RR 是跟世紀有關的
FROM dual;
--- 日期函式
-- last_day(date) : 返回給定日期所在月的月底
select last_day(sysdate) from dual;
-- add_months(date,i ) 對給定日期加上指定的月,若i為負數則是減去
--檢視每個員工入職20 週年的紀念日
select add_months(birtheate,12*20) from myemp;
select add_months(sysdate,10*12) from dual;
-- months_between(date1,date2) 兩個日期之間相差多少個月
select months_between(sysdate,systimestamp) from dual;
select months_between(sysdate,birtheate) from myemp;
--next_date(date,char):返回date 日期資料的下一個周幾,周幾是由引數char來決定的,char可以是-1-7之間的數字,
--1代表週日,7 代表週六
select next_day(sysdate,2) from dual;
--最值函式,除了日期之外常用數字也可以比較大小
--least(a,b,c,d) 最小值 注意:日期越晚,越大
--greatest(a,b,c,d) 最大值
select least(sysdate,birtheate) from myemp;
select greatest(sysdate,birtheate) from myemp;
-- extract() 從指定日期中提取時間分量 如 日,月,年
select extract(year from sysdate) from dual;
select extract(year from birtheate) from myemp;
select extract(day from birtheate) from myemp;
-- 空置操作 null 在Oracle中 不插入的值預設為 NULL
--刪除欄位值為null的記錄
delete from student where gender is null;--判斷是null用 is 而不是 =
--null值得運算與操作
--null 與任何數字運算結果還是null
--null與字串拼接等於什麼都沒幹
select '123'||null from dual; --123
--檢視工資(工資=基本工資+績效+獎金)
select 123+null from dual;
--空值函式
-- nvl(arg1,arg2)
--當arg1為null,函式返回arg2 的值,若不為null,則返回arge1 本身
--所以該函式的作用是將null值替換為一個非null值
--比如
select 123+nvl(null,2) from dual; -- 125
select 123+nvl(1,2) from dual; --124
--檢視每個人的績效情況,即,有績效的,顯示為“有績效”,績效為null 的,顯示為
--”沒有績效“
--使用nvl()函式無法實現,要使用nvl2()函式
--nvl2(arg1,arg2,arg3)
--當arg1不為null,則函式返回arg2
--當arg1為 null,則函式返回arg3
--該函式是根據一個值是否為null來返回兩個不同的結果
select nvl2(null,1,2) from dual; --2
select nvl2(1,2,3) from dual; --2
--別名
--如何讓別名含有空格,或者別名裡面出現大小寫,可以使用雙引號括起來“”
select 12*2 "A a" from dual;
--where 關鍵字中使用 and 和 or 可以使用 ()提高or的優先順序
--使用 like(模糊查詢) 萬用字元 % 多個 _單個字元
select * from myemp where name like 'n%';
select * from myemp where name like '_o%';
--in 和 not in 判斷是否在一個列表中(列表可以為一個子查詢)
select * from myemp where gender in ('M','W');
--any 和 all 配合>,< ,<=,>= 一個列表使用(一般列表是一個子查詢)
>any(list) :大於列表中最小的
>all(list) :大於列表中最大的
<any(list) :小於列表中最大的
<all(list) :小於列表中最小的
--between a and b 判斷是否在一個範圍內包含a 和 b (注意:必須 a<b )
--判斷工資在4000-5000
select * from myemp where salary between 6001 and 5000;
--distinct 去除重複 ,有distinct 修飾的欄位前面不要有欄位,並且,如果使用
--多個distinct,是組合去重,兩個欄位加在一起一樣的去除掉重複
select distinct job from myemp;
select distinct job,distinct salary from myemp;
--排序 order by + 指定的欄位 +asc 升序(預設)/desc 降序, (注意:order by 必須為select 語句的最後一個子句,必須放在最後邊)
--可以按照多個欄位排序,且都可以指定排序方式,優先順序是先按照第一個欄位排序,再按照第二個欄位排序
-- 注意:如果排序時候有null值,則null被認為是最大值
select * from myemp order by salary desc,id;
--聚合函式 用於統計出一個值
--聚合函式又叫多行函式,分組函式
--聚合函式是對結果集某些欄位的值進行統計的
--MAX ,MIN 求給定欄位的最大值與最小值
--avg ,sum 求平均值和總和
--count 函式不是對給定的欄位值進行統計,而是對給定欄位不為 null 的資料的統計
--注意:實際上所有聚合函式都是忽略null 值統計
select count (*) from myemp; --檢視這張表的總共記錄數
select count(name) from myemp; --檢視有多少有名字的記錄
--注意:如果統計的時候出現null值,avg函式會只統計不為null的值,並且除以的也是不為null的個數,所以不能做到真正平均
--這樣就要組合使用 nvl()函式
select avg(salary),sum(salary) from myemp; --平均值為3629,未做到平均,因為有 null
select avg(nvl(salary,0)),sum(salary) from myemp; --平均值2903.32
select * from myemp for update;
--分組 group by 有很多注意事項--
--檢視每個部門的平均工資
select avg(salary) from myemp group by deptno;
--檢視每個職位的最高工資
select max(salary) from myemp group by deptno;
select * from myemp for update;
--關聯查詢
---查詢工資高於3000的員工的名字,工資,部門名以及所在地
select * from dept;
select * from myemp;
alter table myemp rename to emp;
select * from emp;
select e.ename,e.sal,d.dname,d.loc
from emp e,dept d
where e.deptno=d.deptno and sal>3000;
--內連結
--檢視員工名字以及其所在部門的名字
SELECT e.ename, d.dname
FROM emp e
JOIN dept d ON (e.deptno = d.deptno)
WHERE e.ename = 'KING';
--注意,所有不滿足連線條件的記錄是不會在關聯查詢中被查詢出來的
--外連線,可以將滿足條件的記錄查詢出來之外,還會將不滿足連線條件的記錄
--也查詢出來
--外連線分為(left outer join/right outer join/full outer join)
--1,左外連線:以join左側表作為驅動表(所有資料都會被查詢出來),那麼
--當該表中的某條記錄不滿足連線條件時來自右側表中的欄位,全部填上null
--2,右外連線:以join右側表作為驅動表(所有資料都會被查詢出來),那麼
--當該表中的某條記錄不滿足連線條件時來自左側表中de
select e.ename,d.dname,d.loc
from emp e left outer join dept d
on(e.deptno=d.deptno);
--注意:可用 + 簡寫左外連線和右外連線,但是全連線不可以這樣用
select e.ename,d.dname,d.loc
from emp e join dept d
on e.deptno=d.deptno(+);
--自連線
--自連線即:當前表的一條記錄可以對應當前表自己的多條記錄
--自連線時為了解決同類型資料但是又存在上下級關係的樹狀結構資料時使用;
select e.ename,d.ename
from emp e,emp d
where e.mgr=d.empno;
select * from emp;
--檢視每個員工以及其領導的名字
select y.ename,l.ename
from emp y,emp l
where y.mgr=l.empno
select y.ename,y.mgr,l.ename,l.empno
from emp y join emp l
on y.mgr = l.empno
--檢視 SMITH 的上司在那個城市工作
select distinct d.dname,d.loc
from emp y join emp l
on y.mgr=l.empno
join dept d
on l.deptno =d.deptno
where d.deptno=
(select f.deptno
from emp e,emp f
where e.mgr=f.empno
and e.ename='SMITH')
select d.dname,d.loc
from deptno d,emp y,emp l
where y.mgr=l.empno
and l.
--oracle 中的行號 -rownum 可將 rownum作為一個虛擬的欄位,直接查詢
select rownum,d.deptno,d.dname,d.loc from dept d;
select rownum,e.ename,m.ename,m.deptno,d.loc
from emp e join emp m
on e.mgr=m.empno
join dept d
on m.deptno=d.deptno
where e.ename='SMITH'
--n張表進行查詢,至少出現 n-1個連結條件
--子查詢,巢狀在其他查詢語句之中的,
--查詢工資大於CLARK的員工
select e.ename
from emp e
where e.sal>(select M.SAL from emp m where m.ename='CLARK' )
--查詢和CLARK同部門的員工
select e.ename
from emp e
where e.deptno=(select m.deptno from emp m where m.ename='CLARK')
--子查詢可以出現在 DDL和DML中
-- 在DDL中使用子查詢,可以根據子查詢的結果集建立一個表 用 AS
create table emp01
as (
select e.ename,e.deptno,d.dname,d.loc
from emp e join dept d
on e.deptno=d.deptno (+)
)
select * from emp01;
--建立表時若子查詢中的欄位有別名,如果有運算和函式,必須用別名,則會以別名命名欄位名
create table emp02
as (
select e.ename as name,e.sal*12 as yearsal ,e.deptno as deptnum,d.dname,d.loc
from emp e join dept d
on e.deptno=d.deptno (+)
)
select * from emp02;
--將CLARK所在部門的所有員工都刪除 DML中使用子查詢
delete from emp02 e
where e.deptnum =(select deptnum from emp02 m where m.name='CLARK')
--查詢工資大於平均工資的員工
select *
from emp e
where e.sal>(select avg(sal) from emp)
--查詢出部門中有SALESMAN但職位不是SALESMAN的員工資訊
--查詢出與SALEMAN同部門的其他職位的員工
select * from dept;
select * from emp;
--單行子查詢返回多個值 不用 = 用 in
select e.ename,e.deptno,e.job ,d.dname
from emp e join dept d
on e.deptno=d.deptno
where e.deptno in (select distinct e.deptno
from emp e
where e.job='SALESMAN')
and e.job<>'SALESMAN'
select *
from emp m
where m.deptno in
(select e.deptno
from emp e
where e.job='SALESMAN')
and m.job <>'SALESMAN'
--檢視職位比CLERK和SALESMAN工資都高得員工 !!!!!!!!!!!!!!
select a.sal
from
(select rownum,m.* from emp m
where m.sal >all
(select e.sal
from emp e
where E.job in ('CLERK','SALESMAN'))
order by m.sal desc) a
--EXISTS關鍵字!!!!!!!!!!!!!!
--exists後面跟一個子查詢,當該子查詢可以查詢出至少一條記錄時
--則exists表示式成立並返回true,返回成立的記錄
--TEST查詢有員工的部門
SELECT d.deptno, d.dname
FROM dept d
WHERE EXISTS (SELECT *
FROM emp e
WHERE e.deptno = d.deptno)
--TEST查詢沒有員工的部門 not exists
SELECT d.deptno, d.dname
FROM dept d
WHERE NOT EXISTS (SELECT *
FROM emp e
WHERE e.deptno = d.deptno)
--TEST 檢視每個部門的最低薪水是多少?前提是該部門的最低薪水高於30號部門的最低薪水
/*select m.sal ,d.dname
from emp m join dept d
on m.deptno=d.deptno
where m.sal>(
select min(e.sal)
from emp e
where e.deptno=30)
order by sal desc*/
SELECT MIN(e.sal) a, e.deptno
FROM emp e
GROUP BY e.deptno
HAVING MIN(e.sal) > (SELECT MIN(e.sal)
FROM emp e
WHERE e.deptno = 30)
--子查詢在FROM 中的使用
--當一個子查詢是多列子查詢,通常將該子查詢的結果集當作一個表
--看待,並基於它進行二次查詢
--TEST 檢視比自己所在部門平均工資高的員工!!!!!!!!!!!!!
SELECT AVG(sal) avgsal, e.deptno
FROM emp e
GROUP BY e.deptno
SELECT m.ename, m.deptno, m.sal
FROM emp m,
(SELECT AVG(sal) avgsal, e.deptno
FROM emp e
GROUP BY e.deptno) n
WHERE m.deptno = n.deptno
AND m.sal > n.avgsal
ORDER BY m.sal DESC
--子查詢在SELECT中出現,子查詢可以作為一個欄位形式出現
select e.ename,e.sal,e.job,
(select d.dname from dept d where e.deptno=d.deptno) deptname
from emp e
----分頁查詢 rownum
--分頁查詢時將查詢表中資料時分段查詢,而不是一次性的將所有資料查詢出來
--有時查詢的資料量非常龐大,這會導致系統資源消耗大,響應速度長,資料冗餘嚴重
--為此當遇到這種情況時一般使用分頁查詢解決,
--資料庫基本都支援分頁,但是不同資料庫語法不通,都是各自的方言
--ORACLE中的分頁是基於偽利ROWNUM實現的
--ROWNUM不存在任何一張表中,但是所有的表都可以查詢該欄位,該欄位的值都會i
--隨著查詢自動生成的,方式是:每當可以從表中查詢出一條記錄,該欄位的
--值幾位該條記錄的行號,從1開始,逐次遞增
select rownum ,a.*
from(select *
from emp e
order by sal desc) a
where rownum between 6 and 10
--檢視員工表中的第6-10行記錄 (要從結果集中再取出記錄)
SELECT *
FROM (SELECT rownum rn, empno, ename, sal, job
FROM emp)
WHERE rn BETWEEN 6 AND 10
--檢視工資排序後的第6-10行(注意要先排序,從裡面向外巴) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SELECT *
FROM (SELECT rownum rn, a.*
FROM (SELECT e.ename, e.deptno, e.sal
FROM emp e
ORDER BY sal) a)
WHERE rn BETWEEN 6 AND 10;
--注意:要點,先排好序,再加行號,再取範圍內的內容
--再注意:如果資料量過於龐大,要先取有意義的部分
select *
from( select rownum rn,a.*
from(select e.ename,e.job,e.sal
from emp e
order by sal desc) a
where rownum<=10)
where rn>=6
--
--計算區間公式
--pagesize:每頁顯示的條目數
--page:頁數
--star: (page-1)*pageSize + 1
--end: pageSize*page
--資料庫中的名字不可以重複
--DECODE 函式,可以實現 像 switch case
--最少三個值 DECODE(表示式1,值1,值2,值3,值4,值5)
--如果表示式1的值是值1,則返回值2,如果是值3則返回值4,其他返回值5,如果沒有值5,返回null
-- TEST根據職位不同,漲工資
select ename,job,sal,
decode(job,
'MANAGER',sal*1.2,
'ANALYST',sal*1.1,
'SALESMAN',sal*1.05,
sal
) bonus
from emp;
--DECODE函式基本語法相似的有 CASE 語句,實現類似於 if -else 的操作
--寫case 必須以 case開始,以end結束,中間用空格,不用逗號
select ename,job,sal,
case job when 'MANAGER' then sal*1.2
when 'ANALYST' then sal*1.1
when 'SALESMAN' then sal*1.05
else sal end
bonus
from emp;
--DECODE 在group by 分組中的應用可以將欄位值不同的記錄看作一組()
--統計人數,將職位是‘MANAGER','ANALYST' 看作一組,其餘職業看作另一組分別統計人數
SELECT COUNT(*) NUM, decode(job, 'MANAGER', 'VIP', 'ANALYST', 'VIP', 'OTHER') JOB1
FROM emp
GROUP BY decode(job, 'MANAGER', 'VIP', 'ANALYST', 'VIP', 'OTHER')
--DECODE 在排序中的靈活應用
--按欄位內容排序,DEPT表中按’POERATIONS'、'ACCOUNTING'、'SALES'
--排序而不按照原來的字面順序排序,注意:null比任何字元都大
select deptno,dname,loc, decode(
dname,'OPERATIONS',1,'ACCOUNTING',2,'SALES',3) a
from dept
order by decode(dname,'OPERATIONS',1,'ACCOUNTING',2,'SALES',3)
--排序函式 ROW_NUMBER() --組內排序
--同rownum一樣也是給結果集編號,但是它可以分組後排序,允許對
--結果集按照指定的欄位分組,在組內再按照指定的欄位排序,最終生成組內編號
--TEST檢視每個部門的工資排名?
select ename,sal,deptno,
ROW_NUMBER() over(
partition by deptno
order by sal desc) rank
from emp;
--Rank 函式,生成組內不連續也不唯一的數字
--同組內排序欄位值一樣的記錄,生成的數字也一樣
select ename,sal,deptno,
rank() over(
partition by deptno
order by sal desc) rank
from emp;
--Dense_Rank()函式,生成組內不唯一但連續的數字
select ename,sal,deptno,
dense_rank() over(
partition by deptno
order by sal desc) rank
from emp;
--高階分組函式
--建立一張表,插入1000條資料
create table sales_tab(
year_id number not null,
month_id number not null,
day_id number not null,
sales_values number(10,2) not null);
insert into sales_tab
select trunc(DBMS_RANDOM.value(2010,2012)) as year_id,
trunc(DBMS_RANDOM.value(1,13)) as month_id,
trunc(DBMS_RANDOM.value(1,32)) as day_id,
round(DBMS_RANDOM.value(1,100),2) as sales_value
from dual
connect by level <=1000;
select * from sales_tab;
--集合操作
--並集 union/union all 全集,有交叉重複的
--交集 intersect
--差集 minus
--TEST 並集
select ename,job,sal from emp
where job='MANAGER'
union
select ename,job,sal from emp
where sal>2500;
--全集有重複的
select ename,job, sal from emp
where job='MANAGER'
union all
select ename,job,sal from emp
where sal>2500;
--TEST 交集(共有部分,即使也是)
select ename,job,sal from emp
where job='MANAGER'
intersect
select ename,job, sal from emp
where sal>2500;
--TEST 差集(只在第一個結果集中存在,第二個結果集中不存在,即是結果集1減去結果集2的結果)
select ename,job,sal from emp
where job='MANAGER'
minus
select ename,job,sal from emp
where sal>=2500
--高階分組函式
--rollup 、cube 、grouping sets ,都是在group by 後面使用的
-- TEST 想要按著,年月日分組檢視營業額,並且先顯示在一條結果集中
select s.year_id,s.month_id,s.day_id,s.sales_values
from sales_tab s
order by s.year_id,s.month_id,s.day_id
--rollup():分組原則,引數逐次遞減,一直到所有引數都不要,每一種分組都
--統計一次結果,並且在一個結果集顯示。
--group by rollup (a,b,c)
--等價於下面的一坨
--group by a,b,c
--union all
--group by a,b
--union all
--group by a
--union all
--全表
--TEST檢視每天,每月,每年以及總共的營業額?
select year_id,month_id,day_id,
sum(sales_values)
from sales_tab
group by rollup(year_id,month_id,day_id)
--cube():每種組合分一次組
--分組次數:2 的引數個數次方
--group by cube(a,b,c)
--等價於
--abc
--ab
--ac
--bc
--a
--b
--c
--全表
--TEST
select year_id,month_id,day_id,
sum(sales_values)
from sales_tab
group by cube(year_id,month_id,day_id)
order by year_id,month_id,day_id
--grouping sets: 每個引數是一種分組方式,然後將這些分組統計並在一個結果集
--顯示,僅檢視每天與每月營業額?
select year_id,month_id,day_id,
sum(sales_values)
from sales_tab
group by
grouping sets(
(year_id,month_id,day_id), -- 精確到每天, 必須把一個分組用括號括起來
(year_id,month_id) -- 精確到每月
)
select s.year_id,s.month_id,s.day_id,
sum(s.sales_values)
from sales_tab s
group by
grouping sets(
(year_id,month_id,day_id),
(year_id,month_id)
)
order by s.year_id,s.month_id,s.day_id
--檢視
--檢視是資料庫物件之一
--所有資料庫物件名字不能重複,所以,檢視名字一般是以“v_"開頭
--檢視在sql語句中體現的角色與表相同
--但是檢視並不是一張真是存在的表,而只是對應一個select語句的查詢結果集
--並將其當作表看待而已
--使用檢視的目的是簡化SQL語句的複雜度
--重用子查詢,限制資料訪問
--建立檢視
--該檢視包含資料為10號部門的員工資訊
--注意:建立檢視時候如果提示沒有許可權,使用dba登陸後賦予scott使用者許可權,命令:grant create view to scott
create view v_emp_10
as
select *
from emp e
where e.deptno=10
--檢視檢視資料:
select * from v_emp_10
--修改檢視對應的SQL查詢語句
create or replace view v_emp_10 --建立或替換檢視v_emp_10
as
select empno id,ename name ,sal salary,deptno
from emp
where deptno=10;
--檢查檢視結構
desc v_emp_10;
--說明:檢視對應的子查詢中的欄位若含有函式或者表示式,
--那麼該欄位必須指定別名,當檢視對應的子查詢中的欄位使用了
--了別名,那麼檢視中該欄位就用別名來命名
--修改檢視
--由於檢視僅對應一個select語句,所以修改檢視,就是替換該
--select 語句而已
create or replace view v_emp_10
as
select empno id,ename name,
sal salary,deptno dep
from emp
where deptno=10
--檢視分為,簡單檢視,複雜檢視,連線檢視(基於多個表,也算複雜)
--檢視分為簡單檢視與複雜檢視
--簡單檢視:對應子查詢中不含油關聯查詢,查詢的欄位不包含函式,
--表示式等,沒有分組,沒有去重,反之則是複雜檢視
--對檢視進行DML操作
--僅能對簡單檢視進行DML操作,對檢視進行DML操作就是對檢視資料來源的基礎
--表進行的操作
--在檢視中插入的記錄實際是存在於原始表中的,插入時不可違反原表約束
insert into v_emp_10 (id,name,salary,dep)
values(1001,'JACK',2000,10)
select * from v_emp_10
select * from emp
--在檢視中修改記錄的值,會在原始表中進行更改
--對檢視的DML操作就是對基表的操作,那麼操作不當可能對基表進行資料汙染
update v_emp_10 set salary=3000 where name='JACK'
Commit
--對基表的汙染案例
--因為原檢視是隻查詢10號部門的員工資訊,如果插入20號部門的資訊,也會插入到
--基表中,但是檢視中查詢時看不到的,不可控的,所以汙染了基表
insert into v_emp_10 (id,name,salary,deptno)values
(1002,'BOSE',3000,20)
commit
--更新同樣存在更新後對資料不可控的情況
--如果將視圖裡面的部門號都改為20號部門,那麼,檢視中將不可見原來的資料
update v_emp_10 set deptno=20
rollback --回滾
--刪除非檢視中的資料,不會對基表進行刪除,
--但是刪除檢視中有的資料,真的會刪除基表中的資料
delete from v_emp_10 where deptno=20
--如何避免出現汙染的情況
--建立具有 with check option 約束,可避免基表汙染
--為檢視新增檢查選項,可以保證對對檢視的DML操作後檢視對其看見
--否則不允許進行該DML操作,這樣就避免了對基表進行資料汙染
create or replace view v_emp_10
as
select e.empno id ,e.ename name,e.sal salary,deptno
from emp e
where e.deptno=10
with check option
--如果再插入20號部門的員工,會提示報錯,如果要將檢視中
--10號部門的員工都改成20號部門,也會報錯,違規
--為檢視新增制度選項,那麼該檢視不允許進行DML操作
--with read only 只讀約束
create or replace view v_emp_10
as
select e.empno id,e.ename name,sal salary,deptno
from emp e
where e.deptno=10
with read only
--下面操作會報錯:無法對只讀檢視進行DML操作
update v_emp_10 set deptno=20
--資料字典:就是幾個特殊的表清單
--user_objects 資料庫中所有資料庫物件
--user_views 所有檢視
--user_tables 所有表
--user_update_columns
select object_name from user_objects u where
object_type='VIEW' or u.object_type='TABLE'
select table_name
from user_tables; --查看錶名在‘所有表’中
select u.text,u.view_name --檢視‘視圖表’中的內容
from user_views u
--複雜檢視,建立一個含有部門工資情況的檢視,內容為:部門編號
--部門名稱,部門的最高,最低,平均,以及工資總和資訊
create or replace view v_salary
as
select e.deptno,d.dname,max(e.sal) maxsal,min(e.sal) minsal,avg(e.sal) avgsal,sum(e.sal) sumsal
from emp e,dept d
where e.deptno=d.deptno
group by e.deptno,d.dname ---分組時,除了聚合函式的欄位,其他出現在select中的欄位都要出現在group by中
with read only
select * from v_salary
create or replace view v_dept_sal
as
select d.deptno,d.dname,
min(e.sal) min_sal,
max(e.sal) max_sal,
avg(e.sal) avg_sal,
sum(e.sal) sum_sal
from emp e join dept d
on e.deptno=d.deptno
group by d.deptno,d.dname
with read only
select * from v_dept_sal
--檢視誰比自己所在部門平均工資高?
select e.*
from emp e,v_dept_sal v
where e.deptno=v.deptno
and e.sal>v.avg_sal
--為什麼不能對複雜檢視進行DML操作,因為基表中沒有檢視中的欄位
--刪除檢視
--刪除檢視是不會對基表產生影響
--但是,刪除檢視中的資料會將基表中的資料也刪除掉!!!!!!!!!!!!!!
drop view v_salary
select * from v_salary --表或檢視不存在
rollback --刪除操作無法回滾
--序列 (注意:系列不會回退,用了就是用了!!!!!!!!!!)
--生成一系列數字
--序列也是資料庫物件之一,作用是生成一系列數字
--序列常用於為某張表的主鍵欄位提供值使用
--注意 --序列會在兩種情況下斷裂,1,多張表使用同一個序列,2,伺服器斷電,快取消失
create sequence seq_emp_id
start with 1 --從1開始
increment by 1 --步長值是1,
--預設快取是20
--序列支援兩個偽例
--nextval: 獲取序列下一個值
--若是新建立的序列,那麼第一次呼叫返回的是start with
--指定的值,以後每次呼叫都會得到當前序列值加上步長值後的數字
--nextval會導致序列發生步進,且序列不能回退
--currval:獲取序列當前值,即:最後一次呼叫nextval後得到的值,currval
--不會導致步進,但是新建立的序列至少呼叫一次nextval後才可以使用currval
--使用序列,沒執行查詢一次,步進一次
select seq_emp_id.nextval
from dual
--查詢序列當前值,不會產生步進
select seq_emp_id.currval
from dual
--TEST 在emp中插入記錄,使用序列遞增自動改變empno
--此時的 empno值為序列值的下一個值
--使用序列為EMP表中插入的資料提供
insert into emp(empno,ename,sal,job,deptno)
values
(seq_emp_id.nextval,'JACK',3000,'CLERK',10)
select * from
emp
--刪除序列
drop sequence seq_emp_id
--索引 (注意:索引要使用在資料量大、查詢頻繁的欄位中)
--資料庫內部自己維護,不用關心,索引是給表的某個欄位或某些欄位加的
--而不是給整個表加,索引就像是字典的目錄以及路標一樣,當資料改變,也是需要
--維護一下索引的
--給emp表中的ename欄位加索引
create index idx_emp_ename on emp(ename);
--查詢的時候不用關心怎麼用,只要建立過這個欄位的索引,就會自動顯現有時
select * from emp where ename='JACK'
--索引的統計與應用是資料庫自動完成的,只要資料庫認為可以使用某個
--已建立的索引時就會自動應用
--複合索引
create index idx_emp_job_sal on emp(job,sal);
--當做下面查詢時,會自動應用該索引(注意:job,sal 的順序要和索引一致)
select empno,ename,sal,job from emp
order by job,sal;
--基於函式的索引
create index emp_ename_upper_idx on emp(upper(ename));
select * from emp where upper(ename)='KING';
--修改和刪除索引
--修改索引
--如果經常在索引列上執行DML操作,需要定期重建索引,提高索引的空間liyonlv
--重建索引
alter index index_name rebuild;
--刪除索引 當一個表上有不合理的索引,會導致操作效能下降,刪除索引的語法
drop index index_name;
drop index idx_emp_ename;
--約束
--非空 約束,兩種建立方式
create table employees(
eid number(6),
name varchar(30) not null, --非空
salary number(7,2),
hiredate date constraint employees_hiredate_nn not null --非空 必須在一個欄位後面,不可單獨指定
);
--新增/修改表時新增非空約束
alter table employees modify (eid number(6) not null);
--取消非空約束脩改為可以有空值
alter table employees modify (eid number(6) null);
--唯一性約束 unique 同樣有兩種寫法
--除了null之外不能有重複值
--唯一性約束可以保證表中欄位的值任何一條記錄都不可以初伏,nullchuwai
create table employees(
eid number(6) unique,
name varchar(30) not null, --非空
salary number(7,2),
hiredate date constraint employees_hiredate_nn not null, --非空
constraint employees_email_uk unique(email) --可以單獨指定
);
--新增唯一性約束(在建表之後新增)
alter table employees
add constraint employes_ename_uk unique(name);
--如果原表中該欄位已經存在有重複的值,會報錯-找到重複關鍵字
--要將其找到清除才能正確新增唯一性約束
--主鍵約束
--一般每張表的第一個欄位是主鍵,命名為ID
--在建表時新增主鍵約束條件
create table employees2(
eid number(6) primary key,
name varchar2(30),
email varchar2(50),
salary number(7,2),
hiredate DATE
);
--如果重複插入該行記錄,會報錯‘違反唯一約束’
insert into employees2
(eid,name)
values
(2,'JACK');
--新增主鍵約束
alter table employees3
add constraint employees3_eid_pk primary key(eid);
--外來鍵約束
--oracle中一般不使用,很疼
--主表的外來鍵必須是附表的主鍵
--如果使用外來鍵約束,外來鍵必須參照主鍵,同時制約主鍵和外來鍵
--外來鍵裡面的值必須是主鍵中有的或者是null
--檢查約束
--限制欄位值的插入,修改
--如果有兩個check 檢查約束,必須同時滿足
--新增check檢查約束
alter table employees2
add constraint employees2_salary_check
check(salary>2000);
--正常插入資料
insert into employees2(eid,name,salary)
values(1236,'donna moble',2500);
select * from employees2
--修改有約束的記錄值為不滿足條件
update employees2 set salary=1300
where eid=1236 --報錯,違反檢查約束