热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在DB2通用数据库中自动生成的数值序列

生成数字序列的两种方法在DB2中可以用两种方法自动生成一个数字序列:定义带有IDENTITY属性的列。创建SEQUENCE对象。IDENTITY列当用IDENTIT

生成数字序列的两种方法
在 DB2 中可以用两种方法自动生成一个数字序列:

  • 定义带有 IDENTITY 属性的列
  • 创建 SEQUENCE 对象

IDENTITY 列

当用 IDENTITY 属性定义表的列时,每当将一行插入表时,就会自动为该列生成一个数值。

SEQUENCE 对象

让 DB2 自动生成数字序列的第二种方法是创建 SEQUENCE 对象。可以使用序列表达式(sequence expression)来引用序列对象。序列表达式可以出现在表达式能够出现的大多数位置。序列表达式可以指定要返回的值是新生成的值还是以前生成的值。

如果序列引用是针对下一值(next value),就会为序列自动生成一个数值,并将该数值作为序列表达式的结果返回。例如,如果我们假设已经创建了名为 orders_seq 的序列,该序列表达式就返回为序列生成的下一个值:

NEXT VALUE FOR orders_seq

如果序列引用是针对前一值(previous value),那么会将前一个 SQL 语句中为序列生成的数值作为序列表达式的结果返回。该序列表达式返回由序列生成的前一个值:

PREVIOUS VALUE FOR orders_seq

注:当 DB2 UDB 引入序列时,曾支持非 SQL 标准语法 NEXTVAL 代替 NEXT VALUE,以及 PREVVAL 代替 PREVIOUS VALUE。这些变体继续受到支持。

在标识和序列之间做出选择

虽然标识和序列都用于生成数值,但您也许要根据特殊情况选择使用一种来代替另一种。

在以下情况下,标识列很有用:

  • 表中只有一列需要自动生成的值
  • 每一行都需要独立的值
  • 用自动生成器来产生表的主键
  • 生成新值的进程与对表的插入操作紧密联系,无论插入操作是如何发生的

在以下情况下,序列对象很有用:

  • 要将从一个序列生成的值存储到多个表中
  • 每个表有多个列需要自动生成的值(可能通过使用同一个序列或多个序列为每一行生成多个值)
  • 生成新值的进程与任何对表的引用无关

与序列对象不同,标识列是在表上定义的,因此需要某些限制。每个表最多只能有一个标识列。当创建一个列作为标识列时,对于该列必须使用确切的数字数据类型。因为标识属性为列生成一个值,这类似于 DEFAULT 子句所做的,所以在定义标识列时不能指定 DEFAULT 子句。标识列被隐式地定义成 NOT NULL

示例 1. 组合客户和供应商表

要说明标识列的典型用法,请考虑这样一个表:它包含了虚构的 Widget 公司的数据库的客户订单信息。该公司希望为插入表中的每一行(订单)自动生成订单号。

用于我们的示例的 DDL

清单 1 所示,我们使用了用于订单号的标识列,他们将订单号列定义成主键的一部分。注:该列中的以及它本身的 IDENTITY 属性并没有保证所生成的序列值是唯一的。但是,PRIMARY KEY 约束保证了表中行的唯一性。为了确保只将自动生成的值插入标识列,他们指定了 GENERATED ALWAYS 子句。在每个季度结束时,Widget 公司使用最后一个生成的 order_id 来确定这个季度接了多少订单。选项 NO CACHEORDER 确保了在系统故障的情况下,不废弃未使用的标识值。Widget 公司计划通过使用 ALTER TABLE 语句,又从 1 重新开始订单号列,以开始一个新的季度。

清单 1 中显式地显示了标识列的所有属性,即使所设定的值是未指定值时的缺省值。因为缺省值会因各供应商实现而不同,所以指定所有选项是一个很好的编码习惯。

清单 1. 使用 IDENTITY 列创建订单表

CREATE TABLE customer_orders_t (
order_id INT NOT NULL
GENERATED ALWAYS
AS IDENTITY
(START WITH
1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
NO CACHE
ORDER),

order_date DATE NOT NULL,
cust_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
status CHAR(9) NOT NULL,
PRIMARY KEY (order_date, order_id))

以下是将行插入表的 INSERT 语句的示例。

INSERT INTO customer_orders_t VALUES 
(DEFAULT, CURRENT DATE,
:cid, :pid, :qty, :cost, 'PENDING')

