|
| 1 | +# Oracle |
| 2 | + |
| 3 | +[[toc]] |
| 4 | + |
| 5 | + |
| 6 | +## Flag |
| 7 | + |
| 8 | +* [Oracle with as + /*+ materialize*/ 优化](https://blog.csdn.net/qq_34745941/article/details/106897099) |
| 9 | +* [Oracle两种临时表的创建及使用方法](https://www.cnblogs.com/beloved-bq/p/12561512.html) |
| 10 | +* [https://docs.oracle.com/en/database/oracle/oracle-database/21/lnoci/preface.html](https://docs.oracle.com/en/database/oracle/oracle-database/21/lnoci/preface.html) |
| 11 | + |
| 12 | + |
| 13 | +> 空字符串''同等NULL,字符串与数字类型会自动转换 |
| 14 | +
|
| 15 | +> Oracle Call Interface(OCI)是Oracle提供的一组C语言API,用于开发Oracle数据库应用程序。 |
| 16 | +> OCI提供了一种直接访问Oracle数据库的方式,使开发人员可以编写高效且可扩展的应用程序 |
| 17 | +
|
| 18 | + |
| 19 | +```sql |
| 20 | +-- 创建会话级临时表来存储原数据,并删除表数据 |
| 21 | +CREATE GLOBAL TEMPORARY TABLE TEST_BAK AS (SELECT * FROM TEST); |
| 22 | + |
| 23 | +-- 查看临时表数据 |
| 24 | +SELECT * FROM TEST_BAK; |
| 25 | + |
| 26 | +-- Oracle中类似于PostgreSQL的unnest |
| 27 | +-- https://docs.oracle.com/en/database/oracle/oracle-database/23/addci/extensibility-constants-types-and-mappings.html |
| 28 | +select * from table(sys.odcinumberlist(3,4,3)) |
| 29 | +select * from table(sys.odcivarchar2list('3a','4b','3d')) |
| 30 | + |
| 31 | +-- 常量子查询 |
| 32 | +字段 IN (SELECT 10000 FROM dual UNION ALL SELECT 20000 FROM dual) |
| 33 | + |
| 34 | +-- 清空数据 delete是dml操作;truncate是ddl操作,ddl隐式提交不能回滚,会回收表空间 |
| 35 | +DELETE FROM TEST; |
| 36 | +-- 将目标字段数据清空 |
| 37 | +--UPDATE TEST SET MEASURED = NULL; |
| 38 | + |
| 39 | +-- 修改表字段 |
| 40 | +ALTER TABLE TEST MODIFY MEASURED NUMBER(18,6); |
| 41 | + |
| 42 | +-- 还原表结构 |
| 43 | +INSERT INTO TEST SELECT * FROM TEST_BAK; |
| 44 | + |
| 45 | +-- 删除临时表 |
| 46 | +DROP TABLE TEST_BAK; |
| 47 | + |
| 48 | + |
| 49 | +-- 替代LISTAGG拼接超4000字符长度 |
| 50 | +SELECT |
| 51 | +REGEXP_REPLACE(RTRIM(XMLSERIALIZE(CONTENT XMLAGG(XMLELEMENT(E,colname,',').EXTRACT('//text()')) AS CLOB),', '),'(,)+',',') a, |
| 52 | +REGEXP_REPLACE(RTRIM(XMLAGG(XMLELEMENT(E,colname,',').EXTRACT('//text()')).getclobval(),','),'(,)+',',') b, |
| 53 | +REGEXP_REPLACE(RTRIM(REGEXP_REPLACE(XMLSERIALIZE(CONTENT XMLAGG(XMLELEMENT(e, colname || ',')) AS CLOB),'<E>|</E>',''),','),'(,)+',',') c |
| 54 | +FROM table_name |
| 55 | +GROUP BY grouping_column; |
| 56 | +``` |
| 57 | + |
| 58 | + |
| 59 | +**系统表** |
| 60 | + |
| 61 | +- `USER_TABLES` 当前用户拥有的表:`TABLE_NAME`,`TABLESPACE_NAME`,`LAST_ANALYZED` |
| 62 | +- `DBA_TABLES` 包括系统表:多了`OWER`列 |
| 63 | +- `ALL_TABLES` 所有用户的表:多了`OWER`列 |
| 64 | +- `ALL_OBJECTS` 当前用户有访问权限的所有对象:`OWER`,`OBJECT_NAME`,`SUBOBJECT_NAME`,`OBJECT_ID`,`CREATED`,`LAST_DDL_TIME`,`TIMESTAMP`,`STATUS` |
| 65 | +- `USER_TAB_COLUMNS` 当前用户拥有的表字段 |
| 66 | +- `ALL_TAB_COLUMNS` |
| 67 | +- `DBA_TAB_COLUMNS` |
| 68 | +- `USER_TAB_COMMENTS` 当前用户拥有的表注释 :`TABLE_NAME`,`TABLE_TYPE`,`COMMENTS` |
| 69 | +- `DBA_TAB_COMMENTS` :多了`OWER`列 |
| 70 | +- `ALL_TAB_COMMENTS` :多了`OWER`列 |
| 71 | +- `USER_COL_COMMENTS` 当前用户拥有的表字段注释 : `TABLE_NAME`,`COLUMN_NAME`,`COMMENTS` |
| 72 | +- `DBA_COL_COMMENTS` :多了`OWER`列 |
| 73 | +- `ALL_COL_COMMENTS` :多了`OWER`列 |
| 74 | + |
| 75 | +> `SELECT * FROM USER_TAB_COMMENTS WHERE COMMENTS LIKE '%摘要%'` |
| 76 | +
|
| 77 | + |
| 78 | +**分组获取最新一条数据(查询各组最新的一条记录)** |
| 79 | + |
| 80 | +- over partition by 分析函数(开窗函数) |
| 81 | + |
| 82 | +```sql |
| 83 | +SELECT * FROM ( |
| 84 | + SELECT ROW_NUMBER() OVER(PARTITION BY 分组字段名 ORDER BY 排序字段名 DESC) rn,t.* FROM test1 t |
| 85 | + ) WHERE rn = 1; |
| 86 | + |
| 87 | +SELECT t.* FROM test1 t GROUP BY 分组字段名 ORDER BY 排序字段名 DESC FETCH FIRST 1 ROWS ONLY; |
| 88 | + |
| 89 | + |
| 90 | +SELECT * FROM ( |
| 91 | + select eb_vipcode,eb_time,MAX(eb_time) over(partition by eb_vipcode) as "atime" from eb_daskexpdateinfo |
| 92 | + ) x where eb_time = "atime"; |
| 93 | + |
| 94 | +SELECT * FROM ( |
| 95 | + select ID_,COMPANY_NAME,USAGE_RATE,CREATE_TIME |
| 96 | + ,MAX(CREATE_TIME) over(partition by COMPANY_NAME) as "atime" from SPEC_RATE_ORIGIN |
| 97 | + ) x where CREATE_TIME = "atime"; |
| 98 | +``` |
| 99 | + |
| 100 | +- group by |
| 101 | + |
| 102 | +```sql |
| 103 | +SELECT eb_vipcode,MAX(eb_time) AS "atime" FROM eb_daskexpdateinfo group by eb_vipcode |
| 104 | +``` |
| 105 | + |
| 106 | +- inner join |
| 107 | + |
| 108 | +```sql |
| 109 | +SELECT A.* FROM SPEC_RATE_ORIGIN A INNER JOIN ( |
| 110 | + SELECT COMPANY_NAME,MAX(CREATE_TIME) AS "atime" FROM SPEC_RATE_ORIGIN group by COMPANY_NAME |
| 111 | + ) B ON A.COMPANY_NAME = B.COMPANY_NAME AND A.CREATE_TIME = B."atime"; |
| 112 | +``` |
| 113 | + |
| 114 | + |
| 115 | +**一次执行多条SQL** |
| 116 | + |
| 117 | +```sql |
| 118 | +INSERT ALL |
| 119 | + INTO a表(字段) VALUES(各个值1) |
| 120 | + INTO a表(字段) VALUES(其它值2) |
| 121 | + INTO a表(字段) VALUES(其它值3) |
| 122 | +SELECT 1 FROM DUAL; |
| 123 | +``` |
| 124 | + |
| 125 | +- 使用`begin…end;` |
| 126 | + |
| 127 | +* [如何在Oracle中一次执行多条sql语句](https://www.cnblogs.com/teamleader/archive/2007/05/31/765943.html) |
| 128 | + |
| 129 | +```sql |
| 130 | +begin |
| 131 | +insert into table_name (列名,列名) values (express,express); |
| 132 | +insert into table_name (列名,列名) values (express,express); |
| 133 | +insert into table_name (列名,列名) values (express,express); |
| 134 | +insert into table_name (列名,列名) values (express,express); |
| 135 | +end; |
| 136 | +``` |
| 137 | + |
| 138 | + |
| 139 | + |
| 140 | +**插入或更新 upsert** |
| 141 | + |
| 142 | +* [SQL语句 存在就更新不存在就插入](https://www.jianshu.com/p/602ba0b8395b) |
| 143 | +* [merge into 的用法](https://blog.csdn.net/weixin_40374341/article/details/109239544) |
| 144 | + |
| 145 | + |
| 146 | +```sql |
| 147 | +MERGE INTO table_name alias1 |
| 148 | +USING (table|view|sub_query) alias2 |
| 149 | +ON (join condition) |
| 150 | +WHEN MATCHED THEN |
| 151 | + UPDATE table_name SET col1 = col_val1 |
| 152 | +WHEN NOT MATCHED THEN |
| 153 | + INSERT (column_list) VALUES (column_values); |
| 154 | +``` |
| 155 | + |
| 156 | + |
| 157 | + |
| 158 | + |
| 159 | +**死锁** |
| 160 | + |
| 161 | +```sql |
| 162 | +-- 查询死锁会话 |
| 163 | +SELECT l.session_id sid, s.serial#, l.locked_mode, l.oracle_username, l.os_user_name |
| 164 | +, s.machine, s.terminal, o.object_name, s.logon_time, p.SPID |
| 165 | + FROM v$locked_object l, all_objects o, v$session s,v$process p |
| 166 | + WHERE l.object_id = o.object_id AND l.session_id = s.sid AND s.paddr = p.addr |
| 167 | + ORDER BY sid, s.serial#; |
| 168 | + |
| 169 | +-- 结束 |
| 170 | +alter system kill session 'sid,serial#'; |
| 171 | +``` |
| 172 | + |
| 173 | +```bash |
| 174 | +orakill SID spid |
| 175 | +``` |
| 176 | + |
| 177 | + |
| 178 | +**查看所有表结构** |
| 179 | + |
| 180 | +```sql |
| 181 | +SELECT t1.Table_Name || chr(13) || t3.comments AS "表名称及说明", |
| 182 | + --t3.comments AS "表说明", |
| 183 | + t1.COLUMN_ID AS "序号", |
| 184 | + t1.Column_Name AS "字段名称", |
| 185 | + t1.DATA_TYPE || '(' || t1.DATA_LENGTH || ')' AS "数据类型", |
| 186 | + t1.NullAble AS "是否为空", |
| 187 | + t2.Comments AS "字段说明", |
| 188 | + t1.Data_Default AS "默认值" |
| 189 | + --t4.created AS "建表时间" |
| 190 | +FROM cols t1 |
| 191 | +LEFT JOIN user_col_comments t2 ON t1.Table_name = t2.Table_name AND t1.Column_Name = t2.Column_Name |
| 192 | +LEFT JOIN user_tab_comments t3 ON t1.Table_name = t3.Table_name |
| 193 | +LEFT JOIN user_objects t4 ON t1.table_name = t4.OBJECT_NAME |
| 194 | +WHERE NOT EXISTS ( |
| 195 | + SELECT t4.Object_Name |
| 196 | + FROM User_objects t4 |
| 197 | + WHERE t4.Object_Type = 'TABLE' AND t4.Temporary = 'Y' AND t4.Object_Name = t1.Table_Name |
| 198 | +) |
| 199 | +ORDER BY t1.Table_Name, t1.Column_ID; |
| 200 | + |
| 201 | +-- 查询表字段信息 |
| 202 | +WITH ct AS ( |
| 203 | + SELECT u3.table_name,u3.column_name,u4.constraint_type FROM user_cons_columns u3 |
| 204 | + JOIN user_constraints u4 ON u4.constraint_name=u3.constraint_name AND u4.constraint_type='P' |
| 205 | +) |
| 206 | +SELECT DISTINCT u1.column_id |
| 207 | +, u1.column_name |
| 208 | +, u1.data_type AS column_type |
| 209 | +, (CASE WHEN u1.data_type='NVARCHAR2' THEN u1.data_length/2 ELSE u1.data_length END) AS data_length |
| 210 | +, (CASE WHEN DECODE(u1.nullable, 'Y', 'N', 'N', 'Y', 'N')='Y' THEN 0 ELSE 1 END) AS nullable |
| 211 | +, u1.data_precision AS data_precision |
| 212 | +, u1.data_scale AS data_scale |
| 213 | +, u2.comments |
| 214 | +, DECODE(ct.constraint_type,'P','PRI') AS column_key |
| 215 | +FROM user_tab_columns u1 |
| 216 | +LEFT JOIN user_col_comments u2 ON u1.table_name=u2.table_name AND u1.column_name=u2.column_name |
| 217 | +LEFT JOIN ct ON ct.table_name=u1.table_name AND ct.column_name=u1.column_name |
| 218 | +WHERE u1.table_name= '表名' |
| 219 | +ORDER BY u1.column_id |
| 220 | +``` |
| 221 | + |
| 222 | + |
| 223 | +**日期时间** |
| 224 | + |
| 225 | +* [Oracle日期格式转换 to_date,to_char,to_timetamp 相互转换](https://blog.csdn.net/HaHa_Sir/article/details/125572325) |
| 226 | + |
| 227 | +```sql |
| 228 | +SELECT SYSDATE, SYSTIMESTAMP FROM dual; |
| 229 | +SELECT TO_CHAR(TO_TIMESTAMP('2023-05-08 10:10:10', 'yyyy-mm-dd hh24:mi:ss'), 'ww') FROM dual; |
| 230 | +-- 得到当天凌晨0点0分0秒的日期 |
| 231 | +SELECT TRUNC(SYSDATE) FROM DUAL; |
| 232 | +-- 获取今天最后的时间(即午夜之前的那一刻) |
| 233 | +SELECT TRUNC(SYSDATE) + 0.99999 AS last_time FROM DUAL; |
| 234 | +SELECT TRUNC(SYSDATE) + 1 - 1/86400 AS last_time FROM dual; |
| 235 | +SELECT TRUNC(SYSDATE) + 1 - INTERVAL '1' SECOND AS last_time FROM DUAL; |
| 236 | +SELECT TRUNC(SYSDATE) + INTERVAL '1' DAY - INTERVAL '1' SECOND AS last_time FROM DUAL; |
| 237 | +SELECT TRUNC(SYSDATE) + INTERVAL '23' HOUR + INTERVAL '59' MINUTE + INTERVAL '59' SECOND AS last_time FROM DUAL; |
| 238 | +-- 获取本周开始日期(星期一) |
| 239 | +SELECT TRUNC(SYSDATE, 'IW') FROM DUAL; |
| 240 | +-- 获取本周结束日期(星期日) |
| 241 | +SELECT TRUNC(SYSDATE, 'IW') + 7 - 1 FROM DUAL; |
| 242 | +-- 获取当月开始时间和结束时间 |
| 243 | +SELECT TRUNC(SYSDATE, 'MM') FROM DUAL |
| 244 | +SELECT TRUNC(LAST_DAY(SYSDATE))+ 0.99999 FROM DUAL |
| 245 | +-- 获取今年开始时间和结束时间 |
| 246 | +SELECT TO_CHAR(TRUNC(SYSDATE, 'YYYY'), 'YYYY-MM-DD HH24:MI:SS') AS start_date, |
| 247 | + TO_CHAR(LAST_DAY(TRUNC(SYSDATE, 'YYYY') + 0.99999), 'YYYY-MM-DD HH24:MI:SS') AS end_date |
| 248 | +FROM dual; |
| 249 | +SELECT TO_DATE(EXTRACT(YEAR FROM SYSDATE) || '-01-01', 'YYYY-MM-DD HH24:MI:SS') AS start_date, |
| 250 | + TO_DATE(EXTRACT(YEAR FROM SYSDATE) || '-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS') AS end_date |
| 251 | +FROM dual; |
| 252 | +SELECT TRUNC(SYSDATE, 'YYYY') AS start_date, |
| 253 | + TRUNC(SYSDATE + INTERVAL '1' YEAR, 'YYYY') - INTERVAL '1' SECOND AS end_date |
| 254 | +FROM dual |
| 255 | +-- FM格式模型来实现不要前导零 |
| 256 | +SELECT TO_CHAR(SYSDATE, 'FMMM') AS one_digit_month |
| 257 | +FROM dual; |
| 258 | + |
| 259 | + |
| 260 | +-- 获取倒推时间列表 |
| 261 | +SELECT TRUNC(sysdate - NumToDSInterval(level-1, 'hour'), 'MI') AS ds -- 'day','hour','minute','second' |
| 262 | +, TRUNC(sysdate - NumToYMInterval(level-1, 'month'), 'MI') AS ym -- 'year','month' |
| 263 | +FROM dual CONNECT BY level <= 12; |
| 264 | + |
| 265 | +SELECT TO_CHAR(Add_Months(TRUNC(sysdate,'YYYY'), Level-1), 'FMMonth') AS month_name FROM Dual CONNECT BY Level <= 12; |
| 266 | +SELECT TRUNC(SYSDATE - LEVEL/24, 'HH24') AS HOURMIN FROM DUAL CONNECT BY LEVEL <= 12 ORDER BY 1; |
| 267 | + |
| 268 | +-- 将数据按半小时进行分组 |
| 269 | +SELECT TO_CHAR(record_date, 'YYYY-MM-DD HH24') || CASE WHEN TO_CHAR(record_date, 'MI') < '30' THEN ':00' ELSE ':30' END AS half_hour, |
| 270 | + SUM(col_8) AS total_money |
| 271 | +FROM table_name |
| 272 | +GROUP BY TO_CHAR(record_date, 'YYYY-MM-DD HH24') || CASE WHEN TO_CHAR(record_date, 'MI') < '30' THEN ':00' ELSE ':30' END |
| 273 | + |
| 274 | +SELECT TRUNC(record_date, 'HH24') + CASE WHEN TO_CHAR(record_date, 'MI') < '30' THEN INTERVAL '0' MINUTE ELSE INTERVAL '30' MINUTE END AS half_hour, |
| 275 | + SUM(col_8) AS total_money |
| 276 | +FROM table_name |
| 277 | +GROUP BY TRUNC(record_date, 'HH24') + CASE WHEN TO_CHAR(record_date, 'MI') < '30' THEN INTERVAL '0' MINUTE ELSE INTERVAL '30' MINUTE END |
| 278 | +``` |
| 279 | + |
| 280 | + |
| 281 | +**随机取数** |
| 282 | + |
| 283 | +```sql |
| 284 | +SELECT * |
| 285 | +FROM test a |
| 286 | +--WHERE rownum = FLOOR(DBMS_RANDOM.VALUE(1, 10)) |
| 287 | +WHERE MOD(rownum, floor(DBMS_RANDOM.VALUE(1, 10))) = 0 |
| 288 | +FETCH FIRST ROW ONLY |
| 289 | + |
| 290 | +-- 重建排序 |
| 291 | +SELECT * FROM ( |
| 292 | + SELECT a.*, rownum as rn |
| 293 | + FROM test a |
| 294 | +) |
| 295 | +WHERE MOD(rn, floor(DBMS_RANDOM.VALUE(1, 1))) = 0 |
| 296 | +ORDER BY dbms_random.value |
| 297 | +FETCH FIRST ROW ONLY; |
| 298 | + |
| 299 | +-- Oracle类PostgreSQL的generate_series函数 |
| 300 | +SELECT ROWNUM AS num FROM dual CONNECT BY ROWNUM <= 3; |
| 301 | +SELECT LEVEL AS num FROM DUAL CONNECT BY LEVEL <= 3; |
| 302 | +-- 使用序列 |
| 303 | +CREATE SEQUENCE seq_num START WITH 1 INCREMENT BY 1 NOMAXVALUE; |
| 304 | +SELECT NEXT VALUE FOR seq_num AS num FROM DUAL WHERE NEXT VALUE FOR seq_num <= 3; |
| 305 | +``` |
| 306 | + |
| 307 | + |
0 commit comments