2015-11-09 27 views
1

我正在运行更新脚本来混淆数据,偶尔会遇到算术溢出错误消息,如标题中所示。正在更新的表有260k条记录,但更新脚本需要多次运行才能产生错误。尽管它非常罕见,但在修复之前我不能依赖代码,因为调试很麻烦。**偶尔**将表达式转换为数据类型的算术溢出错误int

查看其他类似的问题,通常可以通过在表格中或计算中将数据类型从INT更改为BIGINT来解决此问题。但是,我不明白这可能是需要的。我已经将脚本简化到了下面,因为我已经将脚本指向了一列的更新。

函数正在被更新调用,我已经在下面包含了这个函数。我怀疑,由于错误的随机性,使用NEW_ID函数可能会导致它,但是当多次运行这部分函数时,我无法重新创建错误。 NEW_ID函数不能在函数中使用,所以它被从视图中调用,也包含在下面。

更新脚本:

UPDATE dbo.Addresses 
SET HouseNumber = CASE WHEN LEN(HouseNumber) > 0 
         THEN dbo.fn_GenerateRandomString (LEN(HouseNumber), 1, 1, 1) 
         ELSE HouseNumber 
        END 

NEW_ID视图和随机串函数

CREATE VIEW dbo.vw_GetNewID 
AS 
SELECT NEWID() AS New_ID 

CREATE FUNCTION dbo.fn_GenerateRandomString (
@stringLength int, 
@upperCaseBit bit, 
@lowerCaseBit bit, 
@numberBit bit 
) 
RETURNS nvarchar(100) 
AS 
BEGIN 
-- Sanitise string length values. 
IF ISNULL(@stringLength, -1) < 0 
SET @stringLength = 0 

-- Generate a random string from the specified character sets. 
DECLARE @string nvarchar(100) = '' 
SELECT 
@string += c2 
FROM 
(
    SELECT TOP (@stringLength) c2 FROM (
     SELECT c1 FROM 
     (
      VALUES ('A'),('B'),('C') 
     ) AS T1(c1) 
     WHERE @upperCaseBit = 1 
     UNION ALL 
     SELECT c1 FROM 
     (
      VALUES ('a'),('b'),('c') 
     ) AS T1(c1) 
     WHERE @lowerCaseBit = 1 
     SELECT c1 FROM 
     (
      VALUES ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9') 
     ) AS T1(c1) 
     WHERE @numberBit = 1 
     ) 
    AS T2(c2) 
    ORDER BY (SELECT ABS(CHECKSUM(New_ID)) from vw_GetNewID) 
) AS T2 

RETURN @string 
END 

地址表(用于测试):

CREATE TABLE dbo.Addresses(HouseNumber nchar(32) NULL) 

INSERT Addresses(HouseNumber) 
VALUES ('DSjkmf jkghjsh35hjk h2jkhj3h jhf'), 
    ('SDjfksj3548 ksjk'), 
    (NULL), 
    (''), 
    ('2a'), 
    ('1234567890'), 
    ('An2b') 

注意:地址表中只有7k行有输入值,即LEN(HouseNumber) > 0

回答

3

算术溢出是什么,否则基于字符串的代码混淆。但有一件事可能会导致算术溢出。这是你的ORDER BY条款:

ORDER BY (SELECT ABS(CHECKSUM(New_ID)) from vw_GetNewID) 

CHECKSUM()返回一个整数,其范围是-2,147,483,648到2,147,483,647。请注意,最小数字的绝对值为2,147,483,648,这就是范围之外。您可以验证SELECT ABS(CAST('-2147483648' as int))是否生成算术溢出错误。

你不需要checksum()。唉,你确实需要这个观点,因为这个逻辑在一个函数中,并且是不利的。但是,你可以使用:

ORDER BY (SELECT New_ID from vw_GetNewID) 

我怀疑的原因,你所看到的每一个亿个左右行本,而不是每4个十亿行左右是因为ORDER BY值被多次评估每一行的一部分的分拣过程。最终,它将达到下限。

编辑:

如果你关心效率,它可能是更快地做到这一点使用的字符串操作,而不是表。我可能会建议这个版本的功能:

CREATE VIEW vw_rand AS SELECT rand() as rand; 
GO 
CREATE FUNCTION dbo.fn_GenerateRandomString (
    @stringLength int, 
    @upperCaseBit bit, 
    @lowerCaseBit bit, 
    @numberBit bit 
) 
RETURNS nvarchar(100) 
AS 
BEGIN 
    DECLARE @string NVARCHAR(255) = ''; 
-- Sanitise string length values. 
    IF ISNULL(@stringLength, -1) < 0 
     SET @stringLength = 0; 
    DECLARE @lets VARCHAR(255) = ''; 
    IF (@upperCaseBit = 1) SET @lets = @lets + 'ABC'; 
    IF (@lowerCaseBit = 1) SET @lets = @lets + 'abc'; 
    IF (@numberBit = 1) SET @lets = @lets + ''; 

    DECLARE @len int = len(@lets); 

    WHILE @stringLength > 0 BEGIN 
     SELECT @string += SUBSTRING(@lets, 1 + CAST(rand * @len as INT), 1) 
     FROM vw_rand; 
     SET @stringLength = @stringLength - 1; 
    END; 
    RETURN @string 
END; 

作为一个说明:rand()被记录为独占其范围的末端,所以你不必担心它恰好返回1.

此外,这个版本与你的版本有细微的差别,因为它可以多次拉同一个字母(因此也可以处理更长的字符串)。我认为这实际上是一种好处。

+0

非常感谢,这很有道理。正如你所建议的那样,我完全失去了ABS和CHECKSUM的功能,而且它很有效。我相信这将有助于减少运行时间。不幸的是,对视图的引用将需要保留,因为如果直接插入NEWID(),我会得到消息'在函数中无效使用副作用运算符newid'..再次感谢。 – Fletch

+0

非常有帮助编辑谢谢。我用这个来代替它,它需要一半的时间!在运行新函数时,我注意到当CAST(rand * @len as INT)'返回0时,字符串长度偶尔会缩短。我改变了WHILE条件为LEN(@String)<@ stringLength',并删除了SET @ stringLength..'声明,并且运行良好。 – Fletch

+0

@Fletch。 。 。对于编辑后的代码中的偏移量,应该是1 + cast(...)。 –

相关问题