当前位置:   article > 正文

Oracle Insert All、merge into 批量新增与修改、regexp_like 、regexp_replace 正则、with as 虚拟视图

insert all

目录

Oracle Insert All 批量插入

oracle merge into 合并新增与更新

regexp_like 正则匹配

regexp_replace 正则替换

with as 虚拟视图


脚本:部门及其his与log表

Oracle 函数官网文档:https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm

Oracle Insert All 批量插入

1、假如需要将 dept 的数据备份到 dept_his 和 dept_log 表,最简单的方式如下所示,然后它并不严谨,特别是在生产上的时候,因为在第一次 Insert 的时候,可能 dept 表中的数据已经发生了变化,从而导致 his 和 log 表并不一样。

  1. insert into dept_his(deptno,dname,loc) select deptno,dname,loc from dept;
  2. insert into dept_log(deptno,dname,loc) select deptno,dname,loc from dept;

2、Oracle 的 insert all 用于把同一批数据插入到不同的表中。

3、insert first 与 insert all 支持 when then 条件插入,都会对 select 的每一行结果判断是否满足条件。

  1. insert first:对于每一行数据,只插入到第一个 when 条件成立的表,不继续检查其他条件。
  2. insert all:对于每一行数据,对每一个 when 条件都进行检查,如果满足条件就执行插入操作。

4、insert all 多表插入限制条件:

  1. 1. 只能对表执行多表插入语句,不能对视图或物化视图执行;
  2. 2. 不能对远端表执行多表插入语句;
  3. 3. 不能使用表集合表达式;
  4. 4. 不能超过999个目标列;
  5. 5. 在RAC环境中或目标表是索引组织表或目标表上建有BITMAP索引时,多表插入语句不能并行执行;
  6. 6. 多表插入语句不支持执行计划稳定性;
  7. 7. 多表插入语句中的子查询不能使用序列。

示例1:将 dept 的数据备份新增到 his 和 log 表

  1. -- 将 dept 的数据备份新增到 his 和 log
  2. -- 对于 select 的每一行结果都会 into 到每张目标表中, into 后面没有写 values,此时 select 的列相当于 values
  3. insert all
  4. into dept_his(deptno,dname,loc)
  5. into dept_log(deptno,dname,loc)
  6. select deptno,dname,loc from dept;

示例2:insert first 与 insert all 的用法区别

  1. -- 将部门编码小于30的数据备份新增到 his 表; 大于等于30且小于60的备份新增到log
  2. -- 对于 select 的每一行结果进行 when 条件匹配,匹配上,则进入子块,且不继续往后判断,直接进入下一条数据
  3. -- 当 select 查询的列和 into 目标表的列一致时,则都可以省略,否则需要明确指定,values 获取的值来自 select
  4. insert first
  5. when deptno <30 then
  6. into dept_his
  7. when deptno < 60 then
  8. into dept_log
  9. select * from dept;
  10. -- 将部门编码小于30的数据备份新增到 his 表; 小于60的备份新增到log
  11. -- 对于 select 的每一行结果进行 when 条件匹配,匹配上,则进入子块,且继续往后判断剩余的 when 条件
  12. -- 当 select 查询的列和 into 目标表的列一致时,则都可以省略,否则需要明确指定,values 获取的值来自 select
  13. insert all
  14. when deptno <30 then
  15. into dept_his(deptno,dname,loc) values(deptno,dname,loc)
  16. when deptno < 60 then
  17. into dept_log(deptno,dname) values (deptno,dname)
  18. select deptno,dname,loc from dept;

示例3:批量新增插入(多用于程序中)

  1. -- 批量新增插入
  2. -- select 查询有几条结果,则全部 into 执行几次,此时 values 不再从 select 中取值
  3. insert all
  4. into dept_his(deptno,dname,loc) values(1,'预算','北京')
  5. into dept_his(deptno,dname,loc) values(2,'支付','上海')
  6. into dept_his(deptno,dname,loc) values(3,'指标','深圳')
  7. select 1 from dual;

merge into 合并新增与更新

