UPDATE 语句将记入日志;但是,对使用 .WRITE 子句对较大值数据类型的部分更新进行最小日志记录。有关详细信息,请参阅后面的“更新大值数据类型”。
仅当所修改的表是 table 变量时,才允许在用户定义函数的主体中使用 UPDATE 语句。
如果对行的更新违反了某个约束或规则,或违反了对列的 NULL 设置,或者新值是不兼容的数据类型,则取消该语句、返回错误并且不更新任何记录。
当 UPDATE 语句在表达式求值过程中遇到算术错误(溢出、被零除或域错误)时,则不进行更新。批处理的剩余部分不再执行,并且返回错误消息。
如果对参与聚集索引的一列或多列的更新导致聚集索引和行的大小超过 8,060 字节,则更新失败并且返回错误消息。
如果 UPDATE 语句在更新聚集键以及一个或者多个 text、 ntext 或 image 列时可以更改多个行,则对这些列的部分更新将作为替换所有值来执行。
所有的 char 和 nchar 列向右填充至定义长度。
对于用于远程表以及本地和远程分区视图的 UPDATE 语句,忽略 SET ROWCOUNT 选项的设置。
如果 ANSI_PADDING 设置为 OFF,则会从插入 varchar 和 nvarchar 列的数据中删除所有尾随空格,但只包含空格的字符串除外。这些字符串被截断为空字符串。如果 ANSI_PADDING 设置为 ON,则插入尾随空格。Microsoft SQL Server ODBC 驱动程序和用于 SQL Server 的 OLE DB 访问接口自动对每个连接设置 ANSI_PADDING ON。这可在 ODBC 数据源中进行配置,也可通过设置连接特性或属性进行配置。有关详细信息,请参阅 SET ANSI_PADDING (Transact-SQL)。
使用 WHERE CURRENT OF 子句的定位更新将在游标的当前位置更新单行。这比使用 WHERE <search_condition> 子句限定所更新行的搜索更新更精确。当搜索条件不唯一标识一行时,搜索更新将修改多行。
使用包含 FROM 子句的 UPDATE
如果 UPDATE 语句包含了未指定每个更新列的位置只有一个可用值的 FROM 子句(换句话说,如果 UPDATE 语句是不确定性的),则其结果将不明确。例如,对于下面脚本中的 UPDATE 语句,Table1 中的全部两行都满足 UPDATE 语句中 FROM 子句的限定条件;但是,将使用 Table1 的哪一行来更新 Table2. 中的行是不明确的。
USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1
(ColA int NOT NULL, ColB decimal(10,3) NOT NULL);
GO
CREATE TABLE dbo.Table2
(ColA int PRIMARY KEY NOT NULL, ColB decimal(10,3) NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES(1, 10.0);
INSERT INTO dbo.Table1 VALUES(1, 20.0);
INSERT INTO dbo.Table2 VALUES(1, 0.0);
GO
UPDATE dbo.Table2
SET dbo.Table2.ColB = dbo.Table2.ColB + dbo.Table1.ColB
FROM dbo.Table2
INNER JOIN dbo.Table1
ON (dbo.Table2.ColA = dbo.Table1.ColA);
GO
SELECT ColA, ColB
FROM dbo.Table2;
当结合使用 FROM 和 WHERE CURRENT OF 子句时,可能发生同样的问题。在以下示例中,Table2 中的全部两行都满足 UPDATE 语句中 FROM 子句的限定条件。将使用 Table2 的哪一行来更新 Table1 中的行是不明确的。
USE AdventureWorks;
GO
IF OBJECT_ID ('dbo.Table1', 'U') IS NOT NULL
DROP TABLE dbo.Table1;
GO
IF OBJECT_ID ('dbo.Table2', 'U') IS NOT NULL
DROP TABLE dbo.Table2;
GO
CREATE TABLE dbo.Table1
(c1 int PRIMARY KEY NOT NULL, c2 int NOT NULL);
GO
CREATE TABLE dbo.Table2
(d1 int PRIMARY KEY NOT NULL, d2 int NOT NULL);
GO
INSERT INTO dbo.Table1 VALUES (1, 10);
INSERT INTO dbo.Table2 VALUES (1, 20);
INSERT INTO dbo.Table2 VALUES (2, 30);
GO
DECLARE abc CURSOR LOCAL FOR
SELECT c1, c2
FROM dbo.Table1;
OPEN abc;
FETCH abc;
UPDATE dbo.Table1
SET c2 = c2 + d2
FROM dbo.Table2
WHERE CURRENT OF abc;
GO
SELECT c1, c2 FROM dbo.Table1;
GO
更新用户定义类型列
更新用户定义类型列中的值可以通过下列方式之一完成:
-
提供 SQL Server 系统数据类型的值,条件是该用户定义类型支持该类型的隐式转换或显式转换。以下示例显示如何通过从字符串显式转换来更新用户定义类型
Point 的列中的值。
UPDATE Cities
SET Location = CONVERT(Point, '12.3:46.2')
WHERE Name = 'Anchorage';
-
调用标记为“赋值函数”的用户定义类型的方法执行更新。以下示例调用类型
Point 的名为 SetXY 的赋值函数方法。这将更新该类型的实例状态。
UPDATE Cities
SET Location.SetXY(23.5, 23.5)
WHERE Name = 'Anchorage';
注意: |
|---|
|
如果对 Transact-SQL Null 值调用赋值函数方法,或者赋值函数方法产生的新值为 Null,则 SQL Server 将返回错误。
|
-
修改用户定义类型的已注册属性或公共数据成员的值。提供值的表达式必须可隐式转换为属性的类型。以下示例修改用户定义类型
Point 的属性 X 的值。
UPDATE Cities
SET Location.X = 23.5
WHERE Name = 'Anchorage';
若要修改同一用户定义类型列的不同属性,请发出多个 UPDATE 语句,或者调用该类型的赋值函数方法。
更新大值数据类型
使用 .WRITE (expression, @Offset, @Length) 子句执行对 varchar(max)、nvarchar(max) 和 varbinary(max) 等数据类型的部分或完整更新。例如,对 varchar(max) 列的部分更新可能只删除或修改该列的前 200 个字符,而完整更新则删除或修改该列中的所有数据。如果将数据库恢复模式设置为大容量日志模式或简单模式,则对插入或追加新数据的 .WRITE 更新进行最小日志记录。在更新现有值时,不使用最小日志记录。有关详细信息,请参阅可以尽量减少日志量的操作。
当 UPDATE 语句导致下列任一操作时,数据库引擎便会将部分更新转换为完整更新:
-
更改分区视图或表的键列。
-
修改多行并且还将非唯一的聚集索引的键更新为非常量值。
不能使用 .WRITE 子句更新 NULL 列或将 column_name 的值设置为 NULL。
对于 varbinary 和 varchar 数据类型,以字节为单位指定 @Offset 和 @Length;对于 nvarchar 数据类型,则以字符为单位进行指定。已针对双字节字符集 (DBCS) 排序规则计算了适当的偏移量。
为了获得最佳性能,建议按照块区大小为 8040 字节倍数的方式插入或更新数据。
如果在 OUTPUT 子句中引用了由 .WRITE 子句修改的列,则该列的完整值(deleted.column_name 中的前像或 inserted.column_name 中的后像)都返回到表变量中的指定列。请参阅后面的示例 G。
若要针对其他字符或二进制数据类型获得相同的 .WRITE 功能,请使用 STUFF (Transact-SQL)。
更新 text、ntext 和 image 列
使用 UPDATE 修改 text、ntext 或 image 列时将对列进行初始化,向其列分配有效的文本指针,并且分配至少一个数据页(除非使用 NULL 更新该列)。
若要替换或修改大型 text、ntext 或 image 数据块,请使用 WRITETEXT 或 UPDATETEXT,而不使用 UPDATE 语句。
使用 UPDATE 操作的 INSTEAD OF 触发器
当对表的 UPDATE 操作定义 INSTEAD OF 触发器时,将运行触发器而不运行 UPDATE 语句。早期版本的 SQL Server 只支持对 UPDATE 和其他数据修改语句定义 AFTER 触发器。不能在直接或间接引用定义有 INSTEAD OF 触发器的视图的 UPDATE 语句中指定 FROM 子句。有关 INSTEAD OF 触发器的详细信息,请参阅 CREATE TRIGGER (Transact-SQL)。
设置变量和列
可以在 UPDATE 语句中使用变量名称来显示受影响的旧值和新值,但仅当 UPDATE 语句影响单个记录时才应使用变量名称。如果 UPDATE 语句影响多个记录,若要返回每个记录的旧值和新值,请使用 OUTPUT 子句。