1. 程式人生 > >oracle基礎知識,oracle sql練習

oracle基礎知識,oracle sql練習

本案例用的是oracle資料庫。

一、建表

--dept職位表
drop table dept_test; --刪除語句
create table dept_test(
deptno number(2) ,
dname char(20) ,
location char(20)) ;

insert into dept_test values(10 , 'developer' , 'beijing') ;
insert into dept_test values(20 , 'account' , 'shanghai') ;
insert into dept_test values(30 , 'sales'
, 'guangzhou') ;
insert into dept_test values(40 , 'operations' , 'tianjin') ; commit ; --事務控制語句 --emp員工表 drop table emp_test; create table emp_test( empno number(4) , ename varchar2(20) , job varchar2(15) , salary number(7 , 2) , bonus number(7 , 2) , hiredate date, mgr number(4) , deptno number(10) ) ;
insert into emp_test values(1001 , '張無忌' , 'Manager' ,10000 , 2000 , '12-MAR-10' , 1005 , 10) ; insert into emp_test values(1002 , '劉蒼松' , 'Analyst' ,8000 , 1000 , '01-APR-11' , 1001, 10) ; insert into emp_test values(1003 , '李翊' , 'Analyst' ,9000 , 1000 , '11-APR-10' , 1001, 10) ; insert into emp_test values(1004 , '郭芙蓉' , 'Programmer'
,5000 , null , '01-JAN-11' , 1001 , 10) ;
insert into emp_test values(1005 , '張三丰' , 'President' ,15000 , null , '15-MAY-08' , null , 20) ; insert into emp_test values(1006 , '燕小六' , 'Manager' ,5000 , 400 , '01-FEB-09' , 1005 , 20) ; insert into emp_test values(1007 , '陸無雙' , 'clerk' ,3000 , 500 , '01-FEB-09' , 1006 , 20) ; insert into emp_test values(1008 , '黃蓉' , 'Manager' ,5000 , 500 , '1-MAY-09' , 1005 , 30) ; insert into emp_test values(1009 , '韋小寶' , 'salesman' ,4000 , null , '20-FEB-09' , 1008 , 30) ; insert into emp_test values(1010 , '郭靖' , 'salesman' ,4500 , 500 , '10-MAY-09' , 1008 , 30) ; commit ; --事務控制語句

二、練習sql(由淺入深)

1、計算員工的月收入?(包括工資和獎金)
錯誤寫法:select ename , salary , bonus , salary+bonus month_sal from emp_test ;
關於空值:空值和任何資料做算數運算 , 結果都是 null;空值和字串型別做連線操作 , 結果相當與空值不存在。
正確寫法:select ename, salary , bonus , salary + nvl(bonus, 0) month_sal from emp_test ;

2、distinct 關鍵字的使用
distinct 必須( 只能 )跟在 select 後邊
機構中有多少種職位?
select distinct job from emp_test ;
查詢每個部門不重複的職位?
select distinct deptno, job from emp_test ;

3、模糊匹配
如果要查詢的資料中有特殊字元( 比如_或% ),在做模糊查詢時,需要加上\符號表示轉義 , 並且用 escape 短語指明轉義字元\

列出職位中第二個字元是 a 的員工資料?
select * from emp_test where job like ‘_a%’ ;
查詢資料庫中有多少個名字中以 ‘S_’ 開頭的表?
select count(*) from user_tables where table_name like ‘S/_%’ escape ‘/’ ;
查詢資料庫中名字帶‘%’的資料?
select * from user_tables where table_name like ‘%/%%’ escape ‘/’

下面練習一些常用函式

4、nvl(d1 , d2)
如果 d1 為 null 則用 d2 替代
計算總月收入多少
select ename, salary , bonus , salary + nvl(bonus, 0) month_sal from emp_test ;
mysql中空值處理:mysql中沒有nvl(expr1,expr2)函式,但是有下面兩個:
ifNull(expr1,expr2):如果expr1不為空則結果為expr1,如果expr1為空則結果為expr2;
if(expr1,expr2,expr3):如果expr1為true,則結果為expr2,如果expr1為false則結果為expr3;

5、字元函式
substr/ upper / lower / initcap/length / lpad / rpad / replace / trim

6、數字函式
round( 數字 , 小數點後的位數 ):用於數字的四捨五入
trunc( 數字 , 小數點後的位數 ):用於擷取(mysql沒有該函式)
ceil(n) 取大於等於數值n的最小整數;
floor(n)取小於等於數值n的最大整數