1、merge into 合并语法如下:

  1. MERGE INTO target_table A USING source_table B ON search_condition
  2. WHEN MATCHED THEN
  3. UPDATE SET A.col1 = B.col1, A.col2 = B.col2,... WHERE xxx [DELETE WHERE]
  4. WHEN NOT MATCHED THEN
  5. INSERT (A.col1,A.col2,...) values(B.value1,B.value2,...) WHERE xxx;

2、merge into 执行过程:对于 source_table(来源表) 中的每一条记录,结合 target_table(目标表) 判断该记录是否满足 search_condition 条件,如果满足:则执行 MATCHED 部分的 update 更新语句;如果不满足:则执行 NOT MATCHED 部分的 insert 新增语句;

3、merge into 注意事项

3.1、on 条件必须唯一定位来源表中单条记录,即目标表的记录在来源表中最多只能有1条数据匹配,否则报错:ORA-30926:无法在源表中获得一组稳定的行。

目标表与来源表可以多对一,但是绝不能一对多。

3.2、update 不能更新 ON 条件子句中引用的列,即目标表在 on 条件中使用了的字段,都不能再进行更新操作。

4、update 语句可以指定一个可选的带 where 条件的 delete 语句,用来删除目标表中符合  search_condition,且在 update 操作之后,满足 delete where 条件的数据。

示例1:合并更新与插入

  1. -- 将部门表 dept 中编号大于20的数据备份到 deot_his 历史表,已经存在时更新,不存在时新增.
  2. -- MATCHED THEN 与 NOT MATCHED THEN 可以同时存在,也可以单独存在
  3. MERGE INTO dept_his A
  4. USING (SELECT * FROM dept t where t.DEPTNO > 20) B
  5. ON (A.deptno = B.deptno)
  6. WHEN MATCHED THEN
  7. UPDATE SET A.dname = B.dname, A.loc = B.loc
  8. WHEN NOT MATCHED THEN
  9. INSERT (A.deptno, A.dname, A.loc) VALUES (B.deptno, B.dname, B.loc);

示例2:合并更新并删除

  1. -- 将部门表 dept 的数据更新到 his 表,如果更新后的部门名称是以 'S' 开头,则删除 his 表中的此条数据
  2. MERGE INTO dept_his A USING dept B ON (A.deptno = B.deptno)
  3. WHEN MATCHED THEN
  4. UPDATE SET A.dname = B.dname, A.loc = B.loc DELETE WHERE A.Dname like 'S%';

示例3:无条件 insert

  1. -- 将部门编码大于20的数据全部备份插入到 his 表,因为 1=0 条件不成立,所以来源表中的每条数据都将插入到 his 表
  2. -- 如果 values 中的列与目标表一致,则 insert 后面的列可以省略不写
  3. MERGE INTO dept_his A USING (SELECT T.* FROM dept t where t.deptno > 20) B ON (1=0)
  4. WHEN NOT MATCHED THEN
  5. INSERT VALUES (B.deptno, B.dname, B.loc);

示例4: where 条件过滤说明,USING 左侧的目标表、右侧的来源表都可以在 on 过滤前先带条件进行过滤,然后 on 条件中可以继续带条件过滤,最后 UPDATE、INSERT 语句的后面也可以带条件过滤。原则就是尽量提前缩小结果集,为后续操作减去压力,能提起带条件过滤的,尽量提起过滤。

  1. -- 将 emp 表中部门号大于 20,且薪水小于 3k的员工,奖金加上 100元.
  2. -- 方式1-推荐
  3. MERGE INTO (SELECT T.* FROM emp t where t.sal < 3000) E USING (SELECT d.deptno FROM dept d where d.deptno > 20) B
  4. ON (e.deptno = b.deptno) WHEN MATCHED THEN UPDATE SET e.comm = nvl(e.comm, 0) + 100;
  5. -- 方式2
  6. MERGE INTO emp e USING dept B ON (e.sal < 3000 and B.deptno > 20 and e.deptno = b.deptno)
  7. WHEN MATCHED THEN UPDATE SET e.comm = nvl(e.comm, 0) + 100;
  8. -- 方式3
  9. MERGE INTO emp e USING dept B ON (e.deptno = b.deptno)
  10. WHEN MATCHED THEN UPDATE SET e.comm = nvl(e.comm, 0) + 100 where b.deptno > 20 and e.sal < 3000;

