Oracle字串操作 、 Oracle數值操作 、 Oracle日期操作 、 空值操作
1. Oracle字串操作
1.1. 字串型別
1.1.1. CHAR和VARCHAR2型別
CHAR和VARCHAR2型別都是用來表示字串資料型別,用來在表中存放字串資訊, 比如姓名、職業、地址等。
CHAR存放定長字元,如果資料存不滿定長長度,則補齊空格;
VARCHAR2存放變長字元,實際資料有多少長度則佔用多少。
如儲存字串’HELLOWORLD’,共10個英文字母:
- CHAR(100): 10個字母,補齊90個空格,實際佔用100個位元組。
- VARCHAR2(100) :10個字母,實際佔用10個位元組。
CHAR型別浪費空間換取查詢時間的縮短,VARCHAR2節省空間查詢時間較CHAR型別要長。字串按照自然順序排序。
1.1.2. CHAR和VARCHAR2的儲存編碼
字串在資料庫中儲存的預設單位是位元組,也可顯式指定為字元。如:
- CHAR(10),等價於 CHAR(10 BYTE)
- 如果指定單位為字元:CHAR(10 CHAR),20個位元組
- VARCHAR2(10), 等價於VARCHAR2(10 BYTE)
- 指定單位為字元:VARCHAR2(10 CHAR),20個位元組
每個英文字元佔用一個位元組,每個中文字元按編碼不同,佔用2-4個位元組:
- ZHS16GBK: 2個位元組
- UTF-8: 2-4個位元組
1.1.3. CHAR和VARCHAR2的最大長度
CHAR型別的最大取值為2000位元組,也就是定義為CHAR(2000)。其中最多儲存2000個英文字元,1000個漢字(GBK)。
VARCHAR2最大取值為4000位元組,也就是VARCHAR2(4000),最多儲存4000個英文字元,2000個漢字(GBK)。
CHAR如果不指定長度,預設為1個位元組, VARCHAR2必須指定長度。
1.1.4. LONG和CLOB型別
LONG型別可以認為是VARCHAR2的加長版,用來儲存變長字串,最多達2GB的字串資料,但是LONG型別有諸多限制,所以不建議使用:
- 每個表只能有一個LONG型別列;
- 不能作為主鍵;
- 不能建立索引;
- 不能出現在查詢條件中等
CLOB用來儲存定長或變長字串,最多達4GB的字串資料,ORACLE建議開發中使用CLOB替代LONG型別,比如如下方式定義資料表:
- CREATE TABLE
- idNUMBER(4),
- nameCHAR(20),
- detailCLOB);
CREATE TABLE student( id NUMBER(4), name CHAR(20), detail CLOB);
1.2. 字串函式
1.2.1. CONCAT和“||”
CONCAT是字串連線函式,語法是:
- CONCAT(char1, char2)
CONCAT(char1, char2)
用於返回兩個字串連線後的結果,兩個引數char1、char2是要連線的兩個字串。concat只能有兩個引數,所以如果連線三個字串時,需要兩個concat函式。比如連線emp表中的name列和salary列,中間用“:”隔開:
- SELECTCONCAT(CONCAT(name, ' : '), sal)FROMemp;
SELECT CONCAT(CONCAT(name, ' : '), sal)FROM emp;
圖-1 CONCAT連線字串的結果
在連線兩個以上操作符時並不是很方便。concat的等價操作是連線操作符”||”。當多個字串連線時,用||符號更直觀。下述SQL語句實現相同的效果:
- SELECTename || ' : ' || salFROMemp;
SELECTename || ' : ' || sal FROMemp;
在連線時,如果任何一個引數是NULL,相當於連線了一個空格。
1.2.2. LENGTH
LENGTH(char)用於返回引數字串的長度。如果字元型別是VARCHAR2,返回字元的實際長度,如果字元型別是CHAR,長度還包括後補的空格。例如:
- SELECTename, LENGTH(name) FROMemp;
SELECTename, LENGTH(name) FROM emp;
將列出name和name的字串長度:
圖-2Lenth函式的執行結果
1.2.3. UPPER、LOWER和INITCAP
這三個函式全部是英文的大小寫轉換函式,用來轉換字元的大小寫:
- UPPER(char)用於將字元轉換為大寫形式
- LOWER(char)用於將字元轉換為小寫形式
- INITCAP(char)用於將字串中每個單詞的首字元大寫,其它字元小寫,單詞之間用空格和非字母字元分隔
如果這三個函式的輸入引數是NULL值,仍然返回NULL值。例如:
- SELECTUPPER('hello world'), LOWER('HELLO WORLD'), INITCAP('hello world')
- FROMDUAL;
SELECT UPPER('hello world'), LOWER('HELLO WORLD'), INITCAP('hello world') FROM DUAL;
將列出引數“hello world”的大寫、小寫和首字元大寫的形式。一般用來查詢資料表中不確定大小寫的情況。查詢結果如圖-3所示。
圖-3大小寫轉換函式的執行結果
1.2.4. TRIM、LTRIM、RTRIM
這三個TRIM函式的作用都是截去子字串。語法形式及解釋:
- TRIM(c2 FROM c1) 表示從c1的前後截去c2
- LTRIM(c1[, c2]) 表示從c1的左邊(Left)截去c2
- RTRIM(c1[, c2]) 表示從c1的右邊(Right)截去c2
在後兩個函式中,如果沒有引數c2,就去除空格。例如:
- SELECTTRIM('e' from 'elite') ASt1,
- LTRIM('elite', 'e') ASt2,
- RTRIM('elite', 'e') AS t3
- FROMDUAL;
SELECT TRIM('e' from 'elite') AS t1, LTRIM('elite', 'e') AS t2, RTRIM('elite', 'e') AS t3 FROM DUAL;
其中最常用的是TRIM,經常用來去掉字串前後的空格。執行結果如圖-4所示。
圖-4TRIM函式的執行結果
1.2.5. LPAD、RPAD
PAD意即補丁,LPAD和RPAD兩個函式都叫做補位函式,LPAD表示LEFT PAD,在左邊打補丁,RPAD表示RIGHT PAD,在右邊打補丁。語法如下:
- LPAD(char1, n, char2) 左補位函式
- RPAD(char1, n, char2) 右補位函式
引數的含義:在字串引數char1的左端或右端用char2補足到n位,其中引數char2可重複多次。例如在EMP表中使用左補位,將sal用$補齊6位,執行結果如圖-5所示。
圖-5補位函式的執行結果
1.2.6. SUBSTR
SUBSTR表示在一個字串中擷取子串,語法是:
- SUBSTR(char, [m[, n]])
SUBSTR(char, [m[, n]])
用於返回char中從m位開始取n個字元的子串,字串的首位計數從1開始。引數含義如下:
- 如果m = 0,則從首字元開始,如果m取負數,則從尾部開始
- 如果沒有設定n,或者n的長度超過了char的長度,則取到字串末尾為止
例如:
- SELECT
- SUBSTR('Doctor Who travels in TARDIS', 8, 25)
- FROMDUAL;
SELECT SUBSTR('Doctor Who travels in TARDIS', 8, 25) FROM DUAL;
圖-6取子串函式的執行結果
1.2.7. INSTR
用來返回在一個字串中子串的位置。語法是:
- INSTR(char1, char2[, n [, m]])
INSTR(char1, char2[, n [, m]])
引數的含義:
- 返回子串char2在源字串char1中的位置
- 從n的位置開始搜尋,沒有指定n,從第1個字元開始搜尋
- m用於指定子串的第m次出現次數,如果不指定取值1
- 如果在char1中沒有找到子串char2 ,返回0
例如:
- SELECTINSTR('Doctor Who', 'Who') words FROMDUAL;
SELECT INSTR('Doctor Who', 'Who') words FROM DUAL;
結果將返回8.
2. Oracle數值操作
2.1. 數值型別
2.1.1. NUMBER(p)表示整數
資料表中的數值型別用NUMBER表示,完整語法是:
- NUMBER(precision ,scale)
NUMBER(precision ,scale)
可以用來表示整數和浮點數。如果沒有設定引數s,則預設取值0,即NUMBER(p)用來表示整數。P表示數字的總位數,取值為1-38。一般用來在表中存放如編碼、年齡、次數等用整數記錄的資料。例如建表時指定學生編碼是4位數字:
- CREATE TABLEstudent (
- idNUMBER(4),
- nameCHAR(20));
CREATE TABLE student ( id NUMBER(4), name CHAR(20));
2.1.2. NUMBER(P,S)表示浮點數
如果NUMBER(precision ,scale)的兩個引數全部顯式定義,則表示浮點數:
- precision:NUMBER可以儲存的最大數字長度(不包括左右兩邊的0)
- scale:在小數點右邊的最大數字長度(包括左側0)
如果指定了s但是沒有指定p,則p預設為38,例如:
- 列名 NUMBER(*,S)
列名 NUMBER(*,S)
NUMBER(p,s)經常用來做表中存放金額、成績等有小數位的資料。例如建立學生表,指定成績整數位最多3位,小數位最多2位:
- CREATE TABLEstudent (
- idNUMBER(4),
- nameCHAR(20),
- scoreNUMBER(5, 2));
CREATE TABLE student ( id NUMBER(4), name CHAR(20), score NUMBER(5, 2));
NUMBER的變種資料型別:內部實現是NUMBER,可以將其理解為NUMBER的別名,目的是多種資料庫及程式語言相容
- NUMERIC(p,s):完全對映至NUMBER(p,s)
- DECIMAL(p,s)或DEC(p,s):完全對映至NUMBER(p,s)
- INTEGER或INT:完全對映至NUMBER(38)型別
- SMALLINT:完全對映至NUMBER(38)型別
- FLOAT(b):對映至NUMBER型別
- DOUBLE PRECISION:對映至NUMBER型別
- REAL:對映至NUMBER型別
2.2. 數值函式
2.2.1. ROUND
數值函式指引數是數值型別的函式。常用的有ROUND、TRUNC、MOD、CEIL和FLOOR。其中ROUND用來四捨五入,語法如下:
ROUND(n[, m])用於將引數n按照m的數字要求四捨五入。其中:
- 引數中的n可以是任何數字,指要被處理的數字
- m必須是整數
- m取正數則四捨五入到小數點後第m位
- m取0值則四捨五入到整數位
- m取負數,則四捨五入到小數點前m位
- m預設,預設值是0
例如:
- SELECTROUND(45.678, 2) FROMDUAL; --45.68
- SELECTROUND(45.678, 0) FROMDUAL;--46
- SELECTROUND(45.678, -1) FROMDUAL;--50
SELECT ROUND(45.678, 2) FROM DUAL; --45.68 SELECT ROUND(45.678, 0) FROM DUAL;--46 SELECT ROUND(45.678, -1) FROM DUAL;--50
2.2.2. trunc
TRUNC(n[, m])的功能是擷取,其中n和m的定義和ROUND(n[, m])相同,不同的是功能上按照擷取的方式處理數字n。例如:
- SELECTTRUNC(45.678, 2) FROMDUAL; --45.67
- SELECTTRUNC(45.678, 0) FROMDUAL;--45
- SELECTTRUNC(45.678, -1) FROMDUAL;--40
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
2.2.3. MOD
MOD(m, n)是取模函式,返回m除以n後的餘數,如果n為0則直接返回m。例如:
- --薪水值按1000取餘數
- SELECTename, sal, MOD(sal, 1000) FROMemp;
--薪水值按1000取餘數 SELECTename, sal, MOD(sal, 1000) FROM emp;
圖-7薪水列按1000取模後的執行結果
2.2.4. CEIL和FLOOR
CEIL(n)、FLOOR(n)這兩個函式顧名思義,一個是天花板,就是取大於或等於n的最小整數值,一個是地板,就是取小於或等於n的最大整數值。比如數字n = 4.5,那麼它的CEIL是5.0,它的FLOOR是4.0。在SQL語句中的例子如下:
- SELECTCEIL(45.678) FROMDUAL; --46
- SELECTFLOOR(45.678) FROMDUAL;--45
SELECT CEIL(45.678) FROM DUAL; --46 SELECT FLOOR(45.678) FROM DUAL;--45
3. Oracle日期操作
3.1. 日期型別
3.1.1. DATE
DATE和TIMESTAMP是ORACLE中最常用的日期型別。DATE用來儲存日期和時間。表示範圍從是公元前4712年1月1日至公元9999年12月31日。
DATE型別在資料庫中的實際儲存固定為7個位元組,格式分別為:
- 第1位元組:世紀+100
- 第2位元組:年
- 第3位元組:月
- 第4位元組:天
- 第5位元組:小時+1
- 第6位元組:分+1
- 第7位元組:秒+1
3.1.2. TIMESTAMP
TIMESTAMP表示時間戳,與DATE的區別是不僅可以儲存日期和時間,還能儲存小數秒,可指定為0-9位,預設6位,最高精度可以到ns(納秒)級別。
資料庫內部用7或者11個位元組儲存,精度為0時,用7位元組儲存,與DATE功能相同,精度大於0則用11位元組儲存。格式為:
- 第1位元組-第7位元組:和DATE相同
- 第8-11位元組:納秒,採用4個位元組儲存,內部運算型別為整型
用日期型別建表的例子:
- CREATE TABLEtest(
- c1DATE,
- c2TIMESTAMP(9));
CREATE TABLE test( c1 DATE, c2 TIMESTAMP(9));
3.2. 日期關鍵字
3.2.1. SYSDATE
SYSDATE本質是一個Oracle的內部函式,用來返回當前的系統時間,精確到秒,預設顯示格式是DD-MON-RR,只有年月日並不顯示時間。例如:
- SELECT SYSDATE FROMDUAL;
SELECT SYSDATE FROM DUAL;
如果資料庫是英文環境,將顯示“03-MAY-14”的形式,如果是中文環境,將顯示“03-5月-14”的形式。如果想顯示時分秒,需要將格式轉換一下:
- SELECTTO_CHAR(SYSDATE,'yyyy-mm-dd day hh24:mi:ss') FROMDUAL;
SELECT TO_CHAR(SYSDATE,'yyyy-mm-dd day hh24:mi:ss') FROM DUAL;
執行結果是:
圖-8顯示當前的系統時間
在建表時,可以將系統時間SYSDATE作為某一列的預設值,當插入新的記錄,將會取當時的系統時間,作為資料表的一列資料儲存起來。例如學生表,學生的註冊時間列即預設取值資料記錄插入的時間:
- CREATE TABLEstudent (idNUMBER(4),
- nameCHAR(20),
- registerDate DATE DEFAULTSYSDATE);
CREATE TABLE student (id NUMBER(4), name CHAR(20), registerDate DATE DEFAULT SYSDATE);
3.2.2. SYSTIMESTAMP
SYSTIMESTAMP也是Oracle的內部日期函式,返回當前系統日期和時間,精確到毫秒。例如:
- SELECT SYSTIMESTAMP FROMDUAL;
- SELECTTO_CHAR(SYSTIMESTAMP,'SSSS.FF') FROMDUAL;
SELECT SYSTIMESTAMP FROM DUAL; SELECT TO_CHAR(SYSTIMESTAMP,'SSSS.FF') FROM DUAL;
3.3. 日期轉換函式
3.3.1. TO_DATE
日期資料有時需要和字串資料相互轉換,需要用到日期轉換函式,包括TO_CHAR和TO_DATE。
TO_DATE的功能是將字串按照定製格式轉換為日期型別,語法格式是:
- TO_DATE(char[, fmt[, nlsparams]])
TO_DATE(char[, fmt[, nlsparams]])
其中:char是要轉換的字串,fmt是轉換格式,nlsparams是指定日期語言。其中比較重要的是格式,常用的日期格式如下:
表-1 常用日期格式
例子:查詢2002年以後入職的員工:
- SELECTename, hiredate
- FROM emp
- WHEREhiredate>
- TO_DATE(‘2002-01-01',
- 'YYYY-MM-DD');
SELECTename, hiredate FROM emp WHERE hiredate> TO_DATE(‘2002-01-01', 'YYYY-MM-DD');
3.3.2. TO_CHAR
TO_CHAR的作用是將其它型別(日期,數值)的資料轉換為字元型別,主要應用在日期型別上。語法格式:
- TO_CHAR(date[, fmt[, nlsparams]])
TO_CHAR(date[, fmt[, nlsparams]])
其中fmt是格式,將日期型別資料date按照fmt格式輸出字串,nlsparams用於指定日期語言。例如:
- SELECTename,TO_CHAR(hiredate, 'YYYY"年"MM"月"DD"日"')
- FROMemp;
SELECTename,TO_CHAR(hiredate, 'YYYY"年"MM"月"DD"日"') FROM emp;
3.4. 日期常用函式
3.4.1. LAST_DAY
LAST_DAY(date):返回日期date所在月的最後一天,一般是在按照自然月計算某些業務邏輯,或者安排月末週期性活動時很有用處。例子:
- SELECTLAST_DAY(SYSDATE) FROMDUAL;--查詢當月的最後一天
- SELECTLAST_DAY('20-2月-09') FROMDUAL;--查詢09年2月的最後一天
SELECT LAST_DAY(SYSDATE) FROM DUAL;--查詢當月的最後一天 SELECT LAST_DAY('20-2月-09') FROM DUAL;--查詢09年2月的最後一天
3.4.2. ADD_MONTHS
ADD_MONTHS(date, i):返回日期date加上i個月後的日期值.
其中:
- 引數i可以是任何數字,大部分時候取正值整數
- 如果i是小數,將會被擷取整數後再參與運算
- 如果i是負數,則獲得的是減去i個月後的日期值
例如計算職員入職20週年紀念日:
- SELECTename, ADD_MONTHS(hiredate, 20 * 12) "20週年"
- FROMemp;
SELECTename, ADD_MONTHS(hiredate, 20 * 12) "20週年" FROM emp;
3.4.3. MONTHS_BETWEEN
MONTHS_BETWEEN(date1, date2):計算date1和date2兩個日期值之間間隔了多少個月,實際運算是date1-date2,如果date2時間比date1晚,會得到負值。
除非兩個日期間隔是整數月,否則會得到帶小數位的結果,比如計算2009年9月1日到2009年10月10日之間間隔多少個月,會得到1.29個月。例如計算職員入職多少個月:
- SELECTename, MONTHS_BETWEEN(SYSDATE, hiredate) hiredate FROM emp;
SELECTename, MONTHS_BETWEEN(SYSDATE, hiredate) hiredate FROM emp;
3.4.4. NEXT_DAY
NEXT_DAY(date, char):返回date日期資料的下一個周幾,周幾是由引數char來決定的。在中文環境下,直接使用”星期三”這種形式,英文環境下,需要使用”WEDNESDAY”這種英文的周幾。為避免麻煩,可以直接用數字1-7表示週日-週六。
需要注意的是NEXT_DAY不要按字面意思理解為明天。查詢下個週三是幾號:
- SELECTNEXT_DAY(SYSDATE, 4) next_wedn FROMDUAL;
SELECT NEXT_DAY(SYSDATE, 4) next_wedn FROM DUAL;
3.4.5. LEAST、GREATEST
比較函式LEAST和GREATEST語法如下:
- GREATEST(expr1[, expr2[, expr3]]…)
- LEAST(expr1[, expr2[, expr3]]…)
GREATEST(expr1[, expr2[, expr3]]…) LEAST(expr1[, expr2[, expr3]]…)
兩個函式都可以有多個引數值,但引數型別必須一致,返回結果是引數列表中最大或最小的值。
在比較之前,在引數列表中第二個以後的引數會被隱含的轉換為第一個引數的資料型別,所以如果可以轉換,則繼續比較,如果不能轉換將會報錯。
- SELECTLEAST(SYSDATE, '10-10月 -08') FROMDUAL;
SELECT LEAST(SYSDATE, '10-10月 -08') FROM DUAL;
3.4.6. EXTRACT
EXTRACT直譯是抽取或提取:
EXTRACT(date FROM datetime):從引數datetime中提取引數date指定的資料,比如提取年、月、日。例如取出當前日期的年:
- SELECTEXTRACT(YEAR FROMSYSDATE) current_year FROMDUAL;
SELECT EXTRACT(YEAR FROM SYSDATE) current_year FROM DUAL;
取出指定時間的小時:
- SELECTEXTRACT(HOUR FROMTIMESTAMP '2008-10-10 10:10:10')
- FROMDUAL;
SELECT EXTRACT(HOUR FROM TIMESTAMP '2008-10-10 10:10:10') FROM DUAL;
4. 空值操作
4.1. NULL的含義
NULL是資料庫裡的重要概念,即空值。當表中的某些欄位值,資料未知或暫時不存在,取值NULL。
Java中的簡單資料型別是不能取值NULL的,在資料庫中,任何資料型別均可取值NULL。
4.2. NULL操作
4.2.1. 插入NULL值
在資料表中插入記錄時,如果要插入NULL值,可以用顯式指定NULL值的方式,或者不插入某個欄位值,即隱式表示NULL值。例如表student中:
- CREATE TABLEstudent(idNUMBER(4), nameCHAR(20), genderCHAR(1));
- INSERT INTO studentVALUES(1000, '李莫愁', 'F');
- INSERT INTO studentVALUES(1001, '林平之', NULL);--顯式插入NULL值
- INSERT INTOstudent(id, name) VALUES(1002, '張無忌');--隱式插入NULL值
CREATE TABLE student(id NUMBER(4), name CHAR(20), gender CHAR(1)); INSERT INTO student VALUES(1000, '李莫愁', 'F'); INSERT INTO student VALUES(1001, '林平之', NULL);--顯式插入NULL值 INSERT INTO student(id, name) VALUES(1002, '張無忌');--隱式插入NULL值
4.2.2. 更新成NULL值
把資料表的某個欄位更新為NULL值,和更新為其他資料的語法是相同的。比如更新
- UPDATE student SETgender = NULL; --全表都被更新
UPDATE student SET gender = NULL; --全表都被更新
注意這種更新只有在此列沒有非空約束的情況下才可操作。如果gender列有非空約束,則無法更新為NULL值,上述語句會報錯。
4.2.3. NULL條件查詢
在條件查詢中,因為NULL不等於任何值,所以不能用“列名=NULL”這種形式查詢。必須用“列名 IS NULL”來判斷,或者用“列名 IS NOT NULL”來查詢非空資料。
- SELECT * FROM student WHERE gender ISNULL;
SELECT * FROM student WHERE gender IS NULL;
4.2.4. 非空約束
非空(NOT NULL)約束是約束條件的一種,用於確保資料表中某個欄位值不為空。
因為在預設情況下,任何資料型別的列都允許有空值,但系統的業務邏輯可能會要求某些列不能取空值。這時需要在建表時指定該列不允許為空。
一旦某個欄位被設定了非空約束條件,這個欄位中必須存在有效值。即:當執行插入資料的操作時,必須提供這個列的資料,當執行更新操作時,不能給這個列的值設定為NULL。
- --建立資料表student,其中gender列不允許為空
- CREATE TABLE student
- (idNUMBER(4),
- nameCHAR(20),
- genderCHAR(1) NOTNULL);
--建立資料表student,其中gender列不允許為空 CREATE TABLE student (id NUMBER(4), name CHAR(20), gender CHAR(1) NOT NULL);
4.3. 空值函式
4.3.1. NVL
NVL(expr1, expr2):將NULL轉變為非NULL值。如果expr1為NULL,則取值expr2, expr2是非空值。
其中expr1和expr2可以是任何資料型別,但兩個引數的資料型別必須是一致的。
計算員工月收入,如果comm列為空值的話,最終計算結果將是空,不符合邏輯,所以先將取NULL值的comm列轉換為0,再相加。
- SELECTename, sal, comm,sal + nvl(comm, 0) salary
- FROMemp;
SELECTename, sal, comm,sal + nvl(comm, 0) salary FROM emp;
4.3.2. NVL2
NVL2(expr1, expr2, expr3):和NVL函式功能類似,都是將NULL轉變為非空值。NVL2用來判斷expr1是否為NULL,如果不是NULL,返回expr2,如果是NULL,返回expr3。
- SELECTename, sal, comm,
- nvl2(comm, sal + comm, sal) salary
- FROMemp;
SELECTename, sal, comm, nvl2(comm, sal + comm, sal) salary FROM emp;