馬果老師整理
oracle數據庫中,主要包含6種類型的運算符
- 賦值運算符 =
- 連接運算符 ||
- 算術運算符 + - * /
- 邏輯運算符 or and
- 關係運算符 > >= < <= = != <> in not in between
- 聯合運算符 union union all intersect
賦值運算符 =
- update 表 set 字段=值
連接運算符 ||
作用:通過||可以把指定內容,拼接成一個字符串
- select name||'的成績是'||score 信息 from inf;
算術運算符 + - * /
- update 表 set 字段值=字段值+10
- select name,score-20 from inf;
邏輯運算符 or and
OR:或者
- select * from info2 where class='s1t80' or class='s1t82'
and:並且
- select * from info2 where class='s1t80' and gender='男';
關係運算符 > >= < <= = != <> in not in between
select * from info2 where score>=90;
select * from info2 where class!='s1t80';
select * from info2 where class<>'s1t80';
select * from info2 where class in('s1t80','s1t82');
select * from info2 where class not in('s1t80','s1t82');
select * from info2 where score between 90 and 100
問題1: -- select * from info2 where score between 100 and 90
- 這樣,查詢,是沒有結果的,區間查詢時,小的值要在前,大的值要在後
問題2:--日期類型的數據可不可進行區間查詢?
- select * from info2 where bir between date'1985-01-01' and date'1990-12-31';
- 日期類型的數據,可以進行區間查詢
聯合運算符 union union all intersect
union:聯合兩張表的數據,兩張表相同部份的數據,只顯示1次,不同的部份,則分別顯示
select * from one
union
select * from two;
union all:聯合兩張表的數據,先顯示第一張表的全部數據,然後再顯示第二張表的全部數據,不論數據是否相同,都會顯示
select * from one
union all
select * from two;
intersect:顯示兩張表的交集(只顯示兩張表都有的數據)
select * from one
intersect
select * from two;
模糊查詢
- %: 通配任意長度的任意字符
- _: 通配一個任意字符
select * from info2 where name like '%柳%'
select * from info2 where name like '柳%'
select * from info2 where name like '柳_'
範圍查詢
select * from info2 where score between 60 and 100;
select * from info2 where score >=60 and score<=100;
select * from info2 where class in('s1t80','s1t81');
select * from info2 where class not in('s1t80','s1t81');
分組查詢 group by
select class 班級名稱 from info2 group by class; --分組查詢
select class 班級名稱, count(*) 人數 from info2 group by class; --先分組再聚合
要求,查詢班級人數爲5人,或者是5人以上的班級,並且按人數從多至少排序
- 在分組以後,要設置查詢條件,使用having
- select class 班級名稱, count(*) 人數 from info2 group by class having count(*)>=5 order by count(*) desc;
聚合查詢 (數據庫中有幾個聚合函數)
- sum:總和
- count:個數
- avg:平均值
- max:最大值
- min:最小值
如果查詢語句中,同時包含: order by , group by ,having ,where
它們出現的正常順序應該是:select ......from 表 where .....group by ....having....order by
oracle中的多表連接 (重點)
在實際工作中,不論任何操作,都是對數據庫執行:增刪改查。其中,最爲繁的就是:查詢
在實際開發過程中,多表聯合查詢很常見:
oracle多表連接查詢的方式有:
自連接:natural join
內連接:inner join
外連接:
- left outer join 左外連接
- right outer join 右外連接
- full outer join 完全外連接
子查詢
自連接: natural join
特點:
- 兩張表如果要進行自連接,前提條件是,兩張表中,一定要有相同的字段名,纔可以建立關聯
- 如果進行自連接,兩張表無需設置關聯條件
- 如果兩張表中,沒有相同的字段名,也在採用自連接,將會產生: 迪卡爾積
學生表
drop table stu;
create table stu
(
stuId number(11) primary key,--學生編號
stuName varchar2(20) --學生名稱
)
insert into stu values(1,'張三');
insert into stu values(2,'李四');
insert into stu values(3,'王五');
成績表
create table score
(
sid number(11) primary key,--成績編號
stuId number(11),--哪一個學生的成績
score number(11) --分數
)
insert into score values(1,1,90);
insert into score values(2,3,78);
自連接
- select * from stu natural join score;
內連接 inner join
特點:
- 內連接的兩張表,不需要有相同的字段名,只要設置關聯條件即可
- 兩張表進行內連接,至少要設置一個關聯條件。N張表進行內連接,至少要設置N-1個關聯條件
- 內連接的兩張表是平級關係,必須兩張表都存在的數據,纔可以建立關係
內連接的標準語法:
採用inner join連接兩張表,採用on設置關聯條件
- select a.stuid,a.stuName,b.score from stu a inner join score b on(a.stuId=b.stuId);
內連接的另一種寫法:
採用where設置連接條件 ,可以省略inner join關鍵字
- select a.stuid,a.stuName,b.score from stu a,score b where a.stuid=b.stuid;
只要會3張的內連接,再多表的內連接,原理一樣
********************三張表的內連接
create table stu
(
stuId number(11) primary key,--學生編號
stuName varchar2(20) --學生名稱
)
insert into stu values(1,'張三');
insert into stu values(2,'李四');
insert into stu values(3,'王五');
--課程表
create table course
(
cid number(11) primary key,--課程編號
cname varchar2(20)--課程名稱
)
insert into course values(1,'語文');
insert into course values(2,'數學');
insert into course values(3,'英語');
--成績表
drop table score;
create table score
(
sid number(11) primary key,--成績編號
stuId number(11),--哪一個學生的成績
cid number(11),--哪一門課程
score number(11) --分數
)
insert into score values(1,1,3,90);
insert into score values(2,3,1,75);
select a.stuid 學生編號,a.stuName 學生名稱,b.cname 課程名稱,c.score 分數 from stu a,course b,score c where a.stuid=c.stuid and b.cid=c.cid;
外連接 (包含三種類型的外連接)
特點:
- 外連接的兩張表,分爲主表與副表,主表的數據必須全部顯示,副表的數據只有對應上主表纔可以顯示
左外連接 left outer join
--連接符左側的表爲主表,右側爲副表
右外連接 right out join
--連接符右側的表爲主表,左側爲副表
完全外連接 full outer join
內連接與外連接的區別是什麼(面試題)?
- 內連接的兩張表是平級關係,必須兩張表都存在的數據,纔可以建立關係
- 外連接的兩張表,分爲主表與副表,主表的數據必須全部顯示,副表的數據只有對應上主表纔可以顯示
左外連接(右外連接原理一樣)
顯示所有參加考試的學生,及成績 (左外連接)
- select a.stuid,a.stuname,b.score from stu a left outer join score b on(a.stuid=b.stuid);
左外連接的簡化寫法
- select a.stuid,a.stuname,b.score from stu a,score b where a.stuid=b.stuid(+);
注意:有+號的是副表,沒有+的是主表
--右外連接
- select a.stuid,a.stuname,b.score from stu a right outer join score b on(a.stuid=b.stuid);
--右外連接的簡化寫法
- select a.stuid,a.stuname,b.score from stu a,score b where a.stuid(+)=b.stuid;
完全外連接:full outer join
- 表示:連接的兩張表,都是主表,所有數據都要顯示
- select a.stuid,a.stuname,b.score from stu a full outer join score b on(a.stuid=b.stuid);
總結
左外連接
select ...from 表1 left outer join 表2 on(表1.字段=表2.字段);
select ...from 表1,表2 where 表1.字段=表2.字段(+);
右外連接
select ...from 表1 right outer join 表2 on(表1.字段=表2.字段);
select ...from 表1,表2 where 表1.字段(+)=表2.字段;
完全外連接
select ...from 表1 full outer join 表2 on(表1.字段=表2.字段);
子查詢:
問題1:什麼叫子查詢?
- 在一條查詢語句中,包含多個select子句,這樣的查詢語句,就稱爲:子查詢語句
問題2:子查詢語句,可以出現在查詢語句中的什麼位置?
子查詢語句,可以出現在查詢語句中任何位置
- 可以將查詢的結果作爲要顯示的字段
- 可以將查詢的結果作爲條件
- 可以將查詢的結果作爲表來繼續查詢
select (select * from 表) from 表;---------------把子查詢的結果,作爲要顯示的字段
select * from 表 where 字段 in(select * from 表)---------把子查詢的結果,作爲條件過濾
select * from (select * from 表 ) ---------------把子查詢的結果,當作爲表來繼續查詢
查詢沒有參加考試的學生,把子查詢的結果,作爲條件過濾
- select * from stu where stuid not in (select stuid from score)
問題:在執行子查詢時,先執行括號內的語句?還是先執行括號外的語句
- 先執行括號內的語句,再執行括號外的語句
oracle中的分頁
把子結果,當前數據表,來繼續查詢
例如:oracle中的分頁
注意:在oracle中執行分頁,需要使用rownum(僞列),配合子查詢語句使用
查詢前3條數據
- select f.*,rownum r from info2 f where rownum<=3;
假設,當前每1頁顯示3條數據,當前是第1頁
- select f.*,rownum r from info2 f where rownum<=3;
假設,當前每1頁顯示3條數據,當前是第2頁
- 找到前6條數據:select f.*,rownum r from info2 f where rownum<=6
- 排除第1頁,已經顯示過的3個僞列:select * from (select f.*,rownum r from info2 f where rownum<=12) k where k.r>9
分頁語法:
select * from (select f.*,rownum r from info2 f where rownum<=當前頁*每頁顯示條數據) k where k.r>(當前頁-1)*每一頁顯示的條數據
按學生的成績顯示,查詢分數最高的前三名,oracle是先查詢,再生成僞列,再排序
- select * from (select f.* from info2 f order by score desc) k where rownum<=3;
按學生的成績顯示,查詢分數最高的4-6名
- select * from (select rownum r,k.* from (select f.* from info2 f order by score desc) k where rownum<=6) t where t.r>3;
oracle中的函數,主要有下面幾種類型:
- 日期函數
- 字符函數
- 數學函數
- 轉換函數
- 分析函數
- 聚合函數(avg,sum,count,max,min)
- 分組函數(group by)
- 排序函數(order by)
在講解函數之前,看一下,oracle中一張特殊的表 dual
- dual:虛表-------------這張表本身並不存在,它的意義是爲了保證語法的完整
日期函數:
sysdate---獲得系統時間
- select sysdate from dual; --系統函數可以基於虛表查詢,也可以基於任何一張表查詢
add_months
作用:在指定日期上,加上一個指定的月份,產生一個新的日期
- select sysdate 生產日期,add_months(sysdate,6) 過期日期 from dual;
- select add_months(date'2019-01-15',6) from dual;
months_between
作用:計算兩個日期之間,間隔的月份
注意:在實際開發中,數據表中絕對不會有年齡字段 (年齡一般是根據出生日期自動進行計算)
- select months_between(date'2020-06-15',date'2019-06-15')/12 年 from dual;
- select floor(months_between(sysdate,date'2019-06-15')/12) 年 from dual;
floor(浮點數):得到一個小於當前浮點數的最大整數
- select name,bir,floor(months_between(sysdate,bir)/12) 年齡 from info2;
- select * from info2;
last_day
作用:得到指定日期這一個月的最後一天是哪一個日期
- select last_day(date'2020-02-01') from dual;
next_day
作用,得到從指定日期開始,下一個星期幾是哪一個日期
注意:在日期格式中的星期:
- 1--------------代表星期天
- 2--------------代表星期一
- 7--------------代表星期六
- select next_day(sysdate,2) from dual;
trunc
作用:截斷日期格式,去掉時分秒,只保留年月日
- select trunc(sysdate) from dual;
extract
作用:獲得一個日期格式中,指定部份的值
- select extract(year from sysdate) from dual; --獲得年份
- select extract(month from sysdate) from dual; --獲得月份
- select extract(day from sysdate) from dual; --獲得天
字符函數
length() ----獲得字符串的長度(空格也要計算長度)
select length('abc ') from dual;
select length('中國') from dual; --在計算長度時,只要是一個字符,就只算一個長度
select name,length(name) from info2;
ltrim,rtrim,trim
- ltrim()---去掉字符串左側的空格
- rtrim()---去掉字符串右側的空格
- trim()----去掉字符串兩邊的空格(不能去掉中間的空格)
select ltrim(' abc') from dual;
upper(),lower()
- upper()----------將小寫字母轉換成大寫字母
- lower()----------將大寫字母轉換成小寫字母
select upper('abcABC') from dual;
select lower('abcABC') from dual;
substr()
- 作用:截斷字符串
substr(字符內容,開始位置,截取長度);
select substr('你好,李小龍!',4,3) from dual;
select substr('18627198028',4,5) from dual;
replace()
- 作用:將字符內容中的指定內容,用新的內容進行替換
replace(字符內容,指定字符,新字符);
select replace('你好,張三丰','張三丰','李小龍') from dual;
lpad(),rpad()
- lpad():從字符內容中,截取指定長度的內容,如果內容的長度不夠,就左至右填充指定的符號
select lpad('abc12345def',5,'*') from dual; --abc12
select lpad('ab',5,'*') from dual; -- ***ab
- rpad():從字符內容中,截取指定長度的內容,如果內容的長度不夠,就右至左填充指定的符號
select rpad('abc12345def',5,'*') from dual; --abc12
select rpad('ab',5,'*') from dual; -- ab***
create table inf3
(
id number(11) primary key,
name varchar2(20),
tel varchar2(20)
)
--1、顯示姓名五個字符或以上,電話號碼以13開始的學生信息
select * from inf3 where tel like '13%' and length(name)>=5;
--2、顯示姓名中任意位置包含c的學生信息,並且電話號碼中間五位用*號替換
select name,tel,replace(tel,substr(tel,4,5),'*****') from inf3 where name like '%c%';
--3、顯示所有學生信息,姓名只顯示第一位,後面幾位用5個*替換,電話號碼中間五位用*替換
例如:
name tel
本身數據 jack 13985141027
christina 13982727341
-----------------------------
顯示爲 j***** 139*****027
c***** 139*****341
select rpad(substr(name,1,1),6,'*'), replace(tel,substr(tel,4,5),'*****') from inf3
數學函數
abs()-------求絕對值
select abs(-23) from dual;
sqrt()-------計算一個數的平方根
select sqrt(2) from dual;
power(k,n)---------計算k的n次冪
select power(2,3) from dual;
floor(浮點數);-------得到一個小於當前浮點數的最大整數
select floor(12.34) from dual;
round(浮點數,2);-----對當前浮點數,四捨五入,小數點後,保留2位有效位數
select round(123.45678,2) from dual;
random()------- 生成隨機數
- dbms: database management system(數據庫管理系統)
select dbms_random.value from dual; --生成一個隨機浮點數(範圍介於0-1之間)
select dbms_random.value(0,100) from dual;--產生一個0-100之間的隨機浮點數
select trunc(dbms_random.value(0,100)) from dual;--產生一個0-100之間的隨機整數
select sys_guid() from dual;---產生一個隨機字符串
sign(num)---判斷num的值是正數,負數,還是零
它的結果只有三種:
- 1---------表示當前數是正數
- -1--------表示當前數是負數
- 0---------表示當前數是零
select sign(0) from dual;
該函數,單獨使用,意義不在。它主要是結合decode函數一起使用
sign函數,結合decode函數,可以在語句中,進行條件判斷,可以形成下列效果
decode+sign可以形成:
- if...else
- if...else if...else
decode函數的語法:
語法1: decode(表達式,值,內容1,內容2) --if..else
- 如果表達式的結果與值是相等的,則執行內容1,否則,執行內容2
- select name,score,decode(sign(score-60),-1,'考覈不通過','考覈通過') 考覈結果 from info2;
語法2: decode(表達式,值1,內容1,值2,內容2....) -------多重if
- 如果表達式的結果與值1相等,則執行內容1,如果與值2相等,則執行內容2
create table user_level
(
id number(11) primary key,
name varchar2(20),
user_level char(1)
)
insert into user_level values(1,'jack','B');
insert into user_level values(2,'andy','A');
insert into user_level values(3,'chris','B');
insert into user_level values(4,'austin','E');
select id,name,user_level,decode(user_level,'A','一級用戶','B','二級用戶','C','三級用戶') 等級 from user_level;
在oracle語法中,在語句中,進行邏輯判斷:
- decode()
- case..when -----------這個語句,在mysql,oracle中用法一樣
用法1: ---用法類似於java中的switch (主要用於精確值的匹配)
case 表達式
when 值1 then 代碼1;
when 值2 then 代碼2;
.....
else
代碼3
end 別名;
select id,name,
case user_level
when 'A' then '一級用戶'
when 'B' then '二級用戶'
when 'C' then '三級用戶'
else '無法確定用戶等級'
end 用戶等級 from user_level;
用法2:---------這種方式,適合用於範圍判斷
case
when 表達式 then 代碼1;
when 表達式 then 代碼2;
when 表達式 then 代碼3;
else 代碼4;
end 別名;
select name,score,
case
when score>=90 then '優秀'
when score>=80 then '良好'
when score>=60 then '合格'
else '不合格'
end 考覈結果 from info2;
轉換函數:
to_date()
- 作用:轉換日期格式
/*
注意,在oracle數據庫中,日期格式的佔位符不區分大小寫
yyyy:年
mm:月
dd:天
hh:小時
mi:分鐘
ss:秒
*/
- 語法1: to_date('2011-12-11','yyyy-mm-dd');
- 語法2: to_date('2011-12-11 10:22:33','yyyy-mm-dd hh:mi:ss');
默認情況下,oracle數據庫中的小時,採用的是12小時制,如果要採用24小時制,需要寫成如下格式 - 語法3: to_date('2011-12-11 10:22:33','yyyy-mm-dd hh24:mi:ss');
to_char()
- 將內容轉換成指定字符格式
- select to_char(123) from dual;
作用1:將數值類型,轉換成字符類型
select name,score,
case
when score>=60 then to_char(score)
else '考覈不合格'
end 考覈結果
from info2;
用法2:獲得一個日期格式中,指定部份的值
select to_char(sysdate,'yyyy') from dual;
select to_char(sysdate,'mm') from dual;
select to_char(sysdate,'dd') from dual;
select to_char(sysdate,'hh24') from dual;
select to_char(sysdate,'mi') from dual;
select to_char(sysdate,'ss') from dual;
日期類型的數據,添加有如下方式:
方式1:
insert into test9 values(1,'jack',date'2019-10-02');
----這種添加日期的方式,只能添加年月日,不能帶時分秒
方式2:
insert into test9 values(2,'andy',sysdate);
----這種是添加系統時間,包含年月日,以及時分秒
方式3:自己添加指定的日期格式,既包含年月日,也包含時分秒 --(此時必須使用轉換日期函數to_date)
insert into test9 values(3,'chris',to_date('2019-01-02','yyyy-mm-dd'));
insert into test9 values(4,'houston',to_date('2019-01-04 10:12:15','yyyy-mm-dd hh:mi:ss'));
insert into test9 values(5,'austin',to_date('2019-01-06 13:12:15','yyyy-mm-dd hh24:mi:ss'));
select * from test9;
分析函數 (這種函數,主要在數據統計、數據分析時使用)
要求:查詢每一個員工的工資,按工資降序排列,並且生成一個名次
- select ename,sal,rownum 名次 from emp order by sal desc;
結果不正確,造成錯誤結果的原因是: 語句的執行順序是:
- 先執行查詢
- 再生成僞列
- 最後排序
解決方案1:子查詢
- select k.*,rownum from (select ename,sal from emp order by sal desc) k
解決方案2:使用分析函數
- 可以先排序,再生成一組連續的序號
- row_number() over(order by 字段名)
select ename,deptno,sal,row_number() over(order by sal desc) from emp;
既然子查詢可以實現,爲什麼還要使用分析函數?
- 原因:在進行統計、彙總的查詢時,一些簡單的統計查詢,可以使用可以使用子查詢實現,但稍微複雜一些的統
---例如:要統計每一個部門中,每一個員工在該部門的收入排名(每一個部門都會有1,2,3名) 統計查詢,子查詢也比較難以實現
- select ename,deptno,sal,row_number() over(partition by deptno order by sal desc) from emp;
- select ename,deptno,sal,row_number() over(partition by deptno order by sal desc) from emp where deptno=20;
--- 排序時,如果值一樣,允許產生並列名次
- select ename,deptno,sal,rank() over(partition by deptno order by sal desc) from emp where deptno=20;
--- 排序時,如果值一樣,允許產生並列名次,產生並列值以後,後面的序號依然連續
- select ename,deptno,sal,dense_rank() over(partition by deptno order by sal desc) from emp where deptno=20;
常用的四個分析函數:
row_number() over(order by 字段)
- 作用:先排序,再根據排列的順序,生成一組連續的序號
row_number() over(partition by 字段名 order by 字段名)
- 作用:先按照指定字段分組,然後在組內進行排序
rank() over(partition by 字段名 order by 字段名)
- 作用:排序時,允許出現在並列名次
- 注意:如果產生幾個並列值,後序就會跳過幾個序號
dense_rank() over(partition by 字段名 order by 字段名)
- 作用:允許產生並列值的排序,產生並列值以後,後面的序號,依然連續