sql/oracle/merge into 同表不同条件更新.sql。

sql/oracle/merge into 多条件批量更新.sql。

regexp_like 正则匹配

1、REGEXP_LIKE 函数语法:REGEXP_LIKE (expression, pattern [, match_parameter])

2、参数 expression:字符表达式,例如列或字段。可以是 VARCHAR2,CHAR,NVARCHAR2,NCHAR,CLOB 或 NCLOB 数据类型。

3、参数 pattern:正则表达式匹配信息,这与前端 JS 还是后台 Java 的正则规则是一样的。Java SE 正则表达式 API Pattern 与 Matcher._蚩尤后裔的博客-CSDN博客

4、参数 match_parameter - 可选:允许修改 REGEXP_LIKE 条件的匹配行为。可以是以下的组合:

描述
'c'执行区分大小写匹配。
'i'执行不区分大小写的匹配。
'n'允许句点字符(.)与换行符匹配。 默认情况下,句点是通配符。
'm'表达式假定有多个行,其中^是行的开始,$是行的结尾,不管表达式中这些字符的位置如何。默认情况下,表达式假定为单行。
'x'忽略空格字符。默认情况下,空格字符与任何其他字符一样匹配。

5、常用内置规则:

规则描述规则描述
[[:alpha:]]任何字母,包括中文[[:space:]]包括换行符、空格、tab在内的任何空白字符
[[:digit:]]任何数字[[:upper:]]任何大写字母
[[:alnum:]]任何字母和数字[[:lower:]]任何小写字母
[[:punct:]]任何标点符号,如 ,.?’[[:xdigit:]]任何16进制的数字,相当于[0-9a-fA-F]
[:blank:]空格和tab[:cntrl:]控制字符,ctrl、backspace等

6、常用操作:

  1. -- 查询 emp 表中以 F开头后面跟着 1-3 位数字的列信息
  2. select * from user_tab_columns where table_name = 'EMP' AND REGEXP_LIKE(COLUMN_NAME, '^F\d{1,3}$');
  3. -- 查询表名中含有数字的表
  4. SELECT T.* FROM user_tables t where regexp_like(t.TABLE_NAME, '[[:digit:]]');
  5. -- 查询员工姓名以'S'开头,'H'结束的记录并且长度是5位
  6. select * from emp t where regexp_like(t.ename,'^S...H$');
  7. -- 查询员工姓名以'K'开头,后面跟着的大写字母不超过1到3位
  8. select * from emp t where regexp_like(t.ename,'^K[A-Z]{1,3}$');
  9. -- 查询员工姓名以'J'开头,'S'结束、中间3位大写字母
  10. select * from emp where regexp_like(ename,'^J[A-Z]{3}S$');
  11. -- 使用字符集实现: [[:upper:]] 任何大写字母
  12. select * from emp where regexp_like(ename,'^J[[:upper:]]{3}S');
  13. -- 查询value中不是纯数字的记录
  14. select * from emp t where not regexp_like(t.ename,'^[[:alnum:]]+$');
  15. -- 查询value中不包含任何数字的记录。
  16. select * from fzq where regexp_like(value,'^[^[:digit:]]+$');
  17. --查询以12或者1b开头的记录.不区分大小写。
  18. select * from fzq where regexp_like(value,'^1[2b]','i');
  19. --查询以12或者1b开头的记录.区分大小写。
  20. select * from fzq where regexp_like(value,'^1[2B]');
  21. -- 查询数据中包含空白的记录。
  22. select * from fzq where regexp_like(value,'[[:space:]]');
  23. --查询所有包含小写字母或者数字的记录。
  24. select * from emp t where regexp_like(t.ename,'^([A-Z]+|[0-9]+)$');
  25. --查询任何包含标点符号的记录。
  26. select * from fzq where regexp_like(value,'[[:punct:]]');

