# [SQL] Oracle [TOC] ## :triangular_flag_on_post: 獲取日期 trunc (time, format) 假設現在時間是2018-11-28 11:11:11 | 需求 | sql語法 | 輸出 | |-|-|-| |當月第一天|select trunc(sysdate, ‘mm’) from dual|2018-11-1 |當年第一天|select trunc(sysdate,‘yy’) from dual|2018-1-1 |當前年月日|select trunc(sysdate,‘dd’) from dual|2018-11-28 |當年第一天|select trunc(sysdate,‘yyyy’) from dual|2018-1-1 |當前星期的第一天(也就是星期天)|select trunc(sysdate,‘d’) from dual|2018-11-28 |當前日期|select trunc(sysdate) from dual|2018-11-28 |當前時間(準確到小時)|select trunc(sysdate, ‘hh’) from dual|2018-11-28 11:00:00 |當前時間(準確到分鐘)|select to_char(trunc(sysdate, ‘mi’),‘yyyy-MM-dd HH:mm:ss’) from dual|2018-11-28 11:11:00 |前一天的日期|select trunc(sysdate - 1) from dual|2018-11-27 |前一個月的日期|select add_months(trunc(sysdate),-1) from dual|2018-10-28 |後一個月的日期|select add_months(trunc(sysdate),1) from dual|2018-12-28 |本月最後一天|select to_char(last_day(sysdate), ‘yyyy-mm-dd’) from dual|2018-11-30 ## :triangular_flag_on_post: 若有null... ### NVL Oracle 獨有的函數,最多接受兩個參數。 * 狀況一 expr1 為 NULL, 返回 expr2; 不為 NULL, 返回 expr1。**注意!二者的類型要一致** ```=sql select NVL(expr1, expr2) as column_name_b from table_name ``` * 狀況二 expr1 不為 NULL, 返回expr2; 為 NULL, 返回 expr3。 expr2 和 expr3 類型不同的話, expr3 會轉換為 expr2 的類型。 ```=sql select NVL2(expr1, expr2, expr3) as column_name_a, NVL2(expr1, 'yes', 'no') as column_name_b from table_name ``` * 狀況三 相等返回 NULL,不相等返回 expr1。 ```=sql select NULLIF(expr1, expr2) as column_name from table_name ``` ### COALESCE 標準的sql函數,可接受一個或多個參數,最終返回第一個非null的值,若都是null則返回null。 ```=sql select coalesce(expr1, expr2, 'default') as column_name from table_name ``` ## :triangular_flag_on_post: 排序時對 Null 值的處理 在 Oracle 預設的處理上,null 會被當成最大值。 > **ASC** 時,null 會排在**最後面** > **DESC** 時,null 會排在**最前面** 當在排序時有需要對 null 做不同的排序。Oracle 有針對此情況支援 order by 相關的語法,如下: - **nulls first** - 將 null 值排在最前面 ```=sql SELECT * FROM <TableName> ORDER BY id NULLS FIRST; ``` - **nulls last** - 將 null 值排在最後面 ```=sql SELECT * FROM <TableName> ORDER BY id NULLS LAST; ``` ## :triangular_flag_on_post: 使用正則表達式 ### 函式:REGEXP_LIKE 尋找符合的字串 >REGEXP_LIKE(string, pattern [,match_option]) >REGEXP_LIKE(<搜尋值>, <正則表達式> [,<>]) 範例: 查詢某欄位是否包含連結的字串 ```=sql! select * from table_name where regexp_like(column_name, '(http|https|ftp)://[a-zA-Z0-9./?#=_-]+/') ``` ### 函式:REGEXP_INSTR 尋找符合的字串並回傳字串位置 >REGEXP_INSTR(<搜尋值>, <正則表達式> [, <搜尋的起始位置> [, occurrence [, return_option [, match_option]]]]) 範例: 要搜尋這些產品名稱以找到第一個非字母字元(無論它是大寫還是小寫)的位置 ```=sql! COLUMN product_name FORMAT a45 COLUMN non_alpha FORMAT 9999999999 SELECT product_name, REGEXP_INSTR(product_name, '[^[:alpha:]]') non_alpha FROM oe.product_information ``` 補充: * `[^[:<class>:]]` 表示一個字元,並匹配任何字元 * `[:alpha:]` 匹配任何字母字元 * `^` 對該表達式取非 ### 函式:REGEXP_REPLACE 尋找符合的字串並取代 >REGEXP_REPLACE(srcstr, pattern [,replacestr [, position [, occurrence [, match_option]]]]) 範例: 查詢符合網址的字串並取代 ```=sql! SELECT UNIQUE REGEXP_REPLACE (catalog_url, 'http://([^/]+).*', '\1') FROM oe.product_information ; ``` 補充: * `http://` 無特殊字元 * `([^/]+)` 不包含`/`的所有字元 * `.*` * `\1` ### 函式:REGEXP_SUBSTR 尋找符合的字串並回傳字串 >REGEXP_SUBSTR(srcstr, pattern [, position [, occurrence [, match_option]]]) 範例: 僅搜尋包含「SWITZERLAND」字串的電子郵件,並取得域名 ``` SELECT REGEXP_SUBSTR(cust_email, '[^@]+') FROM oe.customers WHERE nls_territory = 'SWITZERLAND' ; ``` 參考資料: [在 Oracle 数据库 10g 中使用正则表达式](https://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/228911_zhs.htm) ## 分析函數 在查詢結果內進行分析和計算的函數,與聚合函數(sum、avg、count)不同。分析函數可以不破壞查詢結果來進行分組、排序和計算,用於查詢的欄位(select語句) ```=sql 函數(參數) over( partition by 子句1, 子句2, ... [order by 子句1, 子句2, ... [asc|desc] [nulls first|nulls last]] [windowing 子句] ) ``` * 函數 用在統計,如max、min、avg * partition by 為查詢結果分組,類似group by * order by 可略,為查詢結果排序 * windowing 可略, ### 常見的分析函數 #### ROW_NUMBER() 賦予查詢結果集分配連續的編號 #### RANK() 賦予查詢結果集排名的數字 #### DENSE_RANK() 還沒用過不清楚 #### SUM()、AVG()、COUNT() 聚合函數也可以用在分析函數 參考資料: [SQL Fundamentals: 子查询 || 分析函数(PARTITION BY,ORDER BY, WINDOWING)](https://www.cnblogs.com/thescentedpath/p/analysisfunction.html) ## 階層式查詢 start with ... connect by prior ... ```=sql! SELECT type_id, type_name, SYS_CONNECT_BY_PATH(type_name, '/') as path, Level FROM table_name START WITH type_parent_id = 2 CONNECT BY PRIOR type_id = type_parent_id ``` * `START WITH [起始點]` * `CONNECT BY PRIOR [column1 = column2]` 表示將 column1 = column2 的資料列視為父資料列 * `SYS_CONNECT_BY_PATH(columnName, '/')` 用於串接欄位字串,會依階層( level )上至下(即 Parent > Child > GrandChild )串接該欄位。 參考資料: [Oracle SQL: Hierarchical queries / START WITH … CONNECT BY](https://renenyffenegger.ch/notes/development/databases/Oracle/SQL/select/hierarchical-queries/start-with_connect-by/index) [Oracle官方文件 - Hierarchical Queries](https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm) [ORACLE筆記-使用 CONNECT BY 呈現階層化資料](https://blog.darkthread.net/blog/oracle-connect-by/)