Oracle技巧查询,很香

使用with复用查询结果集及递归查询

适用于一个复杂SQL中多次使用同一个结果集,但是在数据库中只查询一次。

WITH 
T1 AS (SELECT * FROM EMP),
T2 AS (SELECT * FROM T1 WHERE DEPTNO=10),
T3 AS (SELECT * FROM T2 WHERE SAL>1500)
SELECT * FROM T3

将列转成行

# WM_CONCAT只支持以逗号分隔。 且oracle 12c之后已废除
SELECT WM_CONCAT(DISTINCT dname) FROM dept;  

# LISTAGG无版本限制
SELECT DEPTNO, LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS empnames FROM emp GROUP BY DEPTNO ORDER BY 1; 

# 19c新特性,还支持listagg内部使用distinct去重
SELECT DEPTNO, LISTAGG(DISTINCT ename, ',') WITHIN GROUP (ORDER BY ename) AS empnames FROM emp GROUP BY DEPTNO ORDER BY 1;  

并发执行

SELECT /*+ parallel(d, 8) */ * FROM dept d WHERE 1=1;
SELECT /*+ parallel(d, 8) parallel(e, 8) */ * FROM dept d
	INNER JOIN emp e 
	ON d.deptno=e.deptno
 	WHERE 1=1;
INSERT /*+ parallel(d, 8) */ INTO dept d SELECT * FROM dept1;
DELETE /*+ parallel(d, 8) */ FROM dept d WHERE 1=1;
UPDATE /*+ parallel(d, 8) */ dept d SET dept_stat='1' WHERE 1=1;

表关联更新 MERGE INTO

将表T的某一列值,根据关联条件更新为表S的某一列值

MERGE INTO TARGET_TB1 T USING SOURCE_TB2 S ON (T.ID = S.AID)
WHEN MATCHED THEN UPDATE SET T.COL1 = S.COL2, T.COL2 = S.COL4;

以上SQL等同于

UPDATE TARGET_TB1 T SET (T.COL1, T.COL2)=(SELECT COL2, COL4 FROM SOURCE_TB2 
WHERE AID=T.ID) WHERE T.ID IN (SELECT AID FROM SOURCE_TB2);

此外,MERGE INTO还支持UPDATE同时DELTE和INSERT

MERGE INTO TARGET_TB1 T USING SOURCE_TB2 S ON (T.ID = S.AID)
WHEN MATCHED THEN UPDATE SET T.COL1 = S.COL2, T.COL2 = S.COL4
DELETE WHERE T.ID=123456
WHEN NOT MATCHED THEN INSERT (ID, COL1, COL2, COL3) 
VALUES (S.AID, S.COL2, S.COL4, 'XXX');

组内排序,取组内序号

SELECT empno, ename, deptno, sal, 
ROW_NUMBER () OVER(PARTITION BY deptno ORDER BY sal ASC) 工资排行
FROM emp WHERE 1=1;

组内排序,取组内最大值与最小值

SELECT empno, sal, deptno,
row_number() OVER(PARTITION BY deptno ORDER BY sal ASC)  组内工资排行,
MIN(sal) OVER(PARTITION BY deptno ) 组内最低工资,
MAX(sal) OVER(PARTITION BY deptno ) 组内最高工资
FROM emp 

case when

SELECT empno, ename, deptno, sal, 
CASE WHEN sal<1000 THEN '低'
WHEN sal>1001 and sal<3000 THEN '中'
ELSE '高' END AS 薪资水平,
CASE deptno WHEN 10 THEN '财务科'
WHEN 20 THEN '人事科'
ELSE '打工狗' END AS 部门
FROM emp WHERE 1=1;

日期与时间戳转换

SELECT TO_CHAR(
	(TO_TIMESTAMP('1970-01-01 08:00:00.000000', 'yyyy-MM-dd HH24:MI:SS.ff6') 
		+ START_TM/(1000 * 60 * 60 * 24)), 
	'yyyy-MM-dd HH24:MI:SS')
FROM TBL_TASK;

注:oracle中的除默认是带小数位的,所以这里除了天(1000 * 60 * 60 * 24)之后,还能精确到微秒。

日期与字符串格式转换

SELECT TO_CHAR(sysdate,'YYYYMMDD HH24:MI:SS'),   
TO_DATE('20220417 23:32:32','YYYYMMDD HH24:MI:SS') 
FROM dual;

日期格式说明

格式说明
D一周中的星期几
DAY天的名字,使用空格填充到9个字符
DD月中的第几天
DDD年中的第几天
DY天的简写名
IWISO标准的年中的第几周
IYYYISO标准的四位年份
YYYY四位年份
YYY,YY,Y年份的最后三位,两位,一位
HH小时,按12小时计
HH24小时,按24小时计
MI
SS
MM
Mon月份的简写
Month月份的全名
W该月的第几个星期
WW年中的第几个星期

日期加减

--3分钟前
select sysdate,sysdate - interval '3' MINUTE from dual;
--3小时前
select sysdate - interval '3' hour from dual;
--3天后
select sysdate + interval '3' day from dual;
--按天计算可以直接使用加减号计算   3天后如下
select sysdate + 3 from dual; 
--300天前
select sysdate - 300 from dual;
--3个月后
select sysdate,sysdate + interval '3' month from dual;
select sysdate,add_months(sysdate,3) from dual;
--3*3年前
select sysdate,sysdate - 3*interval '3' year from dual;