示例1:如果新增的是暂存数据,且证件号码长度是 15、18位,则入库前自动进行解密

regexp_replace 正则替换

1、regexp_replace 正则替换函数用于通过正则表达式来进行匹配替换,默认情况下,每次匹配到的正则,都替换为 replace_string,返回的字符串与 source_char 字符集相同。如果source_char为非LOB类型,则返回varchar2数据类型,如果为LOB类型,则返回CLOB类型,该函数符合POSIX正则和Unicode正则。

2、格式regexp_replace(source_char,pattern,replace_string,position,occurrence,match_parameter);

参数说明
source_char被搜索的字符列或者字符值,数据类型如 CHAR、VARCHAR2、NCHAR、NVARCHAR2、CLOB、NCLOB
pattern

正则表达式,最多可包含512个字节。

如果pattern数据类型与source_char不同,则将转换pattern的数据类型与source_char的一致。

replace_string

替换的值,数据类型如 CHAR、VARCHAR2、NCHAR、NVARCHAR2、CLOB、NCLOB。

如果是CLOB或NCLOB类型,则自动截断为32K。
可含有多达500个反向引用作为子表达式,其形式为\n,n为数字1~9。
如果n在replace_string中为反斜线字符,则需使用转移字符在其前面(\)。

position表示在source_char中开始搜索的索引位置,正整数,默认值为1,表示从第一个字符开始搜索。
occurrence表示替换动作的发生,非负整数,如果为0,则将替换所有匹配项,如果为正整数n,则Oracle将替换第n个匹配项。
match_parameter匹配行为,上面 regexp_like 中有介绍。
  1. -- 中国 替换为 Chinese:Chinese人民说Chinese话,会Chinese功夫
  2. -- 此时和 replace 效果一样
  3. select regexp_replace('中国人民说中国话,会中国功夫', '中国', 'Chinese') from dual;
  4. -- 将xxx.xxx.xxxx格式的号码重新格式化为(xxx)xxx-xxxx
  5. -- 其中.是特殊字符,需要转义
  6. -- 输出:(515) 123-4567
  7. SELECT REGEXP_REPLACE('515.123.4567', '([[:digit:]]{3})\.([[:digit:]]{3})\.([[:digit:]]{4})', '(\1) \2-\3') "美国座机"
  8. FROM dual;
  9. -- 检查字符串,查找两个或多个空格。Oracle将每次出现的两个或多个空格替换为一个空格。
  10. -- 输出:500 Oracle Parkway, Redwood Shores, CA
  11. SELECT REGEXP_REPLACE('500 Oracle Parkway, Redwood Shores, CA', '( ){2,}', ' ') "REGEXP_REPLACE" FROM DUAL;
  12. -- 将全部的数字替换为 *:太宗*****abcde*****
  13. select regexp_replace('太宗01234abcde56789', '[0-9]', '*') a,
  14. regexp_replace('太宗01234abcde56789', '[[:digit:]]', '*') b
  15. from dual;
  16. -- 去掉其中的全部字母:高宗0123456789。
  17. select regexp_replace('高宗01234abcde56789ABC。', '[a-zA-Z]') a,
  18. regexp_replace('高宗01234abcde56789ABC。', '[[:upper:]]|[[:lower:]]') b
  19. from dual;
  1. -- 使用括号可以取值
  2. -- ’+'在正则里有定义,需转义
  3. -- 输出:(+86)0738-786531 138-1111-2222
  4. select regexp_replace('+86 0738786531',
  5. '(\+[0-9]{2})( )([0-9]{4})([0-9]{1,9})',
  6. '(\1)\3-\4') as "座机号",
  7. regexp_replace('13811112222',
  8. '([0-9]{3})([0-9]{4})([0-9]{4})',
  9. '\1-\2-\3') as "手机号"
  10. from dual;
  11. -- 将字符用空格分隔
  12. -- 输出:高 祖 0 1 2 3 4 a b c d e
  13. select regexp_replace('高祖01234abcde', '(.)', '\1 ') from dual;
  14. --从第8个值开始(包含自己),将所有数字、大/小写字母替换为*
  15. --输出:1867388****
  16. select regexp_replace('18673886425','[0-9a-zA-Z]','*',8) as new_str from dual;
  17. -- 通过i参数,不区分大小写进行匹配
  18. -- 将全部字母替换为 *,输出:中国*******12345.
  19. select regexp_replace('中国abcdefg12345.', '[A-Z]', '*', 1, 0, 'i') from dual;
  20. -- 通过n参数使 ’ . ’ 可以匹配换行符,实现合并
  21. select regexp_replace('a
  22. b
  23. c',
  24. '([a-z])(.)', '\1', 1, 0, 'n')
  25. from dual;
  26. -- 第一条,匹配的是 ‘a a, 第二条,匹配的是 ‘aa’
  27. -- 输出:a0 a bb b b 0 a a bb b b
  28. select regexp_replace('aa a a bb b b', 'a a', '0') a,
  29. regexp_replace('aa a a bb b b', 'a a', '0', 1, 0, 'x') b
  30. from dual;
  1. -- 替换手机号码的中间4位,输出:186****6425
  2. select regexp_replace(
  3. regexp_replace(
  4. regexp_replace(
  5. regexp_replace('18687976425','.','*',4,1)
  6. ,'.','*',4,2)
  7. ,'.','*',4,3)
  8. ,'.','*',4,4) as new_str from dual;
  9. -- -- 替换手机号码的中间4位,输出:186****6425
  10. SELECT substr(regexp_replace('18687976425', '.', '*', 4), 1, 7) || substr('18687976425', 8, 11) FROM dual;