7、日期函式
months_between 兩個日期之間的月份數
add_months 給定一個日期 , 為該日期增加指定月份
last_day 找出引數時間點所在月份的最後一天

select sysdate from dual ; –dual 為虛表,獲取系統當前時間
計算員工入職多少天?
select ename , hiredate , round( sysdate - hiredate ) days from emp_test ;–日期資料相減 , 得到兩個日期之間的天數差 , 不足一天用小數表示。可以用 round 函式處理一下
計算員工入職多少個月?
select ename , hiredate ,round( months_between( sysdate , hiredate ) ) months from emp_test ;
計算 12 個月之前的時間點
select add_months(sysdate, -12) from dual;
計算本月的最後一天
select last_day(sysdate) from dual;

8、轉換函式
to_char(日期資料 , 格式): 將日期資料 按指定格式 轉換為 字串資料
select to_char( sysdate , ‘yyyy-mm-dd hh24:mi:ss ‘) from dual ;
to_date(日期資料 , 格式):將字串資料 按指定格式 轉換為 日期資料
insert into emp_test( empno , ename , hiredate ) values( 1012 , ‘amy ’ ,to_date( ‘2011-10-10 ’ , ‘yyyy-mm-dd ’ ) ) ;
to_number(數字,格式):將字串轉換成數字格式
select to_number(‘7,912,345.67,9,999,999.99’) from dual ;–輸出7912345.7

mysql中使用 CAST(xxx AS 型別) 該函式進行轉換,日期轉字串格式用DATE_FORMAT函式。

9、case 語句
相當於 Java 中的 switch-case 語句

根據員工的職位 , 計算加薪後的薪水資料
要求:
1) 如果職位是 Analyst:加薪 10%
2) 如果職位是 Programmer:加薪 5%
3) 如果職位是 clerk:加薪 2%
4) 其他職位:薪水不變

select ename , salary , job ,
        case job when 'Analyst' then salary * 1.1 --注意這裡沒有“ , ”
                 when 'Programmer' then salary * 1.05
                 when 'clerk' then salary * 1.02
                else salary        --else 相當於 Java 中 case 語句的 default
        end new_salary     --endcase 語句的結束標識
from emp_test ;    --new_salary是從case開始到end結束這部分的別名

10、decode 函式
decode()函式是Oracle 中等價於 case when 語句的函式 , 作用同 case 語句相同。
decode 函式語法如下:
decode(判斷條件 , 匹配 1 , 值 1 , 匹配 2 , 值 2 , … , 預設值)
表達的意思是:如果判斷條件 = 匹配 1 , 則返回值 1
判斷條件 = 匹配 2 , 則返回值 2

select ename , salary , job ,
    decode( job , 'Analyst' , salary * 1.1 ,
                 'Programmer' , salary * 1.05 ,
                 'clerk' , salary * 1.02 ,
                salary) as new_salary
from emp_test ;

11、查詢結果排序 order by
asc:升序;
desc:降序;
按部門排序 , 同一部門按薪水由高到低排序
select ename , deptno , salary from emp_test order by deptno , salary desc ;

下面練習常用組函式

12、count(*)
注意:count 函式忽略空值,所以用conut(*)比具體某個可能存在空值的資料更能精確總資料

13、avg() sum() max() min()
計算員工的人數總和、薪水總和、平均薪水是多少?
錯誤寫法:select count(*) num , sum(salary) sum_sal , avg(salary) avg_sal from emp_test ;
原因:薪水平均值 = 薪水總和 / 人數總和 avg(salary) = sum(salary) / count(*),而 avg(salary)叧按有薪水的員工人數計算平均值。這樣得到的資料不夠準確。
正確寫法:select count(*) num , sum(salary) sum_sal ,avg(nvl(salary , 0)) avg_sal from emp_test ;

注意:
組函式:count / avg / sum / max / min 如果函式中寫列名 , 預設忽略空值
avg / sum 針對數字的操作
max / min 對所有資料型別都可以操作

計算最早和最晚的員工入職時間
select max(hiredate) max_hiredate , min(hiredate) min_hiredate from emp_test ;

14、分組查詢 group by
按部門計算每個部門的最高、最低薪水、薪水總和、平均薪水、總人數分別是多少?
select deptno , max(salary) max_s , min(salary) min_s , sum(salary) sum_s , avg(nvl(salary,0)) avg_s, count(*) emp_num
from emp_test group by deptno ;
按職位分組 , 每個職位的最高、最低薪水和人數?
select job , max(salary) max_s ,min(salary) min_s ,count(*) emp_num
from emp_test group by job order by emp_num ;