Widget 公司不仅管理客户订单,而且还管理供应商订单。供应商订单在一个独立的供应商订单表中,这个表的定义方式与定义客户订单表的方式非常相似。

CREATE TABLE supplier_orders_t (
order_id INT NOT NULL
GENERATED ALWAYS
AS IDENTITY

(START WITH 1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
NO CACHE
ORDER),

order_date DATE NOT NULL,
supp_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
price DECIMAL(10,2) NOT NULL,
status CHAR(9) NOT NULL,
PRIMARY KEY (order_date, order_id))

以下是将行插入 supplier_orders_t 表的 INSERT 语句的示例:

INSERT INTO supplier_orders_t VALUES 
(DEFAULT, CURRENT DATE,
:sid, :pid, :qty, :cost, 'PENDING')

组合表

该公司意识到通过将客户订单表和供应商订单表组合成用于客户和供应商的一个总订单表,可以获得更大的效率和协同。客户订单或供应商订单之间唯一的区 别是订单是进来还是出去,这反映在 STATUS 字段中。为了组合这些表,并造成最小中断,他们计划逐渐引入这种更改。他们的计划中的步骤包括:

  1. 使订单号同步,这些订单号是为每个表生成的,这样在表之间它们就是唯一的。
  2. 等待,直到完成所有非同步订单。(或者,他们可以等到一个季度开始,那时将复位订单号。)
  3. 逐步停止使用供应商订单表,使用客户订单表来管理来自客户和供应商的所有订单。
  4. 清除

第 1 步:使订单号同步
要使在这两个表中使用的生成的 order_id 号码同步,则更改这两个表,这样可以由用于标识列的 SEQUENCE 对象提供值,而不总是生成值。由单个序列 orders_seq 为这两个表中的标识列生成值。通过引用 NEXT VALUE 表达式中的 orders_seq,修改每个表的 INSERT 语句以显式地向标识列提供值。orders_seq 序列的定义方式如下:

CREATE SEQUENCE orders_seq AS INT
START WITH 1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
NO CACHE
ORDER

SET GENERATED BY DEFAULT 子句将客户订单表和供应商订单表改成允许插入操作显式地向标识列提供值。

ALTER TABLE customer_orders_t 
ALTER COLUMN order_id SET GENERATED BY DEFAULT

ALTER TABLE supplier_orders_t
ALTER COLUMN order_id SET GENERATED BY DEFAULT

在将两个订单表的全部 INSERT 语句修改为向 order_id 列提供显式值且 orders_seq 序列从适当的值开始的时候,发出 LOCK TABLE 语句来限制对这两个表的插入操作。

以下是如何更改用于供应商和客户订单表的 INSERT 语句:

INSERT INTO customer_orders_t VALUES
(NEXT VALUE FOR orders_seq, CURRENT DATE,
:cid, :pid, :qty, :cost, 'PENDING')

INSERT INTO supplier_orders_t VALUES
(NEXT VALUE FOR orders_seq, CURRENT DATE,
:sid, :pid, :qty, :cost, 'PENDING')

那么以下是如何修改 orders_seq 序列,使它从客户订单和供应商订单表的 order_id 标识列所生成的最大值的后一个值开始。首先,使用 SELECT 语句确定该值:

SELECT MAX(c.order_id), MAX(s.order_id) 
FROM customer_orders_t c, supplier_orders_t s

例如,假设以上查询返回两个值:42331 和 57231。那么可以按以下方式改变 orders_seq 序列:

ALTER SEQUENCE orders_seq 
RESTART WITH 57232

COMMIT 语句释放表上的锁,那么又可以对这两个订单表执行插入操作了。所插入的值是从单个序列 orders_seq 生成的,并不是每个 order_id 列拥有由标识属性各自独立地生成的值,因此这些值在两个表中将是唯一的。

请参阅图 1 以获取第 1 步的图释。

图 1. order_id 序列值覆盖标识列
第 1 步的图形表示法

第 2 步:等待,直到同步了订单为止
Widget 公司并不想等到季度开始(那时订单被复位);而是决定监控订单的状态。当以下查询的结果是空表时,他们转到第 3 步

SELECT order_id 
FROM (SELECT order_id FROM customer_orders_t
WHERE status <> 'COMPLETED' AND order_id <57232) AS x
UNION ALL (SELECT order_id FROM supplier_orders_t
WHERE status <> 'COMPLETED' AND order_id <57232)

请参阅图 2 以获取第 2 步的图释。