with as 虚拟视图

1、with table as 是Oracle 9i新增语法,用于将查询中公共部分提取出来为虚拟视图,访问虚拟视图减少对原始表的io操作,从而达到优化性能和语法清晰的作用,'一次解析,多次使用'。

  1. -- 示例1:一次解析,多次使用
  2. -- 注意1:with as 语句最后面不能加分号,否则报错:ORA-00928: 缺失 SELECT 关键字
  3. -- 注意2:不能只定义with..as语句,定义了就必须要使用它,否则报错:ORA-00928: 缺失 SELECT 关键字
  4. with temp as
  5. (select '10001' as province_code from dual)
  6. select case
  7. when (select * from temp) = '10001' then 'equals'
  8. when (select * from temp) = '10002' then 'not equals'
  9. else 'unknown'
  10. end is_equals
  11. from dual;
  12. --示例2:with as 非常适合在 union 语句中
  13. with temp1 as (select 2 sex, '张三' name from dual),
  14. temp2 as (select 1 sex, '李四' name from dual),
  15. temp3 as (select 2 sex, '王五' name from dual)
  16. select * from temp1
  17. union all
  18. select * from temp2
  19. union all
  20. select * from temp3;
  21. --示例3:前面定义的 with..as 语句可以在后面定义的with..as语句使用
  22. with temp1 as (select 2 sex, '张无忌' name from dual),
  23. temp2 as (select 1 sex, '赵敏' name from dual),
  24. temp3 as (select * from temp2)
  25. select * from temp1
  26. union all
  27. select * from temp2
  28. union all
  29. select * from temp3;
  30. --示例4:使用with as语句来创建表
  31. --使用虚拟字段时,新表字段的长度就是虚拟字段建表的时的长度
  32. create table temp as
  33. with temp1 as (select 2 sex, '张三' name from dual),
  34. temp2 as (select 1 sex, '李四' name from dual),
  35. temp3 as (select 2 sex, '敏敏特穆尔' name from dual)
  36. select * from temp1
  37. union all
  38. select * from temp2
  39. union all
  40. select * from temp3;
  41. --示例5:使用with as语句来插入数据
  42. insert into temp
  43. with temp1 as (select 2 sex, '张无忌' name from dual),
  44. temp2 as (select 1 sex, '赵敏' name from dual)
  45. select * from temp1
  46. union all
  47. select * from temp2;

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/806750
推荐阅读
相关标签
  

闽ICP备14008679号