算术溢出取决于按列分组

Arithmetic overflow depending on group by columns

我收到此错误,但仅在按特定列分组时出现:

Arithmetic overflow error converting expression to data type int.

我想不通为什么。这是导致它的查询(求和函数是罪魁祸首):

SELECT  a.AtgardAvvattningId, 
        a.ObjektId,
        sum(p.SlutLopLangd - p.StartLopLangd) As TotalLangd
    FROM AtgardAvvattning a 
        INNER JOIN Objekt o ON o.ObjektId = a.ObjektId 
        INNER JOIN Position p ON p.AvvattningAtgardId = a.AtgardAvvattningId 
        INNER JOIN Vna v ON v.PositionId = p.PositionId 
    WHERE v.OID IN (...) 
    GROUP BY a.AtgardAvvattningId, a.ObjektId, o.AtgardsDatum
    ORDER BY a.ObjektId

p.SlutLopLangd 和 p.StartLopLangd 都是 int 列。如果我在求和之前将值转换为 bigints,它会起作用:

    sum(CONVERT(bigint, p.SlutLopLangd - p.StartLopLangd)) As TotalLangd

给出这个结果:

AtgardAvvattningId ObjektId TotalLangd
DC9... 9B2... 25684
ECD... 9B2... 25700
3D0... 9B2... 170005
959... 9B2... 170005
BEC... 214... 11814
C31... 214... 11815

如您所见,没有一个总和甚至接近 int 的限制。奇怪的是,如果我像这样在 group by 子句中包含 positionId,它不会引发错误:

SELECT  a.AtgardAvvattningId, 
        a.ObjektId,
        sum(p.SlutLopLangd - p.StartLopLangd) As TotalLangd
    FROM AtgardAvvattning a 
        INNER JOIN Objekt o ON o.ObjektId = a.ObjektId 
        INNER JOIN Position p ON p.AvvattningAtgardId = a.AtgardAvvattningId 
        INNER JOIN Vna v ON v.PositionId = p.PositionId 
    WHERE v.OID IN (...) 
    GROUP BY a.AtgardAvvattningId, a.ObjektId, o.AtgardsDatum, p.PositionId
    ORDER BY a.ObjektId

在这种情况下,AtgardAvvattning 和 Position 之间是一对一的关系。此查询给出与上面完全相同的结果。

当值这么小时,为什么首先会引发算术溢出?为什么它在第二个工作?有什么不同?我知道如果没有数据和 table 结构可能很难给出答案,但任何提示都会有所帮助。

更新:

当完全使用此查询删除组时:

    SELECT  a.AtgardAvvattningId, 
            a.ObjektId,
            p.PositionId,
            v.VnaId,
            p.StartLopLangd,
            p.SlutLopLangd,
            p.SlutLopLangd - p.StartLopLangd as Subtraction
        FROM AtgardAvvattning a 
            INNER JOIN Objekt o ON o.ObjektId = a.ObjektId 
            INNER JOIN Position p ON p.AvvattningAtgardId = a.AtgardAvvattningId 
            INNER JOIN Vna v WITH (NOLOCK) ON v.PositionId = p.PositionId 
        WHERE v.OID IN (...) 
        ORDER BY a.ObjektId

结果行数不多:

AtgardAvvattningId ObjektId PositionId VnaId StartLopLangd SlutLopLangd Subtraction
DC96... 9B2... 473... 1345183 168501 174922 6421
ECD4... 9B2... 07E... 1252649 74602 81027 6425
ECD4... 9B2... 07E... 1252651 74602 81027 6425
ECD4... 9B2... 07E... 1252652 74602 81027 6425
ECD4... 9B2... 07E... 1252650 74602 81027 6425
DC96... 9B2... 473... 1345180 168501 174922 6421
DC96... 9B2... 473... 1345181 168501 174922 6421
DC96... 9B2... 473... 1345182 168501 174922 6421
3D08... 9BC... F18... 1374284 199000 233001 34001
3D08... 9BC... F18... 1374283 199000 233001 34001
9590... 9BC... A2D... 1374285 16591 50592 34001
9590... 9BC... A2D... 1374286 16591 50592 34001
9590... 9BC... A2D... 1374287 16591 50592 34001
9590... 9BC... A2D... 1374289 16591 50592 34001
9590... 9BC... A2D... 1374288 16591 50592 34001
3D08... 9BC... F18... 1374281 199000 233001 34001
3D08... 9BC... F18... 1374280 199000 233001 34001
3D08... 9BC... F18... 1374282 199000 233001 34001
C31B... 214... B20... 1349999 32756 44571 11815
BEC3... 214... F21... 1349998 205022 216836 11814

无论对行求和,都很难达到 int 溢出限制。

最终值实际上并不重要。可能发生的情况是,在您的 SUM 中的某个时刻,您超过了 int 的最大值 (2,147,483,647) 或最小值 (-2,147,483,648) 并收到错误。

举个例子:

SELECT SUM(V.I)
FROM (VALUES(2147483646),
            (2),
            (-2006543543))V(I);

这可能会产生相同的错误:

Arithmetic overflow error converting expression to data type int.

然而,SUM 的结果将是 140,940,105(远低于最大值)。这是因为if21474836462先求和,然后得到2147483648,比[=13的最大值大=].如果您先 CAST/CONVERT 值,则不会出现错误:

SELECT SUM(CONVERT(bigint,V.I))
FROM (VALUES(2147483646),
            (2),
            (-2006543543))V(I);