注意:select 後出現的列 , 凡是沒有被組函式包圍的列 , 必須出現在 group by 短語中。mysql沒有此限制,但是那樣的sql畢竟不規範。

15、having 子句
having 子句用於對分組後的資料進行過濾。
注意區別 where 是對錶中資料的過濾 ;having 是對分組得到的結果資料進一步過濾

平均薪水大於 5000 元的部門資料 , 沒有部門的不算在內?

select deptno , avg(nvl(salary , 0)) avg_s
from emp_test
where deptno is not null
group by deptno
having avg(nvl(salary , 0)) > 5000 ;

薪水總和大於 20000 元的部門資料?

select deptno , sum(salary) sum_s
from emp_test
where deptno is not null
group by deptno
having sum(salary) > 20000 ;

哪些職位的人數超過 2 個人?

select job , count(*) emp_num
from emp_test
where job is not null
group by job
having count(*) > 2
order by emp_num ;--注意:order by 一定要放到最後

16、總結下
使用頻率比較高的函式 *
1) 單行函式:substr / upper / round / to_char / to_date / nvl
2) 組函式:count / avg / sum / max / min

查詢語句的基本格式:
select 欄位 1 , 欄位 2 , 欄位 3 , 表示式 , 函式 , …
from 表名
where 條件
group by 列名
having 帶組函式的條件
order by 列名
其執行順序為:select–>from–where–group by–>having–>order by

下面開始練習多表查詢

17、子查詢

17-1、單行比較運算子 > < >= <= = <>

單行比較運算子都只能和一個值比較

查詢最高薪水的是誰?
select ename from emp_test
where salary = ( select max(salary) from emp_test) ;
研發部有哪些職位?
select distinct job from emp_test
where deptno = ( select deptno
from dept_test
where dname = ‘developer’ ) ;

17-2、多行運算子 >ALL >ANY <ALL <ANY in
誰的薪水比張無忌高?
錯誤寫法:select enmae from emp_test where salary > (select salary from emp_test where ename='張無忌');
錯誤理由:如果有多個叫張無忌的人將會報錯,單行子查詢返回多個行
正確寫法:

select ename from emp_test
where salary > ALL( select salary from emp_test
where ename = '張無忌' ) ;--查詢誰的薪水比所有叫張無忌的薪水都高,把all改成any也行

誰和劉蒼松同部門?列出除了劉蒼松之外的員工名字

select ename,salary,job
from emp_test
where deptno = (select deptno from emp_test
where ename = '劉蒼松')
and ename <> '劉蒼松' ;

誰和劉蒼松同部門?列出除了劉蒼松之外的員工名字( 如果子查詢得到的結果是多個 )

select ename,salary,job,deptno
from emp_test
where deptno in ( select deptno from emp_test
where ename = '劉蒼松' )
and ename <> '劉蒼松' ;

每個部門拿最高薪水的是誰?

select ename, salary, job, deptno
from emp_test
where (deptno, salary) in ( select deptno, max(salary)
from emp_test
where deptno is not null
group by deptno ) ;

注意:子查詢的條件是單列還是多列沒關係 , 關鍵是要分清返回的是單行還是多行。

17-3、子查詢出現在 having 短語中

哪個部門的人數比部門 號30 的人數多?

select deptno , count(*)
from emp_test
group by deptno
having count(*) > ( select count(*) from emp_test
where deptno = 30 ) ;

列出員工名字和職位 , 這些員工所在的部門平均薪水大於 5000 元

select ename, job
from emp_test
where deptno in (select deptno
from emp_test
group by deptno
having avg( nvl(salary,0)) > 5000 ) ;

18、關聯子查詢

18-1、子查詢中不再是獨立的 Sql 語句 , 需要依賴主查詢傳來的引數 , 這種方式叫關聯子查詢

哪些員工的薪水比本部門的平均薪水低?

select ename, salary, deptno
from emp_test a
where salary < ( select avg(nvl(salary,0))
from emp_test
where deptno = a.deptno ) ;

18-2、Exists關鍵字和in

