【SQL开发实战技巧】系列(四十四):Oracle12C常用新特性☞你知道吗Oracle新增了类似Mysql的自增列(Identity Columns)功能

系列文章目录

【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事
【SQL开发实战技巧】系列(二):简单单表查询
【SQL开发实战技巧】系列(三):SQL排序的那些事
【SQL开发实战技巧】系列(四):从执行计划讨论UNION ALL与空字符串&UNION与OR的使用注意事项
【SQL开发实战技巧】系列(五):从执行计划看IN、EXISTS 和 INNER JOIN效率,我们要分场景不要死记网上结论
【SQL开发实战技巧】系列(六):从执行计划看NOT IN、NOT EXISTS 和 LEFT JOIN效率,记住内外关联条件不要乱放
【SQL开发实战技巧】系列(七):从有重复数据前提下如何比较出两个表中的差异数据及对应条数聊起
【SQL开发实战技巧】系列(八):聊聊如何插入数据时比约束更灵活的限制数据插入以及怎么一个insert语句同时插入多张表
【SQL开发实战技巧】系列(九):一个update误把其他列数据更新成空了?Merge改写update!给你五种删除重复数据的写法!
【SQL开发实战技巧】系列(十):从拆分字符串、替换字符串以及统计字符串出现次数说起
【SQL开发实战技巧】系列(十一):拿几个案例讲讲translate|regexp_replace|listagg|wmsys.wm_concat|substr|regexp_substr常用函数
【SQL开发实战技巧】系列(十二):三问(如何对字符串字母去重后按字母顺序排列字符串?如何识别哪些字符串中包含数字?如何将分隔数据转换为多值IN列表?)
【SQL开发实战技巧】系列(十三):讨论一下常用聚集函数&通过执行计划看sum()over()对员工工资进行累加
【SQL开发实战技巧】系列(十四):计算消费后的余额&计算银行流水累计和&计算各部门工资排名前三位的员工
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
【SQL开发实战技巧】系列(十六):数据仓库中时间类型操作(初级)日、月、年、时、分、秒之差及时间间隔计算
【SQL开发实战技巧】系列(十七):数据仓库中时间类型操作(初级)确定两个日期之间的工作天数、计算—年中周内各日期出现次数、确定当前记录和下一条记录之间相差的天数
【SQL开发实战技巧】系列(十八):数据仓库中时间类型操作(进阶)INTERVAL、EXTRACT以及如何确定一年是否为闰年及周的计算
【SQL开发实战技巧】系列(十九):数据仓库中时间类型操作(进阶)如何一个SQL打印当月或一年的日历?如何确定某月内第一个和最后—个周内某天的日期?
【SQL开发实战技巧】系列(二十):数据仓库中时间类型操作(进阶)获取季度开始结束时间以及如何统计非连续性时间的数据
【SQL开发实战技巧】系列(二十一):数据仓库中时间类型操作(进阶)识别重叠的日期范围,按指定10分钟时间间隔汇总数据
【SQL开发实战技巧】系列(二十二):数仓报表场景☞ 从分析函数效率一定快吗聊一聊结果集分页和隔行抽样实现方式
【SQL开发实战技巧】系列(二十三):数仓报表场景☞ 如何对数据排列组合去重以及通过如何找到包含最大值和最小值的记录这个问题再次用执行计划给你证明分析函数性能不一定高
【SQL开发实战技巧】系列(二十四):数仓报表场景☞通过案例执行计划详解”行转列”,”列转行”是如何实现的
【SQL开发实战技巧】系列(二十五):数仓报表场景☞结果集中的重复数据只显示一次以及计算部门薪资差异高效的写法以及如何对数据进行快速分组
【SQL开发实战技巧】系列(二十六):数仓报表场景☞聊聊ROLLUP、UNION ALL是如何分别做分组合计的以及如何识别哪些行是做汇总的结果行
【SQL开发实战技巧】系列(二十七):数仓报表场景☞通过对移动范围进行聚集来详解分析函数开窗原理以及如何一个SQL打印九九乘法表
【SQL开发实战技巧】系列(二十八):数仓报表场景☞人员分布问题以及不同组(分区)同时聚集如何实现
【SQL开发实战技巧】系列(二十九):数仓报表场景☞简单的树形(分层)查询以及如何确定根节点、分支节点和叶子节点
【SQL开发实战技巧】系列(三十):数仓报表场景☞树形(分层)查询如何排序?以及如何在树形查询中正确的使用where条件
【SQL开发实战技巧】系列(三十一):数仓报表场景☞分层查询如何只查询树形结构某一个分支?如何剪掉一个分支?
【SQL开发实战技巧】系列(三十二):数仓报表场景☞对表中某个字段内的值去重
【SQL开发实战技巧】系列(三十三):数仓报表场景☞从不固定位置提取字符串的元素以及搜索满足字母在前数字在后等条件的数据
【SQL开发实战技巧】系列(三十四):数仓报表场景☞如何对数据分级并行转为列
【SQL开发实战技巧】系列(三十五):数仓报表场景☞根据条件返回不同列的数据以及Left /Full Join注意事项
【SQL开发实战技巧】系列(三十六):数仓报表场景☞整理垃圾数据:查找数据的连续性时间和重叠时间的关系,初始化开始结束时间
【SQL开发实战技巧】系列(三十七):数仓报表场景☞从表内始终只有近两年的数据,要求用两列分别显示其中一年的数据聊行转列隐含信息的重要性
【SQL开发实战技巧】系列(三十八):数仓报表场景☞拆分字符串进行连接
【SQL开发实战技巧】系列(三十九):Oracle12C常用新特性☞新增分页查询
【SQL开发实战技巧】系列(四十):Oracle12C常用新特性☞可以在同样的列(列组合)上创建多个索引以及可以对DDL操作进行日志记录
【SQL开发实战技巧】系列(四十一):Oracle12C常用新特性☞APPROX_COUNT_DISTINCT以及TEMP UNDO(临时undo记录可以存储在一个临时表中)
【SQL开发实战技巧】系列(四十二):Oracle12C常用新特性☞With FUNCTION新特性
【SQL开发实战技巧】系列(四十三):Oracle12C常用新特性☞转换函数的增强和不可见字段
【SQL开发实战技巧】系列(四十四):Oracle12C常用新特性☞你知道吗Oralcle新增了类似Mysql的自增列(Identity Columns)功能



