UPDATE 语句
UPDATE语句用于更新表或视图行中指定列的值。 如果未为视图定义“代替更新”触发器,则更新视图的某一行也会更新其基础表中的某一行。 如果定义了这样的触发器,则启用触发器。
该表或视图可以存在于当前服务器上,也可以存在于当前服务器可以与之建立连接的任何 Db2 子系统中。
这种说法有两种形式:
- 搜索的 UPDATE表单用于更新根据搜索条件确定的一行或多行。
- 定位的更新表单指定要更新与当前光标位置对应的一行或多行。
调用 UPDATE
此语句可嵌入应用程序中或者以交互方式发出。 定位的更新可以嵌入到应用程序中。 这两种形式都是可执行语句,可以动态编写。
授权 UPDATE
权限要求取决于语句中标识的对象是用户定义的表、允许更新的目录表还是视图,以及是否遵循SQL标准规则:
当识别出用户定义的表时 :权限集必须至少包含以下一项:
- DATAACCESS 权限
- 桌上的更新权限
- 每列的更新权限
- 对表的所有权
- DBADM 数据库中包含表格的权限
- SYSADM 权限
如果数据库是隐式创建的,则数据库权限必须位于隐式数据库或 DSNDB04 上。
当识别出目录表时 :权限集必须至少包含以下一项:
- ACCESSCTRL 权限
- DATAACCESS 权限
- 每列的更新权限
- DBADM 目录数据库权限
安装 SYSOPR 权限
- SYSCTRL 权限
- SYSADM 权限
- SYSADM 权限
- 系统 DBADM 权限
当确定一个景观时 :特权集必须至少包含以下内容之一:
- DATAACCESS 权限
- SYSADM 权限
- 视图的更新权限
- 更新每列的更新权限
- 表或视图的 SELECT 权限
- 表格或视图的所有权
- 如果目标是一个表,且该表不是目录表,则DBADM是包含该表的数据库的权限
- DATAACCESS
- SYSADM 权限
- BUSINESS_TIME期间列的UPDATE权限
- 桌上的更新权限
- 表格或视图的所有权
- 如果目标是一个表,且该表不是目录表,则DBADM是包含该表的数据库的权限
- DATAACCESS
- SYSADM 权限
如果被搜索的UPDATE中的搜索条件包含子查询,或者赋值子句包含标量全选或行全选 ,请参阅查询授权 ,了解所需授权的说明。
视图的所有者与表的所有者不同,可能没有视图的更新权限(或者可能拥有更新权限,但不能将其授予他人)。 由于景观本身的性质,无法将其用于更新。 更多信息,请参阅 CREATE VIEW语句中的权限讨论。
FL 509 如果语句试图更新 SYSIBM.SYSAUDITPOLICIES 目录表中受防篡改审计策略约束的行,则需要额外的 RACF® 授权。 在语句执行期间,必须授权主授权ID或与主授权ID关联的某个组访问 RACF 中的防篡改审计策略配置文件。 如需了解授权规则的更多信息,请参阅 Db2 审核政策。
权限集: 如果该语句嵌入在应用程序中,则权限集就是计划或包的所有者所拥有的权限。 如果语句是动态准备的,则权限集由生效的DYNAMICRULES行为(运行、绑定、定义或调用)确定,并在动态SQL语句的准备和执行中汇总。 (如需了解这些行为的更多信息,包括确定这些行为的DYNAMICRULES绑定选项值列表,请参阅授权ID和动态SQL )。
搜索更新:
定位更新:
period-clause:
包括列:
数据类型:
内置类型:
任务条款:
- 1 表达式、DEFAULT和NULL关键字的数量必须与 列名称的数量一致。 表达式不得引用UNPACK函数调用。。
- 2 选择列表中的列数必须与列名数一致。
- 3 UNPACK函数调用返回的项数必须与列名称数一致。
隔离条款:
描述 UPDATE
- 表名或视图名
- 标识UPDATE语句的对象。 名称必须标识 Db2 子系统中存在的表或视图,该名称由隐式或显式指定的位置名称标识。 该名称不得用于以下表格之一:
- 辅助表格
- 临时表或临时表视图
- 没有可更新列的目录表或没有可更新列的目录表视图
目录表
- 只读视图,没有为其更新操作定义“代替”触发器。 (有关只读视图的描述,请参阅 CREATE VIEW语句。)
- 系统维护的实体化查询表
- 为XML列隐式创建的表
- 如果满足以下条件之一,则启用存档功能:
- SYSIBMADM.MOVE_TO_ARCHIVE 全局变量被设置为Y。
- SYSIBMADM.GET_ARCHIVE 全局变量设置为Y,ARCHIVESENSITIVE绑定选项设置为YES,操作为定位更新。
在 IMS 或 CICS® 应用程序中,包含已识别表或视图的 Db2 子系统必须是一个支持两阶段提交(two-phase commit)的远程服务器。
如果SET子句中标识的每一列都是可更新列,则可以识别目录表或目录表视图。 如果目录表的某列可以更新,则其在 Db2 目录表中的描述会表明该列可以更新。 如果对象表是 SYSIBM.SYSSTRINGS ,则除了IBMREQD列之外,其他任何列都可以更新,但选择更新的行必须是由用户提供的行(IBMREQD列的值为N),并且只能指定某些值,如 SYSIBM.SYSSTRINGS 中的条目如何进行字符转换中所述。
- 句中句
- 指定一个期间子句应用于更新操作的目标。 同一时期的名字不能重复出现。 如果更新操作的目标是视图:
- 视图定义的外部全选中的 FROM 子句必须直接或间接引用应用程序期间的时间表。
- 视图定义的外部全选结果表必须明确或隐含地包含BUSINESS_TIME期间的开始和结束列。
- 视图不能定义一个代替触发器。
- FOR PORTION OF BUSINESS_TIME
- 指定更新仅适用于由period子句指定的行中BUSINESS_TIME时段部分的行值。 BUSINESS_TIME 必须是在表格中定义的时段。
如果当 BUSTIMESENSITIVE 绑定选项设置为 YES 时,CURRENT TEMPORAL BUSINESS_TIME 特殊寄存器的值不为 NULL,则不能指定部分业务时间。
- FROM value1 TO value2
- 指定更新应用于从 value1 到 value2。 如果 value1 大于或等于 value2 或 value1 或 value2 为空值。
此条款不得用于包含-包含期间。
对于以 FROM value1 TO value2 ,目标更新行中以period-name 指定的期限:
- 如果开始列的值小于 value1 而结束列的值大于 value1。
- 如果结束列的值大于或等于 value2 且开始列的值小于 value2。
- 如果开始列的值大于或等于 value1 且结束列的值小于或等于 value2。
- 如果时期名称的两列均小于、 value1 或大于或等于 value2。
- 如果行中的时间与指定时间段的开始或结束部分重叠,则部分包含在指定时间段内,但不会同时包含。
- 如果行中的时间与指定时间段的开始和结束时间重合,则完全重合。
如果指定时间段内没有包含行中的时间段名称 ,则该行不会更新。 否则,更新将根据PORTION OF的规格以及期间名称列中的值与指定期间的重叠情况来应用,具体如下:
- 如果行中的时期名称完全包含在指定的时期内,则更新该行, 时期名称的 “开始”列和“结束”列的值保持不变。
- 如果行中的时期、时期名称部分包含在指定的时期内,并且与指定时期的开始部分重叠:
- 行已更新。 在更新后的行中,开始列的值被设置为 value1 ,结束列的值是结束列的原始值。
- 使用该行的原始值插入另一行,但最后一列设置为 value1 ,其他生成的列使用新的值。
- 如果行中的时期、时期名称部分包含在指定的时期内,并且与指定时期的结尾重叠:
- 行已更新。 在更新后的行中,开始列的值是开始列的原始值,结束列的值设置为 value2。
- 使用该行的原始值插入另一行,但将开始列设置为 value2 ,其他生成的列使用新的值。
- 如果行中的时期、时期名称与指定的时期完全重合:
- 行已更新。 在更新行中,开始列的值设置为 value1 ,结束列的值设置为 value2。
- 使用该行的原始值插入另一行,但最后一列设置为 value1 ,定义为数据更改操作的列被设置为“I”,其他生成的列使用新值。
- 使用该行的原始值插入另一行,但开始列设置为 value2 ,定义为数据更改操作的列被设置为“I”,其他生成的列使用新值。
任何现有的更新触发器都会针对更新后的行激活,任何现有的插入触发器都会针对隐式插入的行激活。
BETWEEN value1 AND value2
FL 500 指定更新操作适用于从 value1 至并包括 value2。 如果 value1 大于 value2 ,或者 value1 或 value2 为空值。 此条款不得用于包含-排除期间。
对于用BETWEEN value1 和 value2 ,更新操作目标中连续出现的句号、句号名称 :
- 如果开始列的值小于 value1 而结束列的值大于 value1。
- 如果结束列的值大于或等于 value2 且开始列的值小于 value2。
- 如果行中期间名称的起始列的值大于或等于 value1 且该行对应结束列的值小于或等于 value2。
- 如果行与指定期间的开始或结束部分重叠,则部分包含在指定期间内,但不会同时包含在指定期间内。
- 如果行中的时间与指定时间段的开始和结束时间重叠,则完全与指定时间段重叠。
- 如果时期名称的两列均小于或 value1 或大于 value2。
如果指定时间段内没有包含某一行中的时间段名称 ,则该行不会被更新。 否则,更新操作将基于以下项目:
- “部分”条款的详细说明。
- 时期名称列中的值如何与指定时期重叠。
- spu (最小周期单位),取决于周期列的数据类型,如下所示:
- 对于包含日期列的期间,spu为1天。
- 在包含 TIMESTAMP(6) 列的时段内,spu 为 1 微秒。
基于这些项目,更新操作如下:
- 如果一行中的时期名称完全包含在指定的时期内,则该行将被更新,而时期名称的起始列和结束列的值保持不变。
- 如果行中的时期名称部分包含在指定的时期内,并且与指定时期的开始部分重叠:
- 行已更新。 在更新后的行中,开始列的值被设置为 value1 ,结束列的值是结束列的原始值。
- 插入的行使用该行的原始值,但最后一列设置为 value1 - spu,其他生成的列使用新的值。
- 如果行中的时期名称部分包含在指定的时期内,并且与指定时期的结尾重叠:
- 行已更新。 在更新后的行中,开始列的值是开始列的原始值,结束列的值被设置为 value2
- 插入的行使用该行的原始值,但开始列设置为 value2 + spu,其他生成的列使用新的值。
- 如果行中的时期名称与指定的时期完全重合:
- 行已更新。 在更新后的行中,开始列的值设置为 value1 ,结束列的值设置为 value2。
- 插入的行使用该行的原始值,但最后一列设置为 value1 - spu,定义为数据更改操作的列被设置为“I”,其他生成的列使用新值。
- 使用该行的原始值插入另一行,但开始列设置为 value2 + spu,定义为数据更改操作的列被设置为“I”,其他生成的列使用新的值。
- value1, value2
- 指定返回内置数据类型值的表达式。 每个表达式的结果必须与指定期间列的数据类型相匹配。 参见 “分配和比较” 中描述的比较规则。 每个表达式可以包含以下任何支持的运算符:
- 常量
- 专用寄存器
- 变量
- 数组元素说明
- 一个内置标量函数,其参数为支持的操作数
- CAST 规范,其中 CAST 操作数是受支持的运算数
- 使用算术运算符和操作数的表达式
每个表达式的精度不能高于该期间列的精度。
如果将期间的开始和结束列定义为不带时区的TIMESTAMP,则每个表达式不得返回带有时区的TIMESTAMP值。
视图的期间子句不能包含未定义的参数标记。
- 相关名称
- 可在搜索条件或赋值子句中使用,以指定表或视图。 (关于相关名称的解释,请参阅相关名称。)
- 包括列
- 当UPDATE语句嵌套在子查询、SELECT语句或SELECT INTO语句的外层全选查询的FROM子句中时,指定结果表中包含的一组列以及表名或视图名的列。 包含的列附加到以表名或视图名标识的列列表的末尾。 如果对include-column指定的列未赋值,则该列返回NULL值。
- INCLUDE
- 介绍UPDATE语句结果表中包含的列列表。 仅当UPDATE语句嵌套在SELECT语句或SELECT INTO语句的FROM子句中时,才可使用包含的列。
- 列名
- 指定UPDATE语句结果表某列的名称,该名称不能与表或视图中其他列或表名或视图名中指定的列相同。
- data-type
- 指定包含列的数据类型。 包含的列可以为空。
- 内置式
- 指定内置数据类型。 有关每种内置类型的描述,请参阅 CREATE TABLE语句。
INCLUDE列中不能指定CCSID 1208和CCSID 1200子句。
- 独特类型
- 指定一种不同的类型。 列的任何长度、精度或比例属性都是通过使用CREATE TYPE语句指定的不同类型的源类型的属性。
- SET
- 引入对列名的赋值。
- assignment-clause
- 如果指定了 row-fullselect , 则row-fullselect结果中的列数必须与指定的列名数一致。 如果未指定行全选 ,则表达式、NULL和DEFAULT关键字的数量必须与指定的列名数量匹配。
- column-name
- 标识要更新的列。 列名必须标识指定表或视图的列。 如果扩展指标未启用,则该列必须为可更新列。 列名不能识别生成的列或视图列,这些列是从标量函数、常数或表达式派生的。 列名也可以标识一个必须未加限定的包含列。 同一列名不能重复指定。
如果UPDATE语句包含一个期间子句 ,则不能指定定义为BUSINESS_TIME期间一部分的列。
只有在UPDATE语句嵌套在SELECT语句或SELECT INTO语句的FROM子句中时,才会处理包含列的分配。 必须至少有一个赋值子句指定非包含列的列名。 对于未使用明确的 SET 子句设置的包含列,将返回空值。
对于定位更新,允许的列名可以进一步限制为特定列表中的列名。 此列表出现在相关游标的SELECT语句的FOR UPDATE子句中。 通过使用列的已定位更新中描述的条件,可以省略该条款。
视图列与视图中的另一列源自同一列,可以更新,但无法在同一UPDATE语句中更新这两列。
- 表达式
- 指示列的新值。 表达式是指表达式中描述的任何类型的表达式。 它不能包含聚合函数。
表达式中的列名必须标识表或视图的列。 对于每行更新,表达式中列的值是更新前该行中列的值。
如果表达式是一个单一的主变量,则该主变量可以包含一个带有扩展指示值的指示符。 如果扩展指示符已启用,且赋值子句中的表达式不是单个宿主变量,则不能使用 DEFAULT 和 UNASSIGNED 的扩展指示符值。
如果符合以下任一条件,则可以使用CAST规范:- 目标列定义为可空。
- 目标列定义为非空且默认值为非空,CAST规范的源是一个单一的主机变量,且主机变量的数据属性(数据类型、长度、精度和比例)与CAST规范的结果相同。
- DEFAULT
- 指定根据表中相应列的定义使用默认值。
不能为ROWID列指定DEFAULT。
赋值取决于列的定义方式。
如果列是生成的表达式,则列值将由 Db2 子系统根据表达式的结果生成。
如果列是标识列、行更改时间戳列、行开始列、行结束列或事务开始ID列,则 Db2 子系统将生成一个新值。
- 如果使用 WITH DEFAULT 子句定义,则该值将设置为为该列定义的默认值。
- 如果定义列时未指定 WITH DEFAULT 条款,则 GENERATED 子句或 NOT NULL 子句,则值为空。
- 如果列在 INCLUDE 列列表中,列值将设置为空。
必须为定义为 GENERATED ALWAYS 的列指定 DEFAULT。 可以为定义为 GENERATED BY DEFAULT 的列指定有效值。
如果列定义使用了 NOT NULL 子句,且未使用 GENERATEDWITH DEFAULT 子句,则 DEFAULT 不能为该列指定关键字。
- NULL
- 指定空值作为列的新值。 仅用于可空列。 NULL 仅适用于可空列。
- row-fullselect
- 指定返回单行的全查询。 列值被分配给每个对应的列名。 如果全查询未返回任何行,那么会将空值分配给每个列;如果要更新的任何列都不可空,那么将发生错误。 如果结果中存在多个行,那么也会发生错误。
对于定位更新,如果UPDATE语句的对象表或视图在fullselect中使用,则fullselect中表或视图实例的列不能与正在更新的列名相同。
如果fullselect指的是要更新的列,则fullselect中该列的值是更新前该行中该列的值。
- UNPACK函数调用
- 指定调用UNPACK内置函数。 UNPACK函数调用返回的字段数量必须与列名称的数量相同。
- WHERE
- 指定要更新的行。 您可以省略该子句,给出搜索条件,或指定光标。 如果省略该子句,则更新表格或视图的所有行。
- search-condition
- 指定 SQL 语言元素中描述的任何搜索条件。 除了子查询中,搜索条件中的每个列名必须标识表或视图中的列。
搜索条件应用于表格或视图的每一行,更新后的行是搜索条件为真的行。 如果唯一键或主键是父键,则会在操作结束时有效检查约束。
如果搜索条件包含子查询,则每次将搜索条件应用于一行时,都会执行子查询,并将结果用于应用搜索条件。 实际上,没有关联引用的子查询只执行一次,而具有关联引用的子查询则必须针对每一行执行一次。
- WHERE CURRENT OF 光标名称
- 标识更新操作中使用的光标。 cursor-name 必须按照 DECLARE CURSOR 语句中的说明,将声明的游标标识为 DECLARE CURSOR 语句。 如果UPDATE语句嵌入在程序中,则DECLARE CURSOR语句必须包含 select语句 ,而不是语句名称。
UPDATE语句的对象也必须在游标的SELECT语句的FROM子句中标识。 要更新的列可以在SELECT语句的FOR UPDATE子句中识别,但并非必须识别。 如果没有指定列,则可以更新的列包括在完整选择(fullselect)的第一个 FROM 子句中标识的表或视图的所有可更新列。
光标的结果表不能是只读的。 有关只读结果表的说明,请参阅只读游标。 请注意,UPDATE语句的对象不能在游标的SELECT语句的WHERE子句中作为子查询的对象。
执行UPDATE语句时,光标必须打开并定位在结果表的某一行或某一行集上。
- 如果光标位于单行上,则该行会被更新。
- 如果光标位于行集上,则与当前行集中的行相对应的所有行都会更新。
对于引用了定义了而不是更新触发器的视图的光标,即使该视图是可更新的视图,也不得指定已定位的更新。
- FOR ROW n OF ROWSET
- 指定当前行集的哪一行需要更新。 行集的相应行被更新,光标仍停留在当前行集上。
host-variable 或 integer-constant 被赋值给一个整数 k。 如果指定了宿主变量 ,则该变量必须为精确数值类型且比例系数为零,不得包含指示变量,且 k 必须在 1-32767 范围内。
光标必须位于行集上,且指定值必须是光标最近检索的行集的有效值。 如果指定的行无法更新,则返回错误。 指定的行可能位于最近请求的行集范围内,但当前行集包含的行数少于建立该行集时隐式或显式请求的行数。
如果没有指定此条款,光标位置将决定受影响的行。 如果光标位于单行上,则该行会被更新。 如果最近的FETCH语句返回多行数据(但不是作为行集),则此位置将在返回数据的最后一行。 如果光标位于行集上,则与当前行集对应的所有行都会更新。 光标位置保持不变。
另一个应用程序可能会更新SELECT语句的基表中的某一行,使得游标的指定行在基表中不再有对应的行。 尝试更新此类行会导致错误。
- 隔离条款
- 指定在通过语句定位要更新的行时使用的隔离级别。
- WITH
- 介绍隔离级别,可能为以下之一:
- RR
- 可重复读取
- RS
- 读取稳定性
- CS
- 光标稳定性
语句的默认隔离级别是语句所属包或计划的隔离级别,其中包隔离级别优先于计划隔离级别。 如果没有指定包隔离,则默认使用计划隔离。
- SKIP LOCKED DATA
- 当其他事务对行持有不兼容的锁时,指定跳过该行。 这些行可以属于语句中指定的任何已访问表。 SKIP LOCKED
DATA 仅在隔离CS或RS生效时可用,且仅适用于行级或页级锁定。
SKIP LOCKED DATA 只能在搜索的UPDATE语句(或MERGE语句的搜索更新操作)中指定。 SKIP LOCKED DATA 如果指定的隔离级别为可重复读取(WITH RR)或未提交读取(WITH UR),则忽略它。语句的默认隔离级别取决于绑定语句的程序包或计划的隔离级别,其中程序包隔离级别优先于计划隔离级别。 如果没有指定包隔离,则默认使用计划隔离。
- QUERYNO 整数
- 指定在EXPLAIN输出和跟踪记录中用于此SQL语句的编号。 该数字用于计划表中 QUERYNO 列,其中包含有关此 SQL 语句的信息。 这个数字也用于 SYSIBM.SYSSTMT 和 SYSIBM.SYSPACKSTMT 目录表的QUERYNO列中。
如果省略该子句,则与SQL语句关联的数字就是预编译期间分配的语句编号。 因此,如果应用程序被修改并预编译,那么语句编号可能会发生变化。
使用 QUERYNO 子句为程序中的SQL语句分配唯一编号很有帮助:
- 为了简化优化提示的使用,以便选择访问路径
- 用于将计划表中的SQL语句文本与EXPLAIN输出相关联
有关启用和使用优化提示的更多信息,请参阅影响访问路径选择
有关访问计划表的信息,请参阅 《使用EXPLAIN调查SQL性能 》。
更新说明
- 更新规则:
- 更新值必须符合以下规则。 如果执行UPDATE语句时没有发生错误,或者发生了其他错误,则不会更新任何行,光标的位置也不会改变。
- 任务。 使用 SQL语言元素中描述的赋值规则为列分配更新值。
- 有效性。 更新必须遵守以下规则。 如果执行UPDATE语句时没有发生错误,或者发生了其他错误,则不会更新任何行。
- 全选 :行全选和包含标量全选的表达式必须返回不超过一行。
- 唯一约束和唯一索引 :如果已识别的表(或已识别的视图的基表)具有唯一索引或唯一约束,则表中更新的每一行都必须符合这些索引和约束所施加的限制。
所有唯一性检查都在语句末尾有效进行。 如果是多行更新,则会在所有行更新完成后进行验证。
- 检查约束 :如果已识别的表(或已识别的视图的基表)有任何检查约束,则对于表中更新的每一行,每个检查约束必须为真或未知。
所有检查限制在语句末尾都得到了有效的验证。 如果是多行更新,则会在所有行更新完成后进行验证。
- 查看和带有检查选项。 对于使用“带检查选项”定义的视图,更新的行必须符合视图的定义。 如果您命名的视图依赖于其他视图,而这些视图的定义包含“带检查选项”,则更新后的行也必须符合这些视图的定义。 有关这种情况的规则说明,请参阅 CREATE VIEW语句。
对于未定义为“带检查选项”的视图,您可以更改行,使其不再符合视图的定义。 这些行在视图的基表中更新,不再出现在视图中。
- 现场和验证程序。 更新的行必须符合已识别表(或已识别视图的基表)中任何字段或验证程序所施加的任何约束。
- 参考约束。 父行中父键的值不能更改。 如果更新值产生一个非空的外键,则该外键必须等于关系中父表父键的某个值。
在语句结尾处,所有参照约束都得到了有效检查。 如果是多行更新,则会在所有行更新完成后进行验证。
- 包含VARBINARY列的索引。 如果已识别表中的 VARBINARY 列或基于 VARBINARY 数据类型的不同类型列具有索引,则该索引列不能指定 DESC 属性。 要在已识别表格上使用SQL数据更改操作,要么删除索引,要么将列的数据类型改为二进制,然后重建索引。
- 触发器。 UPDATE语句可能会触发激活。 触发器可能会导致其他语句被执行,或者根据更新值引发错误条件。如果视图的UPDATE语句导致而不是触发器被激活,则有效性、参照完整性以及检查约束将根据触发器中执行的数据更改进行检查,而不是根据导致触发器激活的视图或其基础表进行检查。
- 更新行数:
- 通常,UPDATE语句执行完成后,SQLCA中的SQLERRD(3)值即为更新行数。 (如需了解SQLCA的完整描述,包括前一句的例外情况,请参阅 SQL通信区(SQLCA)。 )
- 嵌套用户定义函数或存储过程:
- UPDATE语句可以隐式或显式地引用用户定义的函数或存储过程。 这被称为SQL语句嵌套。 UPDATE中嵌套的用户定义函数或存储过程不得访问正在更新的表。
- 锁定:
- 除非已经存在合适的锁,否则在成功执行更新操作后,将获取一个或多个专用锁。 在提交或回滚操作释放锁之前,只有执行插入操作的应用程序进程可以访问更新的行。 如果LOB未更新,正在运行且未提交读取的应用程序流程也可以访问更新的行。 锁还可以防止其他应用程序在桌面上执行操作。 然而,未提交读取的应用程序进程可以访问锁定的页面和行。
锁不会在已声明的临时表上获取。
- 使用日期时间寄存器时的日期时间表示:
- 正如在日期时间特殊寄存器中解释的那样,当在单个 SQL 语句中隐式或显式指定两个或多个日期时间寄存器时,它们表示同一时间点。 当更新多行时,也是如此。
- 使用敏感静态可滚动光标定位UPDATE的规则:
- 当敏感静态可滚动光标被启用时,以下规则适用:
- 尝试更新删除的孔洞。 如果使用敏感静态可滚动光标定位更新,并尝试更新已确定为删除孔的行,则会发生错误。
- 更新操作。 使用敏感静态滚动光标定位更新操作,具体操作如下:
- 游标基础表目标行中的 SELECT 列表项与结果表对应行中的值进行比较(也就是说,结果表必须与基础表保持一致)。 如果数值不一致,更新操作将被拒绝,并出现错误。 当目标行成功执行FETCH SENSITIVE后,可以再次尝试执行该操作。
- SELECT语句的WHERE子句被重新评估,以确定基础表中的当前值是否仍然满足搜索条件。 将“选择”列表中的值进行比较,以确定这些值没有发生变化。 如果WHERE子句的计算结果为真,且SELECT子句中的值没有改变,则允许更新操作继续进行。 否则,更新操作将被拒绝,出现错误,光标处会出现一个更新漏洞。
- 更新更新漏洞。 更新孔不是永久性的。 另一个进程或同一进程中的搜索更新可能会更新更新漏洞行,使其不再成为更新漏洞。 使用“FETCH SENSITIVE”功能,定位更新和定位删除的更新孔会变得可见。
- 结果表。 更新基础表后,临时结果表中该行的数值将被重新计算并更新。 此时,已定位的更新可能更改了数据,导致该行不符合搜索条件,在这种情况下,该行将被标记为更新漏洞,供后续的FETCH操作使用。
参考列将更新:
如果游标使用FETCH语句来检索稍后更新的列,则在选择列时指定FOR UPDATE OF。 然后在后续的UPDATE或DELETE语句中指定WHERE CURRENT OF。 这些条款阻止了 Db2 通过更新列的索引进行访问,否则可能导致 Db2 多次读取同一行。
更多信息,请参阅更新之前检索的数据。
- 使用多层安全机制更新表格中的行:
- 当您更新具有多层安全性的表中的行时, Db2 会将用户的安全标签(主要授权ID)与行的安全标签进行比较。 更新将按照以下规则进行:
- 如果用户的安全标签与行中的安全标签相同,则更新该行,并根据用户是否具有写权限来确定安全标签的值:
- 如果用户拥有写权限或写权限未启用,则用户可将行的安全标签设置为任何有效安全标签。 安全标签列指定的值必须分配给定义为 CHAR(8) FOR SBCS DATA NOT NULL 的列。
- 如果用户没有写权限,且写权限被启用,则该行的安全标签将设置为该用户的安全标签值。
- 如果用户的安全标签优先于行的安全标签,则UPDATE语句的结果取决于用户是否具有写权限:
- 如果用户具有写权限或写权限未启用,则该行将被更新,用户可以将该行安全标签设置为任何有效安全标签。
- 如果用户没有写权限,且写权限控制已启用,则该行不会更新。
- 如果该行安全标签优先于用户安全标签,则该行不会更新。
- 如果用户的安全标签与行中的安全标签相同,则更新该行,并根据用户是否具有写权限来确定安全标签的值:
- 更新表中已实施行或列访问控制的行:
- 当对一个表发布UPDATE语句时,如果该表有行或列访问控制,则启用行权限或列掩码中指定的规则将决定是否可以更新该行。 通常情况下,这些规则基于授权ID或流程角色。 以下描述了在UPDATE期间启用行权限和列掩码的使用方法:
- 行权限用于识别要更新的行集。
当为表定义了多个启用行权限时,通过在每个启用权限的搜索条件中应用逻辑或运算符,可以得出行访问控制搜索条件。 此行访问控制搜索条件应用于表,以确定UPDATE语句的授权ID或角色可以访问哪些行。 如果UPDATE语句中指定了WHERE子句,则用户指定的谓词将应用于可访问的行,以确定要更新的行。 如果没有WHERE子句,则可访问的行就是要更新的行。
在此步骤中,柱面罩不适用。
如果表没有通过行访问控制来强制执行,则WHERE子句将确定要更新的行,否则将更新表中的所有行。
- 如果有行需要更新,则根据以下规则确定是否可以更新这些行:
- 对于每个要更新的列,列的新值不能受启用列掩码的影响,因为列掩码的列在导出新值时会被引用。
当在计算新行的值时引用列时,如果该列具有启用的列掩码,则使用掩码值来计算新值。 如果对象表还启用了列访问控制,则用于导出新值的列掩码必须确保列掩码中定义的访问控制规则的评估将列解析为自身,而不是常量或表达式。 如果列掩码没有将列掩码设置为自身,则新值无法用于更新,并且在运行时返回错误。
- 如果行是可更新的,并且表中有“更新前”触发器,则触发器被激活。
在触发操作中,更新后的新值可能会在过渡变量中修改。 当触发器返回最终值时,新的值将用于更新。
- 要更新的行必须符合启用的行权限:
对于要更新的每一行,旧值将被UPDATE语句中指定的新值替换。 符合已启用行权限的行是指如果更新,则可以使用派生行访问控制搜索条件检索的行。
- 如果行是可更新的,并且表有一个“更新后”触发器,则触发器被激活。
- 对于每个要更新的列,列的新值不能受启用列掩码的影响,因为列掩码的列在导出新值时会被引用。
以上规则不适用于所包含的栏目。 包含的列受选择列表规则的约束,因为它们不是UPDATE语句对象表的列。
- 行权限用于识别要更新的行集。
扩展指标的使用:
启用扩展指示器时,指示器值不能为正值和0(零)以外的数值,且必须介于 -7 之间。 在不支持的情况下,DEFAULT和UNASSIGNED扩展指示器值不得出现。
扩展指标:
使用未分配的扩展指示值指定指示值,与在语句中未指定该列的效果相同。 指定扩展指示器值 DEFAULT 将为列指定默认值,且仅适用于定义了默认值的列。
如果目标列不可更新,例如定义为“始终生成”的身份列,则必须为其分配扩展指示符值“未分配”。
UPDATE语句不能为所有目标列指定未分配的扩展指示器值。
扩展指标和更新触发器:
如果目标列的指示值是“未分配”,则该列被视为未更新。 该列被视为在目标表或视图中定义的任何更新触发器的 OF 列名列表中未指定。
扩展指示器和延迟错误检查:
启用扩展指示符后,通常在报表准备期间进行的确认插入不可更新列的操作将推迟到报表执行时进行。
- 生成列的注意事项:
- 定义为 GENERATED ALWAYS 不应被指定为赋值子句的目标,除非要赋值的值是用DEFAULT关键字或指定要赋默认值的扩展指示符指定的。
- 系统周期时间表的注意事项:
- 当系统周期临时表的一行更新时, Db2 会更新行开始和事务开始ID列的值,如下所示:
行首列被分配一个列数据类型的值。 如果SYSIBM的值。 更新时内置全局变量 TEMPORAL_LOGICAL_TRANSACTION_TIME 为空,该值是在执行第一个数据更改语句时读取时钟时间生成的,该语句以工作单元为单位,要求为表中的行开始列或事务开始 ID 列分配一个值,或者删除系统周期时间表中的行。 否则,在插入时,行首列的值将设为 SYSIBM.TEMPORAL_LOGICAL_TRANSACTION_TIME 内置全局变量的值。
- 事务开始标识列被分配一个唯一的时间戳值,或空值。 如果事务开始ID列为空,则该列的值为空。 否则,在执行第一个数据更改语句时,如果需要为表中的行开始列或事务开始ID列分配一个值,则使用时间戳来生成该值。 当系统周期时间表中某一行被删除时,也会发生这种情况。 如果在单个SQL工作单元中更新了多行,则事务开始ID列的值对所有行都是相同的,并且与另一个工作单元中为该列生成的值不同。
如果UPDATE语句的搜索条件包含一个关联子查询,该子查询引用了历史行(显式引用了历史表的名称,或通过在FROM子句中使用期间规范隐式引用了历史表),则作为历史行插入(到历史表中)的更新行的旧版本可能会对随后处理的语句的行的更新操作可见。
如果将 CURRENT TEMPORAL SYSTEM_TIME 特殊寄存器设置为非空值,则 UPDATE 语句的底层目标不能是系统周期临时表。 无论系统周期时间表是直接引用还是间接引用,此限制均适用。
- 历史表格注意事项:
- 当更新系统周期时间表中的某一行时,该行的历史副本将被插入到相应的历史表中,并以系统确定的值的形式捕获历史行的结束时间戳,该值与数据更改操作的时间相对应。 Db2 在事务中执行第一个数据更改语句时,如果需要为表中的行开始或事务开始ID列分配一个值,则通过使用时间戳来生成该值。 当系统周期时间表中某一行被删除时,也会发生这种情况。
如果SYSIBM的值是 在数据更改操作时,内置全局变量 TEMPORAL_LOGICAL_TRANSACTION_TIME 为空,该值是在执行第一个数据更改语句时读取时钟时间生成的,该语句需要为表中的行开始列或事务开始 ID 列分配一个值,或者删除系统周期时间表中的行。 否则,在数据更改操作时,该值将从 SYSIBM.TEMPORAL_LOGICAL_TRANSACTION_TIME 内置全局变量中分配。
- 申请期间临时时间表注意事项:
- 对于申请期间的时间表,包含 FOR PORTION OF BUSINESS_TIME 子句的 UPDATE 语句表示指定更新生效的两个时间点。
假设指定了业务时间的一部分,并且某行的期间值仅部分包含在从 value1 至 value2 或介于 value1 和 value2。 (行的期间值由 BUSINESS_TIME 期间的 begin 列和 end 列的值指定。) 在这种情况下,该行会被更新,并自动插入一行或两行,以表示该行未更改的部分。 对于因更新操作而自动插入的每一行,应用程序时间表中每一生成列都会生成新的值。 如果生成的列被定义为唯一或主键、参照约束中的父键或唯一索引的一部分,则自动插入可能会违反约束或索引。 在这种情况下,将返回一个错误。
当UPDATE语句的目标是应用程序时段表,且当前临时业务时间特殊寄存器的有效值不是空值时, Db2 会在语句中添加以下附加谓词:
- 包容-排斥时期:
bt_begin <= CURRENT TEMPORAL BUSINESS_TIME AND bt_end > CURRENT TEMPORAL BUSINESS_TIME
- 包容性-包容期:
bt_begin <= CURRENT TEMPORAL BUSINESS_TIME AND bt_end >= CURRENT TEMPORAL BUSINESS_TIME
在之前的代码中,bt_begin和bt_end分别是UPDATE语句目标表BUSINESS_TIME期间的开始和结束列。
- 包容-排斥时期:
- 支持存档的表格:
- 将启用归档的表作为UPDATE语句的目标不会影响关联归档表中的行。
如果 全局变量的值为“Y”,则指定启用归档的表作为目标的UPDATE语句将返回错误。 SYSIBMADM.MOVE_TO_ARCHIVE
当系统周期临时表或应用程序周期临时表也被引用时,数据更改语句不得引用启用存档的表。
- 同一工作单元中的其他SQL语句:
- 以下语句不能紧跟在同一工作单元中的UPDATE语句之后:
- ALTER TABLE语句,用于更改列的数据类型(ALTER COLUMN SET DATA TYPE)
- ALTER INDEX语句,用于更改具有不同长度列的索引的填充属性(从PADDED更改为NOT PADDED,反之亦然)
- CREATE TABLE语句,用于创建仅包含加速器的表。
- INSERT、UPDATE或DELETE语句,用于从其他加速器更新仅加速器表。
- 使用UPDATE命令重置表中的AREO*状态:
- 如果所有条件都满足,UPDATE语句将重置表的AREO*状态:
- 该语句是一个搜索的UPDATE语句。 SELECT语句中的UPDATE语句不会重置AREO*状态。
- SET子句中的表达式不是标量全选或行全选
- 更新操作是针对通用表空间中的表
- 该表未启用行访问控制
- 未指定“跳过锁定数据”子句
- WHERE子句未指定
- 未遇到资源不可用的情况。
如果遇到资源不可用的情况,则不会返回错误或警告 SQLCODE。 只会显示资源不可用的控制台消息。
可以使用显示数据库命令来确定AREO*是否被重置。
UPDATE语句示例
假设一名员工获得了晋升。 要更新反映此次调动的NEWEMP表中的若干员工数据,请使用以下UPDATE语句:
UPDATE NEWEMP SET JOB = 'MGR', DEPT = 'E21' WHERE EMPNO = '100125';
在 DSN8C10.EMP 中,将员工编号000190的电话号码更改为3565。
UPDATE DSN8C10.EMP SET PHONENO='3565' WHERE EMPNO='000190';
给部门里的每位成员 D11 加薪100美元。
UPDATE DSN8C10.EMP SET SALARY = SALARY + 100 WHERE WORKDEPT = 'D11';
员工000250正在休假。 将员工的薪酬值(工资、奖金和佣金)设置为空。
或者,这句话也可以这样写:UPDATE DSN8C10.EMP SET SALARY = NULL, BONUS = NULL, COMM = NULL WHERE EMPNO='000250';
UPDATE DSN8C10.EMP SET (SALARY, BONUS, COMM) = (NULL, NULL, NULL) WHERE EMPNO='000250';
假设名为PROJSIZE的列已添加到 DSN8C10.EMP 中。 该列记录了员工所在部门负责的项目数量。 对于部门 E21 中的每位员工,请使用部门负责的项目数量更新PROJSIZE。
UPDATE DSN8C10.EMP SET PROJSIZE = (SELECT COUNT(*) FROM DSN8C10.PROJ WHERE DEPTNO = 'E21') WHERE WORKDEPT = 'E21';
- 光标 C1 所在行所代表的员工工资的两倍。
EXEC SQL UPDATE DSN8C10.EMP SET SALARY = 2 * SALARY WHERE CURRENT OF C1;
假设员工表 EMP1 是用以下语句创建的:
CREATE TABLE EMP1 (EMP_ROWID ROWID GENERATED ALWAYS, EMPNO CHAR(6), NAME CHAR(30), SALARY DECIMAL(9,2), PICTURE BLOB(250K), RESUME CLOB(32K));
假设主变量 HV_EMP_ROWID 包含员工编号为“350000”的员工的ROWID列的值。 使用该 ROWID 值识别员工和用户定义的函数 UPDATE_RESUME,将员工的工资增加 1000 美元,并更新该员工的简历。EXEC SQL UPDATE EMP1 SET SALARY = SALARY + 1000, RESUME = UPDATE_RESUME(:HV_RESUME) WHERE EMP_ROWID = :HV_EMP_ROWID;
在员工表X中,将工资低于平均水平的每位员工的工资提高10%。
EXEC SQL UPDATE EMP X SET SALARY = 1.10 * SALARY WHERE SALARY < (SELECT AVG(SALARY) FROM EMP Y WHERE X.JOBCODE = Y.JOBCODE);
将部门 E11 中工资低于平均水平的员工工资提高到平均水平。
EXEC SQL UPDATE EMP T1 SET SALARY = (SELECT AVG(T2.SALARY) FROM EMP T2) WHERE WORKDEPT = 'E11' AND SALARY < (SELECT AVG(T3.SALARY) FROM EMP T3);
- 给部门“ E11 ”的员工发放相当于其工资10%的奖金。
EXEC SQL DECLARE C1 CURSOR FOR SELECT BONUS FROM DSN8710.EMP WHERE WORKDEPT = 'E12' FOR UPDATE OF BONUS; EXEC SQL UPDATE DSN8710.EMP SET BONUS = ( SELECT .10 * SALARY FROM DSN8710.EMP Y WHERE EMPNO = Y.EMPNO ) WHERE CURRENT OF C1;
- 假设光标 CS1 位于表 T1 中由 10 行组成的行集上,更新行集中的所有 10 行。
EXEC SQL UPDATE T1 SET C1 = 5 WHERE CURRENT OF CS1;
- 假设光标 CS1 位于表 T1 中由 10 行组成的行集上,更新行集的第四行。
short ind1, ind2; int n, updt_value; stmt = 'UPDATE T1 SET C1 = ? WHERE CURRENT OF CS1 FOR ROW ? OF ROWSET' ind1 = 0; ind2 = 0; n = 4; updt_value = 5; ... strcpy(my_sqlda.sqldaid,"SQLDA"); my_sqlda.sqln = 2; my_sqlda.sqld = 2; my_sqlda.sqlvar[0].sqltype = 497; my_sqlda.sqlvar[0].sqllen = 4; my_sqlda.sqlvar[0].sqldata = (int *) &updt_value; my_sqlda.sqlvar[0].sqlind = (short *) &ind1; my_sqlda.sqlvar[1].sqltype = 497; my_sqlda.sqlvar[1].sqllen = 4; my_sqlda.sqlvar[1].sqldata = (int *) &n; my_sqlda.sqlvar[1].sqlind = (short *) &ind2; EXEC SQL PREPARE S1 FROM :stmt; EXEC SQL EXECUTE S1 USING DESCRIPTOR :my_sqlda;
假设表 POLICY 存在,并且它被定义为一个包含-排除时间段 BUSINESS_TIME。 表中有一行,BK列的值为“ P138 ”,CLIENT列的值为“ C882 ”,TYPE列的值为“PPO”,期间值为(“2013-01-01”,“2020-12-31”)。 更新从“2014-01-01”开始的行,将“TYPE”列设置为“HMO”:
UPDATE POLICY FOR PORTION OF BUSINESS_TIME FROM '2014-01-01' TO '9999-12-31' SET TYPE='HMO' WHERE BK='P138', CLIENT='C882';
UPDATE语句处理后,表中包含2行,代替了原来的行。 一行带有时间值('2013-01-01'、'2014-01-01')表示TYPE列的值(更新前的值)为“PPO”,而另一行带有时间值的行('2014-01-01', '2020-12-31')表示TYPE列的值(以UPDATE语句开头)为“HMO”。
- 假设INTARRAY和CHARARRAY数组类型、INTA、CHARA和SI变量以及 T1 表定义如下:
CREATE TYPE INTARRAY AS INTEGER ARRAY [6]; CREATE TYPE CHARARRAY AS CHAR(20) ARRAY [7]; CREATE VARIABLE INTA AS INTARRAY; CREATE VARIABLE CHARA AS CHARARRAY; CREATE VARIABLE SI INT; CREATE TABLE T1 (COL1 CHAR(7), COL2 INT);
为CHARA、INTA和SI赋值。
SET CHARA = ARRAY [ 'a', 'b', 'c' ]; SET INTA = ARRAY [ 1, 2, 3, 4, 5 ]; SET SI = 1;
在表 T1 中插入一行,然后使用CHARA和INTA数组中的值更新该行值,这些数组的索引由变量SI的值决定。
INSERT INTO T1 VALUES ('abc', 10); UPDATE T1 SET COL1 = CHARA[SI], COL2 = INTA[SI];
在表格行中, COL1 现在包含“a”,而 COL2 包含1。
将所有行中列 COL2 的值设置为数组INTA的基数。
UPDATE T1 SET COL2 = CARDINALITY(INTA);
在表格行中, COL2 现在包含5个。
假设表 POLICY 存在,并且它被定义为一个包含-包含时间段 BUSINESS_TIME。 表中有一行,BK列的值为“ P138 ”,CLIENT列的值为“ C882 ”,TYPE列的值为“PPO”,期间值为(“2013-01-01”,“2020-12-31”)。 假设您发出以下UPDATE语句:
UPDATE POLICY FOR PORTION OF BUSINESS_TIME BETWEEN '2014-01-01' AND '9999-12-31' SET TYPE='HMO' WHERE BK='P138', CLIENT='C882';
UPDATE语句处理后,表中包含2行,代替了原来的行。 其中一行日期为('2013-01-01','2013-12-31')的类型列的值为'PPO'(更新前的值),另一行日期为('2014-01-01','2020-12-31')的类型列的值为'HMO'。