帮助 SQL Server 触发器在插入前截断错误数据
Posted
技术标签:
【中文标题】帮助 SQL Server 触发器在插入前截断错误数据【英文标题】:Help with SQL Server Trigger to truncate bad data before insert 【发布时间】:2011-05-23 19:56:29 【问题描述】:我们使用了一项 Web 服务,该服务决定将字段的最大长度从 255 更改。我们有一个旧的供应商表,其上限仍为 255。我们希望使用触发器暂时解决此问题,直到我们可以在下一次迭代中实施对业务更友好的解决方案。
这是我开始的:
CREATE TRIGGER [mySchema].[TruncDescription]
ON [mySchema].[myTable]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [mySchema].[myTable]
SELECT SubType, type, substring(description, 1, 255)
FROM inserted
END
但是,当我尝试在 myTable
上插入时,出现错误:
字符串或二进制数据将是 截断。该声明已 终止。
我尝试使用SET ANSI_WARNINGS OFF
进行试验,它允许查询工作,但只是没有在描述列中插入任何数据。
有什么方法可以使用触发器来截断过长的数据,或者在设计出更有说服力的解决方案之前,我可以使用另一种替代方法吗?我们在表修改方面相当有限(即我们不能),因为它是一个供应商表,而且我们不控制我们正在使用的 Web 服务,所以我们也不能要求他们修复它。任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:该错误无法避免,因为该错误是在填充插入的表时发生的。
来自文档: http://msdn.microsoft.com/en-us/library/ms191300.aspx
"插入表和删除表的格式与定义INSTEAD OF触发器的表的格式相同。插入表和删除表中的每一列都直接映射到基表中的一列。"
我能想到的唯一真正“聪明”的想法是利用模式和登录使用的默认模式。如果您可以获取 Web 服务用于引用另一个表的登录名,则可以增加该表上的列大小并使用 INSTEAD OF INSERT 触发器对供应商表执行 INSERT。一种变体是在不同的数据库中创建表,并为 Web 服务登录设置默认数据库。
CREATE TRIGGER [myDB].[mySchema].[TruncDescription]
ON [myDB].[mySchema].[myTable]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [VendorDB].[VendorSchema].[VendorTable]
SELECT SubType, type, substring(description, 1, 255)
FROM inserted
END
【讨论】:
【参考方案2】:有了这个设置,对我来说一切正常。 不是说显而易见的,但是您确定在测试时描述字段中有数据吗?他们可能会更改您正在插入的其他字段之一,并且其中一个字段可能会引发错误?
CREATE TABLE [dbo].[DataPlay](
[Data] [nvarchar](255) NULL
) ON [PRIMARY]
GO
还有这样的触发器
Create TRIGGER updT ON DataPlay
Instead of Insert
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [tempdb].[dbo].[DataPlay]
([Data])
(Select substring(Data, 1, 255) from inserted)
END
GO
然后用
插入Declare @d as nvarchar(max)
Select @d = REPLICATE('a', 500)
SET ANSI_WARNINGS OFF
INSERT INTO [tempdb].[dbo].[DataPlay]
([Data])
VALUES
(@d)
GO
【讨论】:
【参考方案3】:我无法使用以下方法在 SQL 2008 R2 上重现此问题:
Declare @table table ( fielda varchar(10) )
Insert Into @table ( fielda )
Values ( Substring('12345678901234567890', 1, 10) )
请确保您的字段确实定义为 varchar(255)。
我还强烈建议您使用带有显式字段列表的 Insert 语句。虽然您的 Insert 在语法上是正确的,但您确实应该使用显式字段列表(就像在我的示例中一样)。问题是当您不指定字段列表时,您将受制于 SQL 和字段顺序的表定义。当您确实使用字段列表时,您可以更改表中字段的顺序(或在中间添加新字段),而无需关心您的插入语句。
【讨论】:
不可否认,我只包含了最基本的代码(以及更改架构、表等)。实际插入符合您的建议。我验证了其他领域,除了这个之外,我们在所有领域都做得很好。 @Darryl 能够给出发生此错误的原因。以上是关于帮助 SQL Server 触发器在插入前截断错误数据的主要内容,如果未能解决你的问题,请参考以下文章