图 2. 消除了所有潜在的重复 order_id 号码
第 2 步的图形表示法

第 3 步:逐步停止使用供应商订单
要逐步停止使用 supplier_orders_t 表,通过按以下方式重命名该表,就可以使它暂时不可用:

RENAME TABLE supplier_orders_t TO supplier_orders_t_old

然后,会创建一个视图来允许对 supplier_orders_t 的现有引用继续访问底层数据:

CREATE VIEW supplier_orders_t 
(order_id, order_date, supp_id, product_id, quantity,
price, status)
AS SELECT
order_id, order_date, cust_id, product_id, quantity,
price, status
FROM customer_orders_t

现在传统客户和供应商的所有活动订单都在 customer_orders_t 表中进行管理。要使将来更方便、更直观地维护这些表,还需要在第 4 步中执行一些清除工作。

请参阅图 3 以获取第 3 步的图释。

图 3. 所有新订单都进入 customer_orders_t
第 3 步的图形表示法

第 4 步:清除
因为现在必须只为一个列(order_id)生成订单号,所以可以由标识列生成值,而不是使用单独的序列对象。同样,表暂时不可用,而且标识值被复位成由序列生成的下一个值。

LOCK TABLE customer_orders_t IN EXCLUSIVE MODE

VALUES NEXT VALUE FROM orders_seq INTO :nextorder

例如,假设上述查询返回值:64243。那么,可以按以下方式改变 customer_orders_t 表:

ALTER TABLE customer_orders_t
ALTER COLUMN order_id
SET GENERATED ALWAYS
RESTART WITH
64243

每个实例(在这些实例中,INSERT 语句使用 orders_seq 序列)同样需要更改,回到使用 DEFAULT,如以前在第 1 步中所显示的。现在可以删除该序列:

DROP SEQUENCE orders_seq RESTRICT 

在归档了旧的供应商订单表中的数据之后,也可以删除该表。

请参阅图 4 以获取第 4 步的图释。

图 4. 再次使用标识列生成值,从 64243 开始
第 4 步的图形表示法

调优性能
既然使用 customer_orders_t 表的次数几乎是原来的两倍,Widget 公司决定将该表放在并行环境中。为了利用现在可以执行的并行插入操作,他们决定通过高速缓存值来调优该表的标识列的性能。他们确定了高速缓存大小 50 适合于每小时创建的订单数量以及出于任何原因而重新启动数据库系统的频率。他们还更改了如何计算一个季度中实际创建的订单数,因此没有理由强制按顺序生成 序列值。仍然继续要满足在一个季度中要生成唯一值的主要需求,因此做出了以下调整来增强用于标识列的序列生成的性能:

ALTER TABLE customer_orders_t 
ALTER COLUMN order_id
SET CACHE 50
SET NO ORDER

示例 2. 收集卫星读数

示例 1 中所示,序列允许跨多个表生成唯一值。序列还允许为一个表中的多个列自动生成它们的值。

对于该示例,请考虑一个围绕行星或月亮的轨道卫星。这个特定卫星 SAT1 旨在获取它的轨道上的 16 个不同点的数据读数。收集该数据的表有三个列,在这些列中会自动生成值:一列使用标识属性生成读数标识,另两列则从序列中获取它们的值。请参阅图 5 获取说明。

图 5. 卫星和它的轨道上的 16 个数据读取点
卫星和它的轨道上的 16 个数据读取点

用于我们的示例的 DDL
因为读数的数字可能非常大,标识列使用 DECIMAL(31) 数据类型。

CREATE TABLE SAT1_readings (
reading_id DECIMAL(31) NOT NULL PRIMARY KEY
GENERATED ALWAYS AS IDENTITY
(START WITH 1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
NO CACHE
ORDER
),
orbit_location SMALLINT NOT NULL,
horizon_adjustment SMALLINT NOT NULL,
planet_image BLOB(100 M))

orbit_location 有一个值,该值从 0 到 15,代表轨道上获取读数的 16 个点。创建以下序列来生成这 16 个值的循环序列:

CREATE SEQUENCE orbit_location_seq 
AS SMALLINT
START WITH 0
INCREMENT BY 1
MINVALUE 0
MAXVALUE 15
CYCLE
NO CACHE
ORDER

horizon_adjustment 值表示卫星与水平面相关的位置在哪里。0 值表示它在水平面上,值 +4 表示它位于水平面上的最高点,值 -4 表示它位于水平面下的最低点。这些序列从值 -4 开始,这既不是最小值,也不是最大值,因为它将用于方程式之中,以便计算水平调整值。序列对于每个轨道周期性循环。计算 horizon_adjustment 值时将使用以下序列:

