Skip to content

Commit 70ee1c4

Browse files
author
bajins
committed
docs: update database related documentation and add new RDBMS guides
- 更新关系型数据库文档,增加主流数据库对比内容 - 添加 Oracle 数据库使用指南 - 添加 PostgreSQL 数据库使用指南 - 更新其他相关技术文档
1 parent d02834c commit 70ee1c4

20 files changed

+872
-568
lines changed

DBS/Oracle.md

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
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

Comments
 (0)