前言

本篇文章主要给讲解的Oracle12C+的新特性是:在ORACLE 12C以前的版本中,如果要实现列自增长,需要通过序列+触发器实现,到了12C ORACLE 引进了Identity Columns新特性(GENERATED ALWAYS AS IDENTITY、GENERATED BY DEFAULT AS IDENTITY、GENERATED BY DEFAULT ON NULL AS IDENTITY、手动调用自增列序列),从而实现了列自增长功能,和mysql,sql server类似功能。

【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。


Oralcle自增列(Identity Columns)

在ORACLE 12C以前的版本中,如果要实现列自增长,需要通过序列+触发器实现,到了12C ORACLE 引进了Identity Columns新特性(GENERATED ALWAYS AS IDENTITY、GENERATED BY DEFAULT AS IDENTITY、GENERATED BY DEFAULT ON NULL AS IDENTITY、手动调用自增列序列),从而实现了列自增长功能,和mysql,sql server类似功能:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例一:GENERATED ALWAYS AS IDENTITY

首先查看当前用户下的用户对象

SQL> select object_name,object_type from user_objects;
No rows

接下来创建测试用表:

CREATE TABLE TEST_GEN(
ID  NUMBER GENERATED  ALWAYS AS IDENTITY,
V_NAME   VARCHAR2(100)
);

查看当前用户下的用户对象