CREATE SEQUENCE horizon_adjustment_seq 
AS SMALLINT
START WITH -4
INCREMENT BY 1
MINVALUE -7
MAXVALUE 8
CYCLE
NO CACHE
ORDER

填充读数表

每次产生读数时,以下 INSERT 语句就会填充表:

INSERT INTO SAT1_readings VALUES 
(DEFAULT, NEXT VALUE FOR orbit_location_seq,
ABS(NEXT VALUE FOR horizon_adjustment_seq) - 4,
:planet_image)

在前 17 次读取和相应的 INSERT 语句之后,为列 reading_id (r_i)、orbit_location (o_l) 和 horizon_adjustment (h_a) 自动生成的值是:

r_i 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
o_l 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
h_a 0 -1 -2 -3 -4 -3 -2 -1 0 1 2 3 4 3 2 1 0

捕捉附加读数
因为仪器是足够敏感的,在卫星实际到达轨道之前,可以对行星进行读数。仪器的范围允许在卫星进入其轨道之前,当它接近行星时,可以进行 10 次读数。要捕捉这些在正常轨道圈之外的附加读数,序列值从定义循环极限的 MINVALUEMAXVALUE 值的范围外开始。

以下语句改变标识值和序列值以允许读取轨道上的 16 个点之前先获取附加的 10 个读数。RESTART 选项从指定值重新开始标识列或序列,或者当没有指定值时,在创建标识列或序列时从用 START WITH 值指定的值重新开始。

ALTER TABLE SAT1_readings
ALTER COLUMN reading_id
RESTART

ALTER SEQUENCE orbit_location_seq
RESTART WITH -10

ALTER SEQUENCE horizon_adjustment_seq
RESTART WITH -14

以下的表显示了:如果在相应的 INSERT 语句之前执行了以上三个 ALTER 语句,那么前 17 个读数将会是什么。这 17 个读数包括在轨道之前获得的 10 个读数和在轨道上获得的前七个读数:

r_i 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.
o_l -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6
h_a 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -3 -2

结束语

DB2 支持两种灵活的自动生成数值的方式:标识列(与一个表紧密相连)和序列对象(独立于任何表引用来生成值)。上面的示例说明了标识列和序列对象用于自动生成数值的功能是多么强大以及有多么灵活。这些示例具体演示了标识列和序列的以下功能:

  • 使用主键中的标识列
  • 在两个表的情况下使用序列对象
  • 为标识列显式地指定一个值,而不是生成值
  • 从预先确定的值开始值的序列
  • 从指定值重新开始标识列值
  • 高速缓存标识值以提高性能
  • 定义一个序列或标识列,以允许值循环
  • 为序列指定一个开始值,该值大于为该序列定义的最小值
  • 为序列指定一个开始值,该值是负值
  • 定义一个序列,以生成先增加再减少的值
  • 确保按生成值的顺序返回这些值

我们希望您发现序列和标识会对您的应用程序有用。


推荐阅读
  • vue使用
    关键词: ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Asp.net Mvc Framework 七 (Filter及其执行顺序) 的应用示例
    本文介绍了在Asp.net Mvc中应用Filter功能进行登录判断、用户权限控制、输出缓存、防盗链、防蜘蛛、本地化设置等操作的示例,并解释了Filter的执行顺序。通过示例代码,详细说明了如何使用Filter来实现这些功能。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • DSP中cmd文件的命令文件组成及其作用
    本文介绍了DSP中cmd文件的命令文件的组成和作用,包括链接器配置文件的存放链接器配置信息、命令文件的组成、MEMORY和SECTIONS两个伪指令的使用、CMD分配ROM和RAM空间的目的以及MEMORY指定芯片的ROM和RAM大小和划分区间的方法。同时强调了根据不同芯片进行修改的必要性,以适应不同芯片的存储用户程序的需求。 ... [详细]
  • Python中sys模块的功能及用法详解
    本文详细介绍了Python中sys模块的功能及用法,包括对解释器参数和功能的访问、命令行参数列表、字节顺序指示符、编译模块名称等。同时还介绍了sys模块中的新功能和call_tracing函数的用法。推荐学习《Python教程》以深入了解。 ... [详细]
author-avatar
zhenhuaYang
编程、骑行、健身、民谣、生活!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有