2015-12-18 1 views
0

Я понимаю, что вопрос зависит от поставщика, но спросите, могу ли я беспокоиться, работает ли агрегатная функция, например, SUM на небольшом типе?Что произойдет, если SQL sum() достигнет типа емкости (переполнения)?

Например, MariaDB использует 4 байта для типа INT. Разработчики могут предположить, что каждая транзакция имеет сумму не более нескольких тысяч.

Но что произойдет, если мы попытаемся получить доход в течение целого года для всех отделов? Например .:

-- 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' 
+1

Я думаю, что вы ответили на свой вопрос. Да, это зависит от поставщика, и помощь в этом случае будет полезной. Не могли бы вы переполнить bigint? теоретически. Поэтому вам нужно, основываясь на данных, которые вы будете хранить, не могли бы вы переполнить это. – DBug

+0

@a_horse_with_no_name Спасибо за исправление! Если SQL Server обработчик переполнения, что я должен делать на стороне клиента? Я должен выбрать более крупный тип данных в коде клиента JDBC/ODBC? – gavenkoa

+0

На стороне клиента вы должны принять это во внимание, да. –

ответ

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 

Это значит, там может действительно быть переполнением. Поэтому я рекомендую вам использовать тип float или money для окладов, а не тип int.

+0

Спасибо, по крайней мере, некоторые поставщики поставляют информацию. https://mariadb.com/kb/en/mariadb/sum/ нет никаких заявлений ((я достиг предела досрочного голосования, буду делать завтра. – gavenkoa

3

Это довольно легко проверить на MySQL:

Переполнение 32bit:

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) 

64bit:

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) 

Double:

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 | 
+--------+ 

Это довольно легко проверить на mysql:

Переполнение 32bit:

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) 

64bit:

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) 

Double:

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 | 
+--------+ 

комментарий Followup:

mysql> describe overflow 
    -> ; 
+-------+------------+------+-----+---------+-------+ 
| Field | Type  | Null | Key | Default | Extra | 
+-------+------------+------+-----+---------+-------+ 
| x  | int(11) | YES |  | NULL |  | 
| y  | bigint(20) | YES |  | NULL |  | 
| z  | double  | YES |  | NULL |  | 
+-------+------------+------+-----+---------+-------+ 
3 rows in set (0.00 sec) 

mysql> select * from overflow; 
+------------+---------------------+---------+ 
| x   | y     | z  | 
+------------+---------------------+---------+ 
| 2147483647 | 9223372036854775807 | 1.7e308 | 
| 2147483647 | 9223372036854775807 | 1.7e308 | 
| 2147483647 | 9223372036854775807 | 1.7e308 | 
+------------+---------------------+---------+ 
3 rows in set (0.00 sec) 

mysql> select sum(x), sum(y), sum(z) from overflow; 
+------------+----------------------+--------+ 
| sum(x)  | sum(y)    | sum(z) | 
+------------+----------------------+--------+ 
| 6442450941 | 27670116110564327421 |  0 | 
+------------+----------------------+--------+ 
1 row in set (0.00 sec) 
+1

Какой тип данных 'pow (2,31)' return? bigint или int –

+0

ну, я получаю то же самое значение, если я hardcode 2147483648 вместо pow (...). Pow (2,63) действительно возвращает float. –

+0

хм .. с проблемой сохранения другого редактирования, но hardcoding 2^63 Возвращает значение 27670116110564327424, что превышает максимальный максимум 64 бит int. –

2

Postgres обрабатывает это без переполнения или усечения:

Из инструкции:

сумма (выражение), тип возвращаемых данных: BIGINT для SMALLINT или ИНТ аргументов, числовой для BIGINT аргументы, в противном случае то же самое как тип аргумента данных

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

И быстрый тест доказывает, что:

psql (9.4.5) 
Type "help" for help. 

postgres=> create table x (amount int); 
CREATE TABLE 
postgres=> 
postgres=> insert into x values (2147483647), (2147483647); 
INSERT 0 2 
postgres=> select sum(amount) 
wbtest-> from x; 
    sum 
------------ 
4294967294 
(1 row) 

postgres=> 

Интересный достаточно стандартный SQL требует заявление неудачу в этой ситуации:

Если при вычислении результата AF, промежуточный результат не представляется в объявленный тип сайта, который содержит этот промежуточный результат, затем
...
В противном случае возникает условие исключения: dat исключение - числовое значение вне диапазона.

(AF = агрегатная функция)

+0

Этот выпуск спец. SQL 92/2008? – gavenkoa

+0

@ gavenkoa: SQL: 2003 –

Смежные вопросы