SQL> select object_name,object_type from user_objects;
OBJECT_NAME     OBJECT_TYPE                                                            
----------- -----------------------
TEST_GEN             TABLE
ISEQ$$_77416         SEQUENCE

发现创建表的同时,一个序列同时被创建。接下来挖掘一下此表的DDL语句:

1:29:13 用户名: SCOTT >set long 10000
11:29:19 用户名: SCOTT >select dbms_metadata.get_ddl('TABLE','TEST_GEN') FROM DUAL;
DBMS_METADATA.GET_DDL('TABLE','TEST_GEN')
----------------------------------------------------------------------------
  CREATE TABLE "SCOTT"."TEST_GEN"
   (	"ID" NUMBER GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 99999999999999
99999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE  NOKEEP  NO
SCALE  NOT NULL ENABLE,
	"V_NAME" VARCHAR2(100)
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

DBMS_METADATA.GET_DDL('TABLE','TEST_GEN')
----------------------------------------------------------------------------
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"

仔细看其实这个自增列就是序列的语法,其实内部来讲就是一个序列。
尝试手动drop这个序列:

SQL> drop sequence ISEQ$$_77416;
ORA-32794: 无法删除系统生成的序列

手动drop这个表,

SQL> drop table test_gen
Table dropped
SQL> select object_name,object_type from user_objects;
OBJECT_NAME     OBJECT_TYPE                                                            
----------- -----------------------
ISEQ$$_77416         SEQUENCE
SQL> purge table test_gen;
Done
SQL> select object_name,object_type from user_objects;
No rows.

说明当要drop使用自增列的表时,要直接删除而不是放入回收站,放入回收站,虽然表被删除,但是使用的索引并未被删除。
重建表后接下来手动插入数据:

begin 
  for i in 1..10 
    loop
      insert into test_gen(v_name)values('a'||i);
      end loop;
      commit;
      end;
      
SQL> select * from test_gen;
        ID V_NAME
---------- -------------------
         1 a1
         2 a2
         3 a3
         4 a4
         5 a5
         6 a6
         7 a7
         8 a8
         9 a9
        10 a10

删除一部分数据再次插入数据:

SQL> delete from test_gen where id between 5 and 8;
4 rows deleted
SQL> commit;
Commit complete
SQL> insert into test_gen values(44,'a34');
insert into test_gen values(44,'a34')
ORA-32795: 无法插入到“始终生成”身份列
SQL> insert into test_gen(v_name)values('a34');
1 row inserted
SQL> commit;
Commit complete
SQL> select * from test_gen;
        ID V_NAME
---------- ------------------------------------------
        21 a34
         1 a1
         2 a2
         3 a3
         4 a4
         9 a9
        10 a10

自增列会继续递增。
这里的出来几个结论:

  1. GENERATED ALWAYS AS IDENTITY 列无法人工指定值和修改该值
  2. GENERATED IDENTITY 本质也是通过sequence实现
  3. GENERATED IDENTITY 中sequence不能单独被删除
  4. GENERATED IDENTITY 中的表删除,如果存在回收站中,该sequence依然存储,如果表被彻底删除,则sequence也被删除
  5. GENERATED IDENTITY 中的sequence可以通过select 语句查询
  6. 通过alert table 语句来修改GENERATED IDENTITY 的sequence相关值

案例二:GENERATED BY DEFAULT AS IDENTITY

创建测试用表:

CREATE TABLE TEST_DEF (
ID  NUMBER GENERATED BY DEFAULT AS IDENTITY,
V_NAME   VARCHAR2(100)
);

插入数据:

SQL> insert into test_DEF values(default,'a');
SQL> insert into test_def(v_name)values('b');
SQL> insert into test_def values(1,'c');
SQL> commit;
SQL> insert into test_def values(null,'c');
insert into test_def values(null,'c')
ORA-01400: 无法将 NULL 插入 ("TEST"."TEST_DEF"."ID")
SQL> select * from test_def;
        ID V_NAME
---------- ------------------------------------------
         1 a
         2 b
         1 c
SQL> desc test_def;
Name   Type          Nullable Default                       Comments 
------ ------------- -------- ----------------------------- -------- 
ID     NUMBER                 "TEST"."ISEQ$$_77424".nextval          
V_NAME VARCHAR2(100) Y                                        

通过上面操作可以得出简单的结论:

  1. GENERATED BY DEFAULT AS IDENTITY方式不能在该列中插入null值
  2. GENERATED BY DEFAULT AS IDENTITY方式可以指定具体值插入

案例三:GENERATED BY DEFAULT ON NULL AS IDENTITY

创建测试用表:

CREATE TABLE TEST_NUL (
ID  NUMBER GENERATED BY DEFAULT on null AS IDENTITY,
V_NAME   VARCHAR2(100)
);
SQL> insert into test_NUL values(default,'a');
SQL> insert into test_NUL(v_name)values('b');
SQL> insert into test_NUL values(1,'c');
SQL> insert into test_NUL values(null,'c');
SQL> commit;
SQL> desc test_nul;
Name   Type          Nullable Default                       Comments 
------ ------------- -------- ----------------------------- -------- 
ID     NUMBER                 "TEST"."ISEQ$$_77426".nextval          
V_NAME VARCHAR2(100) Y                                               
SQL> select * from test_nul;
        ID V_NAME
---------- ---------
         1 a
         2 b
         1 c
         3 c

通过上面操作,得出结论:

  1. GENERATED BY DEFAULT ON NULL AS IDENTITY的列上可以查询null值,只是默认转换为对应的sequence值

案例四:手动调用自增列序列

创建测试用表:

CREATE TABLE TEST_seq (
ID  NUMBER GENERATED BY DEFAULT AS IDENTITY,
V_NAME   VARCHAR2(100)
);

查询当前表自增列的序列名:

select a.object_name,a.object_type from user_objects a ;
OBJECT_NAME  OBJECT_TYPE
------------ ------------
TEST_SEQ     TABLE
ISEQ$$_73210 SEQUENCE

手动插入一条数据:

insert into test_seq values(default,'a');

查询数据:

select * from test_seq;

在这里插入图片描述

在插入数据的当前会话手动调用序列查询:

select ISEQ$$_73210.Currval from dual

在这里插入图片描述

select ISEQ$$_73210.Nextval from dual

在这里插入图片描述

select ISEQ$$_73210.Currval from dual

在这里插入图片描述

再次插入数据:

insert into test_seq values(default,'b');

查询表:

select * from test_seq;

在这里插入图片描述

发现手动调用nextval后,再次插入默认值之后,发现默认值也跟着跳号了,如果此时在另一个会话再次调用currval:

SQL> select ISEQ$$_73210.Currval from dual;
ORA-08002: 序列 ISEQ$$_73210.CURRVAL 尚未在此会话中定义

报错,需要先执行nextval:

select ISEQ$$_73210.Nextval from dual;

在这里插入图片描述

这时再次插入数据:

insert into test_seq values(default,'c');

再次查询数据:
在这里插入图片描述

发现创建表时指定的自增列对应的序列,和我们手动建立的序列功能应该一致,在其他地方调用此序列,再次往表插数时也会跳号。不过因为自增列序列命名原因,不会清楚某个序列到底属于哪个表的自增列所有。


总结

本篇文章主要给讲解的Oracle12C+的新特性是:在ORACLE 12C以前的版本中,如果要实现列自增长,需要通过序列+触发器实现,到了12C ORACLE 引进了Identity Columns新特性(GENERATED ALWAYS AS IDENTITY、GENERATED BY DEFAULT AS IDENTITY、GENERATED BY DEFAULT ON NULL AS IDENTITY、手动调用自增列序列),从而实现了列自增长功能,和mysql,sql server类似功能。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵延东的一亩三分地

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值