ORACLE 中非常有用的语句

工作后才开始接触数据库增删改查的多重复杂场景,学校自学的时候都是小打小闹。记录一下工作中常用的 Oracle 数据库的技巧。

去重:DISTINCT

SELECT DISTINCT TRIM(NET_BUS_NET) FROM ZWR_HST_NET_T

去空格:TRIM

SELECT DISTINCT TRIM(NET_BUS_NET) FROM ZWR_HST_NET_T

截取某一个字符前的值:SUBSTR INSTR

SELECT SUBSTR('AAA-BBB-CCC-DDD', 1, INSTR('AAA-BBB-CCC-DDD', '-', -1)-1) FROM dual

第一个1:从哪一位开始,如果改成3,结果为 A-BBB-CCC-D
INSTR(‘AAA-BBB-CCC-DDD’, ‘-’, -1)-1 : 最后不减去1,则结果为AAA-BBB-CCC- , 所以第一个1和最后的-1决定了结果长度
:括号里面的-1是从后往前数第几个符号,改成1的话结果为 AAA-

实战案例:资源中心函数,ZWRCMD_NetCheck CMDB查询结果网段检查 ——

SELECT DISTINCT SUBSTR(VWA_SRV_IPA, 1, INSTR(VWA_SRV_IPA, '.', -1)) 
FROM ZWR_CMD_VWA_T 

AS后的字段取不到问题-视图问题

SELECT DISTINCT SUBSTR(VWA_SRV_IPA, 1, INSTR(VWA_SRV_IPA, '.', -1)) AS SEG , VWA_PRD_STS, VWA_RUN_STS, VWA_VWA_COD, VWA_VMA_NAM 
FROM ZWR_CMD_VWA_T 
WHERE SUBSTR(VWA_SRV_IPA, 1, INSTR(VWA_SRV_IPA, '.', -1)) != ' ' 
AND TRIM(SUBSTR(VWA_SRV_IPA, 1, INSTR(VWA_SRV_IPA, '.', -1))) NOT IN (SELECT DISTINCT TRIM(NET_BUS_NET) FROM ZWR_HST_NET_T)

前面可以用AS SEG,但是AND 后面接的不能写 SEG NOT IN …

查看ORACLE数据库版本

SELECT * FROM v$version

一张表增加数据时,该表的属性附加表也增加一条数据:MERGE INTO

