如果SQL sum()达到类型容量(溢出)会发生什么?

时间:2015-12-18 21:12:14

标签: sql integer-overflow

我理解这个问题取决于供应商,但是如果像SUM这样的聚合函数对小类型进行操作,我应该担心吗?

例如,MariaDB对类型INT使用4个字节。开发人员可能会假设每笔交易的金额不会超过几千。

但如果我们试图让所有部门获得一整年的收入会怎样呢? E.g:

-- CREATE TABLE income (dt DATETIME, department INT, amount INT);
SELECT SUM(amount) FROM income WHERE dt BETWEEN '2014-01-01' and '2014-12-31'

增加存储空间只是为了修复聚合函数SUM的溢出问题,这看起来很愚蠢。

我应该担心什么? SQL 92/99/2008标准是否有任何保证或澄清?

JDBC驱动程序是否有任何特殊支持?

我应该在表格中重写选择:

SELECT SUM(CAST(amount AS BIGINT)) FROM income
  WHERE dt BETWEEN '2014-01-01' and '2014-12-31'

3 个答案:

答案 0 :(得分:3)

在mysql上测试相当容易:

32位溢出:

class MainThreadClass implements InputListner {
  public MainThreadClass() {
    InputRunner inputRunner = new InputRunner();
    inputRunner.addInputListener(this);
    Thread t = new Thread(new InputThread())
    t.start();
  }

  @Override
  public void inputReceived() {
    //bla bla bla
  }
}

class InputRunner implements Runnable {
  ArrayList<InputListener> listeners = new ArrayList<InputLIsteners>();

  public void run() {
    //code to read input, when it is recieved execute fireInputReceived
  }

  public void addListener(InputListener listener) {
    listeners.add(listener);
  }

  public void fireInputReceived(String input) {
    //loop through all listeners
    //fire inputRecieved on each
  }
}

public Interface InputListener {
  public void inputReceived(String input);
}

64位:

mysql> select sum(x) from (
    select pow(2,31) as x
    union all
    select pow(2,31)
    union all
    select pow(2,31)
) as bignums;
+------------+
| sum(x)     |
+------------+
| 6442450944 | // returned as a "bigint"
+------------+
1 row in set (0.00 sec)

双:

mysql> select sum(x) from (
    select pow(2,63) as x
    union all
    select pow(2,63)
    union all
    select pow(2,63)
) as bignums;
+-----------------------+
| sum(x)                |
+-----------------------+
| 2.7670116110564327e19 | // returned as float
+-----------------------+
1 row in set (0.00 sec)

在mysql上测试相当容易:

32位溢出:

mysql> select sum(x) from (
    select 1.7e+308 as x
    union all
    select 1.7e+308
    union all
    select 1.7e+308
) as bignums;
+--------+
| sum(x) |
+--------+
|      0 |
+--------+

64位:

mysql> select sum(x) from (
    select pow(2,31) as x
    union all
    select pow(2,31)
    union all
    select pow(2,31)
) as bignums;
+------------+
| sum(x)     |
+------------+
| 6442450944 | // returned as a "bigint"
+------------+
1 row in set (0.00 sec)

双:

mysql> select sum(x) from (
    select pow(2,63) as x
    union all
    select pow(2,63)
    union all
    select pow(2,63)
) as bignums;
+-----------------------+
| sum(x)                |
+-----------------------+
| 2.7670116110564327e19 | // returned as float
+-----------------------+
1 row in set (0.00 sec)

评论后续:

mysql> select sum(x) from (
    select 1.7e+308 as x
    union all
    select 1.7e+308
    union all
    select 1.7e+308
) as bignums;
+--------+
| sum(x) |
+--------+
|      0 |
+--------+

答案 1 :(得分:2)

Postgres处理这个没有溢出或截断:

从手册:

  

sum(表达式),返回类型:bigint用于smallint或int参数,numeric用于bigint参数,否则与参数数据类型相同

http://www.postgresql.org/docs/current/static/functions-aggregate.html

快速测试证明:

public extension Array where Element: (timeZoneName: String, formattedName: String){

}

有趣的是,在这种情况下,SQL标准要求语句失败

  

如果在计算AF结果的过程中,中间结果在包含该中间结果的网站的声明类型中无法表示,那么   
  ...
  否则,会引发异常条件:数据异常 - 数值超出范围。

(AF =聚合函数)

答案 2 :(得分:1)

当我理解你的时候,你问的是在溢出的情况下会发生什么。

至少对于SQL Server,请查看以下文档:

https://msdn.microsoft.com/de-de/library/ms187810%28v=sql.120%29.aspx

这里说明了sum()对特定输入类型的返回类型:

Expression result               Return type
------------------------------------------------
tinyint                         int
smallint                        int
int                             int
bigint                          bigint
decimal category (p, s)         decimal(38, s)
money and smallmoney category   money
float and real category         float 

这意味着,可以确实是溢出。因此,我建议您使用floatmoney类型来获取工资,而不是类型int