锁表处理

--1:查看被锁记录 
SELECT object_name,machine,s.sid,s.serial# 
FROM v$locked_object l,dba_objects o ,v$session s 
WHERE l.object_id = o.object_id AND l.session_id=s.sid 
 
--删除或解锁该记录 
ALTER system KILL SESSION 'sid,serial#';
ALTER system KILL SESSION '1,1212';

--查看连接的进程
SELECT sid, serial#, username, osuser FROM v$session;

--生成杀掉进程SQL
SELECT 'alter system kill session '''||a.sid||','||a.serial#||''';' 
	FROM v$process p,v$session a, v$locked_object b,all_objects c 
	WHERE p.addr=a.paddr AND a.process=b.process 
	AND c.object_id=b.object_id;

查看数据库最近执行的SQL

SELECT t.SQL_TEXT, t.FIRST_LOAD_TIME FROM v$sqlarea t ORDER BY 2 DESC;

NOWAIT锁表查询

--nowait方式查询,获取不到锁时直接报错  
--	ORA-00054:资源正忙,但指定以 NOWAIT 方式获取资源,或者超时失效
SELECT * FROM emp WHERE id=1001 FOR UPDATE NOWAIT;   

WAIT等待指定时间锁表查询

--WAIT方式查询,等待2秒,2秒内获取不到锁时直接报错  
--	ORA-30006:资源已被占用;执行操作时出现 WAIT 超时
--  本次结果测试版本11g
SELECT * FROM emp WHERE id=1001 FOR UPDATE WAIT 2;  

查看oracle版本号

SELECT * FROM v$version;  

DML增删改

INSERT INTO table_name (col1, col2...) VALUES (value1, value2...);
INSERT INTO table_name    VALUES (value1, value2...);
UPDATE table_name SET col1=222,col2=333 WHERE condition;
DELETE FROM tablename WHERE condition;

DDL增删改

ALTER TABLE table_name MODIFY col_name null;
ALTER TABLE table_name RENAME COLUMN col_name1 TO col_name2;
ALTER TABLE table_name DROP COLUMN col_name;
--drop多列
ALTER TABLE table_name DROP (col1_name, col2_name, col3_name);
ALTER TABLE table_name ADD (col_name VARCHAR(10));
ALTER TABLE table_name MODIFY (col_name VARCHAR2(16));

CREATE TABLE table_name (
        col_name NUMBER(2) NOT NULL,
        col2_name VARCHAR2(14),
        col3_name VARCHAR2(13),
        CONSTRAINT pk_table PRIMARY KEY (col_name)
    );

索引

CREATE UNIQUE INDEX idx_name ON table_name (col_name DESC, col_name2, col_name3);

数据库操作

database dbname

按月统计日均余额SQL

SQL作用是按月统计日均余额

WITH 
T AS
(SELECT '001' ACC, TO_DATE('2022/8/18', 'yyyy/mm/dd') START_DT, 100 BAL_AMT FROM DUAL
  UNION ALL SELECT '001', TO_DATE('2022/10/3', 'yyyy/mm/dd'), 200 FROM DUAL
  UNION ALL SELECT '001', TO_DATE('2022/10/5', 'yyyy/mm/dd'), 400 FROM DUAL
  UNION ALL SELECT '001', TO_DATE('2022/10/21', 'yyyy/mm/dd'), 100 FROM DUAL
  UNION ALL SELECT '002', TO_DATE('2022/10/6', 'yyyy/mm/dd'), 500 FROM DUAL
  UNION ALL SELECT '002', TO_DATE('2022/10/8', 'yyyy/mm/dd'), 100 FROM DUAL
  UNION ALL SELECT '002', TO_DATE('2022/10/14', 'yyyy/mm/dd'), 300 FROM DUAL
  UNION ALL SELECT '002', TO_DATE('2022/10/24', 'yyyy/mm/dd'), 100 FROM DUAL),
T1 AS
(SELECT ACC, TO_DATE('2022/10/1', 'yyyy/mm/dd') + LEVEL - 1 START_DT
    FROM (SELECT DISTINCT ACC FROM T)
  CONNECT BY LEVEL <= 31
         AND PRIOR ACC = ACC
         AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL),
T2 AS (SELECT T1.ACC, T1.START_DT, T.BAL_AMT
  FROM T
RIGHT JOIN T1
    ON T.START_DT = T1.START_DT
   AND T.ACC = T1.ACC
UNION ALL
SELECT * FROM T
WHERE START_DT NOT IN (SELECT DISTINCT START_DT FROM T1))

SELECT '2022/10' ver_month, ACC, ROUND(AVG(BAL_AMT), 2) YUE
  FROM (SELECT ACC,
               START_DT,
               NVL(NVL(BAL_AMT,
                       LAST_VALUE(BAL_AMT IGNORE NULLS)
                       OVER(PARTITION BY ACC ORDER BY START_DT)),
                   0) BAL_AMT
          FROM T2
        --ORDER BY 1, 2
        )
WHERE START_DT IN (SELECT DISTINCT START_DT FROM T1)
GROUP BY ACC
ORDER BY 2
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值