MERGE INTO ZWR_DAP_ART_T A 
USING (SELECT APP_SVC_COD, APP_APP_NAM  FROM ZWR_DAP_APP_T) B
ON (A.ART_APP_NAM = B.APP_APP_NAM AND A.ART_SVC_COD = B.APP_SVC_COD)
WHEN NOT MATCHED THEN
INSERT (ART_SVC_COD, ART_APP_NAM, ART_DTB_NAM, ART_MOV_TAG, ART_GRY_TAG, ART_ERR_TAG, ART_MNT_DAT, ART_MNT_TIM, ART_RCD_VER, ART_RCD_STS)
VALUES (B.APP_SVC_COD, B.APP_APP_NAM, ' ', ' ', ' ', ' ', 
TO_NUMBER (TO_CHAR (SYSDATE, 'yyyyMMdd')),  TO_NUMBER (TO_CHAR (SYSDATE, 'hh24miss')), '1', 'A');`

用一张表数据去更新领一张表(多行批量更新不能用UPDATE否则会报错“单行子查询返回多个行”):MERGE INTO

MERGE INTO ZWR_DWA_VWA_T A 
USING (SELECT APP_NAM,DIV_NAM ,DIV_RAC, RDD_NBR , DPL_SEQ ,VWA_IPA  FROM APP1.NEWTABLE) B 
ON (A.VWA_VWA_IPA = B.VWA_IPA) 
WHEN MATCHED THEN 
UPDATE SET A.VWA_APP_NAM = B.APP_NAM, A.VWA_DIV_NAM = B.DIV_NAM ,  
A.VWA_DIV_RAC =  B.DIV_RAC, A.VWA_RDD_NBR B.RDD_NBR , A.VWA_APP_SEQ =  B.DPL_SEQ

接上一条,批量更新只能是主动给值

UPDATE APP1.NEWTABLE SET MSG = 'N' WHERE VWA_IPA IN
(SELECT  VWA_IPA FROM ZWR_DWA_VWA_T INNER JOIN APP1.NEWTABLE 
ON VWA_VWA_IPA = VWA_IPA AND VWA_APP_NAM != APP_NAM)

Oracle查看数据库最大连接数与当前连接数

数据库允许的最大连接数

select value from v$parameter where name = 'processes' 

–当前的连接数

select count(*) from v$process 

数据库时间

TO_NUMBER(TO_CHAR(SYSDATE,'yyyymmdd')) #注意用yyyy,小写y表示当天所在的年份,大写YYYY代表week in which year
TO_NUMBER(TO_CHAR(SYSDATE,'hh24miss'))

分页查询

使用ROWNUM的方式进行分页查询,查询页起始记录和结束记录,使用两层嵌套的查询方式

SELECT *
FROM
(
      SELECT ROWNUM RN, T1.*
      FROM (
              SELECT * FROM TRANS_XDT_T
              WHERE TRS_SEQ <= '查询条件'
              ORDER BY TRS_SEQ ASC
      ) T1
      WHERE ROWNUM <= endIndex
)T2
WHERE RN >= beginIndex
ORDER BY T2.TRS_SEQ ASC

使用ROWNUM的方式进行分页查询,查询页起始记录和结束记录,使用一层筛选的查询方式

SELECT *
FROM
(
       SELECT ROWNUM RN, T1.*
       FROM (
               SELECT * FROM TRANS_XDT_T
               WHERE TRS_SEQ <= '查询条件'
               ORDER BY TRS_SEQ ASC
       ) T1
)T2
WHERE RN >= beginIndex AND RN <= endIndex
ORDER BY T2.TRS_SEQ ASC

⭐使用续传键值进行续传查询

SELECT T1.*
FROM (
        SELECT * FROM TRANS_XDT_T
        WHERE TRS_SEQ >= '流水号'
        ORDER BY TRS_SEQ ASC
) T1
WHERE ROWNUM <= N
ORDER BY T1.TRS_SEQ ASC

使用ROWNUM的方式进行分页查询,查询页起始记录和结束记录,使用两层嵌套的查询方式。并通过先读索引,再关联查询其他字段的方式进行优化。

SELECT T4.*
FROM
(
        SELECT T2.TRS_SEQ
        FROM
        (
                SELECT ROWNUM RN, T1.TRS_SEQ
                FROM (
                        SELECT TRS_SEQ
                        FROM TRANS_XDT_T
                        WHERE TRS_SEQ <= '查询条件'
                        ORDER BY TRS_SEQ ASC
                        ) T1
                WHERE ROWNUM <= endIndex
        )T2
        WHERE RN >= beginIndex
) T3
INNER JOIN TRANS_XDT_T T4
ON T3.TRS_SEQ = T4.TRS_SEQ
ORDER BY T4.TRS_SEQ ASC

取前10名,然后给这十条记录排序

SELECT RANK() OVER(ORDER BY OPR_CNT) AS RANK, T.* FROM TABLE ORDER BY T.SORT #这种方式会有并列第一名的情况
SELECT ROW_NUMBER() OVER(ORDER BY OPR_CNT DESC) AS RANK, T.* FROM TABLE ORDER BY T.SORT #这种方式不会有并列第一名的情况,DESC的用处是数量最多的给第一名

ORACLE使用场景甄别

当需要从A表中查出数据放到B表中,一次又要重复查多项时,也就是插入是批量插入时有两种方法,
一、addBatch()然后executeBatch();
二、

INSERT INTO TABLE_A VALUES(...)  
SLECET * FROM TABLE_B 
UNION ALL 
SELECT * FROM TABLE_B

实践证明,用executeBatch的效率比拼接SQL的效率更高,时间缩短了近一倍

ONLINE创建表空间

CREATE INDEX 索引名 ON 表名(字段1, 字段2, 字段3)
TABLESPACE 表空间名称 ONLINE;

HAVING COUNT(字段名)用法

HAVING子句用于在GROUP BY 子句后过滤分组结果。与COUNT函数结合使用,来返回满足特定条件的记录数。
可以用来检查是否有重复数据。

语法格式如下:

SELECT col1, COUNT(col2)
FROM tbl
GROUP BY clo1
HAVING COUNT(col2) > value
ORDER BY col1 DESC;

案例

SELECT BUSI_DATE,CUST_ID
FROM tbl
GROPY BY BUSI_DATE,CUST_ID
HAVING COUNT(1) > 1
ORDER BY BUSI_DATE DESC;

创建同义词

有时候SQL表名前不想加SCHEMA,就可以创建同义词。这样有个好处就是简便,但是不规范。对数据库执行SQL他能找到特定的表。但是对于多个SCHEMA下有同名表的就会有问题了,不一定就调用到哪个标了。
这里的场景是为了接入SQL治理平台,怕有些SQL表名前不一定添加了属主引用,为了保证只读用户能正常解析SQL执行计划,需要给各表都创建公共同义词。
先用数据库管理员用户查出哪些表没有公共同义词,并拼装创建公共同义词的SQL。

SELECT
	'CREATE PUBLIC SYNONYM '||T.TABLE_NAME||' FOR '||T.OWNER||'.'||T.TABLE_NAME||';'
FROM
	SYS.ALL_TABLES T 
WHERE
	T.OWNER IN (‘owner_name1’,’owner_name2’,...) -- 这里替换为要监控的owner列表
	AND T.TABLE_NAME NOT IN (
SELECT
	S.TABLE_NAME 
FROM
	SYS.ALL_SYNONYMS S 
WHERE
	S.OWNER = 'PUBLIC' 
	AND S.TABLE_OWNER = T.OWNER);

再用数据库管理员用户执行查询结果,创建公共同义词。创建后,再次执行上面的SQL检查,查询结果应该为空。
后面新增的表,发布到生产时,同样需按CREATE PUBLIC SYNONYM synonym_name FOR owner_name.table_name的格式,创建公共同义词。

我先创建了一波,结果查询发现有多个SCHEMA下同名的表,所以检查了下是不是这个问题:

SELECT * 
  FROM SYS.ALL_SYNONYMS S
 WHERE S.OWNER='PUBLIC' 
   AND S.TABLE_NAME = '这里输入执行有报错说名称已被占用的表名,需大写,如果有多个表,=的条件改成in的条件'

发现确实查出了两条记录,RDMODS和RDMEDW下有同名的,为了安全起见,这样的同义词要删掉,避免不知情的同学不写属主导致调错表:
删除同义词

SELECT 'DROP PUBLIC SYNONYM '||S.SYNONYM_NAME||';'
  FROM SYS.ALL_SYNONYMS S
 WHERE S.SYNONYM_NAME 
    IN (SELECT T.TABLE_NAME  FROM SYS.ALL_TABLES T GROUP BY TABLE_NAME HAVING COUNT(*)>=2)

NOT IN会把NULL值一起过滤

如果一个表中有A, B, C,NULL四种数据,那么NOT IN (‘A’, ‘B’) 只会把C查出,NULL那条数据不会被查出来

Oracle查询表空间使用情况

查询表空间使用情况可以通过以下代码实现:

SELECT segment_name "表名",
       segment_type "对象类型",
       sum(bytes) / 1024 / 1024 "占用空间MB"
  FROM dba_extents
 GROUP BY segment_name, segment_type

通过以上代码,可以得到每个表空间包含的数据文件所占用的文件名、字节数、块数和最大字节数。

回收水位线

DBA提供:
select 'alter table '||owner||'.'||table_name||' enable row movement;' from dba_tables WHERE table_name  in ('TIF_VOUCHINFO','TPORTHOLD','TPORTVALUE','TPORTCURRENTS','TIF_GZB');
 
select 'alter table '||owner||'.'||table_name||' move;' from dba_tables where table_name in ('TIF_VOUCHINFO','TPORTHOLD','TPORTVALUE','TPORTCURRENTS','TIF_GZB') and partitioned='NO';
 
select 'alter table '||table_owner||'.'||table_name||' move partition '||partition_Name||' ;' from dba_tab_partitions
where table_name in (select table_name from dba_tables where table_name in ('TIF_VOUCHINFO','TPORTHOLD','TPORTVALUE','TPORTCURRENTS','TIF_GZB') and partitioned='YES');
 
select 'alter table '||owner||'.'||table_name||' disable row movement;' from dba_tables WHERE table_name  in ('TIF_VOUCHINFO','TPORTHOLD','TPORTVALUE','TPORTCURRENTS','TIF_GZB');
 
 
=====================================
 
-- 回收高水位线
SELECT owner
, TABLE_NAME 表名
, NUM_ROWS 表实际数据条数
, ROUND(AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9) 表需要存储空间MB
, ROUND(BLOCKS*8/1024) 表实际存储空间MB
, ROUND((BLOCKS*8/1024-AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9)) RECOVER_MB
FROM dba_tables
WHERE BLOCKS*8/1024-AVG_ROW_LEN*NUM_ROWS/1024/1024/0.9 > 1
AND OWNER IN ('SCHEMA名')
order by RECOVER_MB desc;
 
-- 查询需要回收的高水位表
SELECT OWNER,
       TABLE_NAME,
       ROUND ( (BLOCKS * 8) / 1024, 2) "HIGH_WATER(MB)",
       ROUND ( (NUM_ROWS * AVG_ROW_LEN / 1024) / 1024, 2) "USED_SPACE(MB)",
       ROUND ( (BLOCKS * 10 / 100) * 8 / 1024, 2) "RESERVE_SPACE(MB)",
       ROUND ( (BLOCKS * 8 - (NUM_ROWS * AVG_ROW_LEN / 1024) - BLOCKS * 8 * 10 / 100) /1024 , 2) "RECOVERY_SPACE(MB)",
       DECODE (NVL((BLOCKS * 8),0), 0, 0, ROUND ( (1 - (NUM_ROWS * AVG_ROW_LEN / 1024)/(BLOCKS * 8)) * 100 ,0)) "PERCENT(%)" --一般超过20%就需要回收了
  FROM DBA_TABLES
 WHERE OWNER IN ('ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL', 'RDMODS', 'RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA')
 --AND TABLE_NAME = '表名'  
   AND ROUND ( (BLOCKS * 8) / 1024, 2) > 1024 -- 只查出超过1G数据量的
 ORDER BY "PERCENT(%)" DESC;
 
--a) 启动行迁移:
ALTER TABLE 表名 ENABLE ROW MOVEMENT;
--b)进行表的收缩:
ALTER TABLE 表名 MOVE;
--c)关闭行迁移
ALTER TABLE 表名 DISABLE ROW MOVEMENT;
 
--blocks字段和有数据的字段对比,用1减,求出没有数据的块的百分比(一般超过20%就需要回收了)
select round((1-a.used/b.num_total)*100,0)  percent from
(SELECT COUNT (DISTINCT SUBSTR(rowid,1,15)) Used FROM 表名) a,
(select blocks num_total from dba_tables where table_name='表名' and owner='SCHEMA名') b;
 
-- 重新分析(如果表数据大要谨慎执行,时间会很久)
ANALYZE TABLE 表名 COMPUTE STATISTICS;
 
-- 重建索引
alter INDEX 索引名 REBUILD;

权限

--赋予表权限
GRANT SELECT ON table_name FROM user;
--收回表访问权限
REVOKE SELECT ON table_name FROM user;
--收回视图访问权限
REVOKE SELECT ON view_name TO user;

权限

-- ==================== 创建一个只读用户给其他平台 ======================
-- 创建用户密码
CREATE USER dgp_reader IDENTIFIED BY 密码;

-- 赋予该用户连接到数据库的权限
GRANT CONNECT TO dgp_reader;

-- 将查询任何表的权限授予用户 'dgp_reader'
GRANT SELECT ANY TABLE TO dgp_reader;

-- 授予权限,包括对系统表的访问
GRANT SELECT ANY DICTIONARY TO dgp_reader;

-- ==================== 创建一个只支持表增删改查业务表、修改存储过程和函数的用户APP1 ======================
-- 创建用户密码
CREATE USER APP1 IDENTIFIED BY 密码;

-- 赋予该用户连接到数据库的权限
GRANT CONNECT TO APP1;

-- 将查询任何表的权限授予用户 'APP1'
GRANT SELECT ANY TABLE TO APP1;

-- 删除用户
--DROP USER APP1 CASCADE;


SELECT * FROM V$SESSION 
WHERE USERNAME IS NOT NULL 
AND USERNAME NOT IN ('ZABBIX') 
AND STATUS = 'ACTIVE' 
AND MODULE NOT IN ('dataflow.exe') ;

-- 表
BEGIN
    FOR t IN (SELECT OWNER, table_name FROM DBA_TABLES 
               WHERE OWNER  NOT IN ('SYS', 'SYSTEM', 'WMSYS', 'EXFSYS', 'APPQOSSYS','OUTLN', 'DBMGR', 'DBSNMP', 'XDB')
               ) LOOP
        EXECUTE IMMEDIATE 'GRANT SELECT, INSERT, UPDATE, DELETE ON ' || T.OWNER || '.' || t.table_name || ' TO APP1';
    END LOOP;
END;

-- 存储过程,这样循环有的编译报错的就过不去。我是直接全量给权限
GRANT CREATE ANY PROCEDURE,ALTER ANY PROCEDURE to APP1;
-- 下面这样循环会报错
BEGIN
    FOR t IN (SELECT OWNER,OBJECT_NAME FROM DBA_PROCEDURES
               WHERE OWNER  NOT IN ('SYS', 'SYSTEM', 'WMSYS', 'EXFSYS', 'APPQOSSYS','OUTLN', 'DBMGR', 'DBSNMP', 'XDB')
                 AND OBJECT_TYPE = 'PROCEDURE' 
               ) LOOP
        EXECUTE IMMEDIATE 'GRANT EXECUTE ON ' || T.OWNER || '.' || t.OBJECT_NAME || ' TO APP1';
    END LOOP;
END;

-- 执行函数的权限
BEGIN
    FOR t IN (
              SELECT DISTINCT OWNER, NAME
                FROM DBA_SOURCE
               WHERE OWNER  NOT IN ('SYS', 'SYSTEM', 'WMSYS', 'EXFSYS', 'APPQOSSYS','OUTLN', 'DBMGR', 'DBSNMP', 'XDB')
                 AND TYPE = 'FUNCTION') LOOP
        EXECUTE IMMEDIATE 'GRANT EXECUTE ON ' || T.OWNER || '.' || t.NAME || ' TO APP1';
    END LOOP;
END;

--赋予创建函数权限
GRANT CREATE FUNCTION TO APP1;

--赋予视图权限
GRANT SELECT ON RDMEDW.V_CRD_DAILY_REPORT TO APP1;
--如果报错RDMDDW.H22_CRD_GUARANTEE_RATIO 不是可授予的对象,就执行下列语句
GRANT SELECT ON RDMDDW.H22_CRD_GUARANTEE_RATIO TO RDMEDW WITH GRANT OPTION;
-- ============================== OKR统计用 ==============================

-- 信用
'ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL', 'RDMODS', 'RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA'

-- 集市
'ETL', 'PTCONFIG', 'PTDATA', 'RDMADI', 'RDMDDW', 'RDMDROP', 'RDMEDW' , 'RDMETL', 'RDMODS', 'RPCONFIG', 'RPDATA'

-- 流动性
'ETL', 'LMCONFIG', 'LMDATA', 'RDM', 'RDMDDW', 'RDMEDW', 'RDMODS' , 'RPCONFIG', 'RPDATA'

-- 有注释的字段数量
SELECT COUNT(*) FROM ( 
   SELECT a.OWNER , a.table_name, a.comments, b.column_name, a.comments 
     FROM dba_tab_comments a
LEFT JOIN dba_col_comments b 
       ON a.table_name = b.table_name
    WHERE a.table_type = 'TABLE' 
      AND a.comments IS NOT NULL
      AND a.OWNER IN ('ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL','RDMODS','RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA')
    );
    
-- 总的的字段数量
SELECT COUNT(*) FROM ( 
   SELECT a.OWNER , a.table_name, a.comments, b.column_name, a.comments 
     FROM dba_tab_comments a
LEFT JOIN dba_col_comments b 
       ON a.table_name = b.table_name
    WHERE a.table_type = 'TABLE' 
      AND a.OWNER IN ('ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL','RDMODS'
    ,'RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA')
    );

-- 有表注释的表数量
SELECT COUNT(*) FROM ( 
SELECT a.OWNER , a.table_name, a.comments
     FROM dba_tab_comments a
    WHERE a.table_type = 'TABLE' 
      AND a.comments IS NOT NULL 
      AND a.OWNER IN ('ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL','RDMODS'
    ,'RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA')
);

-- 总的表数量
SELECT COUNT(*) FROM ( 
SELECT a.OWNER , a.table_name, a.comments
     FROM dba_tab_comments a
    WHERE a.table_type = 'TABLE' 
      AND a.OWNER IN ('ETL', 'ICRCONFIG', 'ICRDATA', 'ICREDIT_CONFIG', 'ICREDIT_DATA', 'RDMDDW', 'RDMEDW', 'RDMETL','RDMODS'
    ,'RISKCONFIG', 'RISKDATA', 'RPCONFIG', 'RPDATA')
);

DB LINK

--查看DBLINK链接信息
SELECT * FROM DBA_DB_LINKS;

--创建语句
CREATE PUBLIC DATABASE LINK XYFX CONNECT TO WOLF  IDENTIFIED BY wolf USING '(DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = TCP)(HOST = 172.24.155.166 )(PORT = 1521))
    )
    (CONNECT_DATA =
      (SERVICE_NAME = ncrms)
    )
)';

-- 删除DBLINK
DROP PUBLIC DATABASE LINK LINK_NAME;

-- 查询语句
SELECT * FROM ICRCONFIG.T_INDUSTRY_INFO@XYFX 

索引

-- 查询索引最后分析的时间
  SELECT *
    FROM DBA_INDEXES
   WHERE LAST_ANALYZED IS NOT NULL
ORDER BY LAST_ANALYZED DESC;

-- 查询索引创建的时间
   SELECT * 
    FROM DBA_OBJECTS 
   WHERE OBJECT_TYPE='INDEX'
     AND OBJECT_NAME NOT LIKE 'SYS%'
ORDER BY CREATED DESC;

存储过程

DECLARE 
RETURN_MESSAGE VARCHAR2(2000);
RETURN_CODE NUMBER;
BEGIN
	ICRCONFIG.P_PRO_STOCK_BALANCE_O32('20240402', RETURN_MESSAGE, RETURN_CODE);
END;
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值