介紹一下existis和in:
exists 關鍵字判斷子查詢有沒有資料返回 , 有則為 ture , 沒有則為 false,它不關心子查詢的結果 , 所以子查詢中 select 後面寫什麼都可以,如本例中我寫常量“1”;
in是把外表和內表作hash 連線,而exists 是對外表作loop 迴圈,每次loop 迴圈再對內表進行查詢,所以如果兩個表中一個較小,一個是大表,則子查詢表大的用exists,子查詢表小的用in:
如果查詢語句使用了not in 那麼內外表都進行全表掃描,沒有用到索引,而not extsts 的子查詢依然能用到表上的索引,所以無論那個表大,用not exists 都比not in 要快。

哪些人是其他人的經理?

select ename from emp_test a
where exists (select 1 from emp_test
where mgr = a.empno) ;--使用了關聯子查詢
select ename from emp_test
where empno in ( select distinct mgr
from emp_test) ;--使用普通子查詢

哪些人不是別人的經理?

select ename from emp_test a
where not exists (select 1 from emp_test
where mgr = a.empno) ;--關聯子查詢
select ename from emp_xx
where empno not in ( select distinct mgr
from emp_test
where mgr is not null) ;--普通子查詢

**注意:**not in (列表):如果列表中有 null 值 , 將沒有結果返回 ;in(列表)沒有關係。
哪些部門沒有員工?

select deptno, dname from dept_test d
where not exists (select 1
from emp_test
where deptno = d.deptno) ;

19、集合操作

兩個結果集必須結構相同:當列的個數、列的順序、列的資料型別一致時 , 我們稱這兩個結果集結構相同
只有結構相同的結果集才能做集合操作
集合型別:
合集:union 和 union all
union 去掉重複記錄 , union all 不去重
union 排序 , union all 不排序
交集:intersect
差集:minus(兩個集合做減法)

select ename , salary from emp_test
where deptno = 10
union
select ename , salary from emp_test
where salary > 6000 ;

下面開始練習表間關聯查詢

表 emp_test 和表 dept_test 之間存在的參照關係:
1) emp_test 的所在部門( deptno )參照 dept_test 的部門編碼( deptno )
2) dept_test 是主表( 父表 ) , emp_test 是從表( 子表 )
表 emp_test 自身存在一種參照關係:
員工的經理( mgr )列參照職員編碼( empno )列

20、內連線

語法:表 1 join 表 2 on 條件
1) 表 1 叫做驅動表 , 表 2 叫做匹配表
3) 執行方式:遍歷驅動表 , 在匹配表中查詢匹配資料

列出員工的姓名和所在部門的名字和城市
select ename , dname , location
from emp_test e join dept_test d
on e.deptno = d.deptno ;
通過檢視結果集 , 我們可以得出結論:
1) 子表( emp_test )中的外來鍵值( deptno )為 null 的資料不包含在結果集中;
2) 父表( dept_test )中主鍵值( deptno )沒有被參照的資料不包含在結果集中;

列出員工的姓名和他的上司的姓名( 自連線 )
select t1.ename , t2.ename
from emp_test t1 join emp_test t2
on t1.mgr = t2.empno ;
–t1 表示從表 , t2 表示主表
– 沒有上司的員工不會列出

21、外連線

1) 左外連線語法結構: 表 1 left (outer) join 表 2 on 條件
2) 右外連線語法結構: 表 1 right (outer) join 表 2 on 條件
3) 外連線的特徵:
 如果驅動表在匹配表中找不到匹配記錄 , 則匹配一行空行
 外連線的結果集 = 內連線的結果集 + 驅動表在匹配表中匹配不上的記錄和空值
 外連線的本質是驅動表中的資料一個都不能少
 left join 以左邊的表為驅動表
 right join 以右邊的表為驅動表

列出員工的姓名和他所在部門的名字 , 把沒有部門的員工也查出來
select e.empno , ename , d.deptno , d.dname , d.location
from emp_test e left join dept_test d
on e.deptno = d.deptno ;

on後面可以接等值連線,也可以非等值連線( on 後面的條件不是等值操作 )。非等值連線指在多個表間使用非等號連線 , 查詢在多個表間有非等值關係的資料 , 非等值連線操
作符包括:>、<、<>、>=、<=以及 Between And、like、in 等。

22、full outer join 全外連線

1) 全外連線可以把兩個表中的記錄全部查出來
2) 全外連線的結果集 = 內連線的結果集 +
驅動表中在匹配表中找不到匹配記錄的資料和 null 值 +
匹配表中在驅動表中找不到匹配記錄的資料和 null 值
3) 驅動表和匹配表可以互換

23、複製表
語法:
create table 表名 as 查詢語句

23、rowid 關鍵字
1) rowid 是 Oracle 資料庫的偽列 , 可以看作是一條資料在資料庫中的物理位置
2) rowid 是 Oracle 資料庫獨有的
注意:每一條記錄的 rowid 在資料庫中都是唯一的
刪除重複資料:
delete from emp_bak1
where rowid not in ( select max(rowid) from emp_bak1
group by empno , ename , salary ) ;
也可以distinct全部欄位(除id)查詢出所有的不重複資料;

24、rownum 關鍵字
rownum 是 Oracle 資料庫提供的 , 代表行號。

--查詢前8條資料
select * from emp_test where rownum <= 8;
--查詢第10到第15條資料
select * from (select *,rownum as num from emp_test)
where num between 10 and 15;

--rownum不支援以下方式的查詢:
select * from emp_test where rownum <=2;
select * from emp_test where rownum>10 and rownum <15;

25、alter( 修改表結構 )

alter table mytemp_test add(name char(10));    --add  表增加欄位
alter table mytemp_test rename column password to pwd;   --rename  欄位重新命名
alter table mytemp_test modify (pwd char(8));  --modify  修改欄位型別
alter table mytemp_test drop column pwd; -- drop 刪除列

26、約束條件
26-1、主鍵約束
列級約束:deptno number(2) primary key,
表級約束:constraint dept_ning2_deptno_pk primary key (deptno)
26-2、非空約束( not null , 簡稱 NN )
name varchar2(10) not null,

唯一約束( Unique , 簡稱 UK )
email varchar2(30) unique,

檢查約束( Check , 簡稱 CK )
gender char(1) check(gender in(‘F’, ‘M’) )–‘F’代表女生 ;’M’代表男生

外來鍵( Foreign key, 簡稱 FK )

全部在表級定義:

constraint student_ning3_id_pk primary key(id),
constraint student_ning3_email_uk unique(email),
constraint student_ning3_age_ck check(age > 10),
constraint student_ning3_gender_ck check(gender in('F', 'M', 'f', 'm'))

27、檢視 View
1) 檢視的使用和表相同
2) 檢視的好處:簡化查詢 ;隱藏資料表的列
3) 檢視不包含任何資料。是基表資料的投影

28、索引 Index
如果資料表有 PK/Unique 兩種約束 , 索引自動建立 , 除此以外 , 索引必須手動建立
自定義索引語法:
create index 索引名 on 表名(列名) ;

29、序列 Sequence
序列的特性:產生連續的不同的數字值用來作為資料表的主鍵,序列是資料庫中的獨立物件。
建議:一個序列為一個表產生主鍵
序列這種物件在 Oracle、db2 等資料庫中有 , 在 mysql、sql server 中沒有。

– 產生從 1 開始的數字值 , 步進是 1
create sequence myseq_ning ;
– 檢視序列產生的值
select myseq_ning.nextval from dual ;
– 使用序列產生的值作為表的主鍵值
insert into student_ning7(id,name) values(myseq_ning.nextval , ‘amy’) ;
select * from sutdent_ning7 ;
– 顯示結果為 2 amy
– 注意: 每呼叫一次 myseq_ning.nextval 就會獲得 1 個遞增的數

28、oracle與mysql的區別:
1、欄位型別上
數字型別oracl用number,mysql用int,如果小數oracle用number(4,2)這種形式,mysql用decimal(4,2);
字串oracle用varchar2(20),mysql用varchar(20),mysql沒有varchar2型別;
具體:
數值型別:
oracle:NUMBER/NUMBER( p,s )
mysql:INT或INTEGER/TINYINT/SMALLINT/MEDIUMINT/BIGINT/FLOAT/DOUBLE/DECIMAL
字元型別:
oracle:CHAR/VARCHAR2/VARCHAR
mysql:CHAR/VARCHAR/TEXT/BLOB/LONGBLOB/LONGTEXT
日期型別:
oracle:DATE/TIMESTAMP/
mysql:DATE/TIME/DATETIME/TIMESTAMP/YEAR

2、個別常用函式上
mysql字元拼接用concat函式,oracle用 ||
在時間格式化方面也有區別,oracle用to_char,mysql用DATE_FORMAT

3、分頁上
mysql用limit,oracle用rownum;

4、主鍵增長上
mysql可以讓主鍵自動增長(auto increment),但是oracle需要建立序列,然後在增加資料的時候把序列帶進去;