Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Microsoft SQL Server |
![]() ![]() |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
Сижу на работе трезвый:WITH t1(p) AS ( SELECT 1.11 UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;
Как так получилось? |
|||||||
5 янв 15, 16:01 [17086798] Ответить | Цитировать Сообщить модератору |
Glory Member Откуда: Сообщений: 104751 |
Обычная ошибка того, кто считает, что по его правилам сервер должен определять размер и точность констант WITH t1(p) AS ( SELECT 1.110 UNION ALL SELECT 1.110 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1; |
||
5 янв 15, 16:14 [17086834] Ответить | Цитировать Сообщить модератору |
SQL2008 Member Откуда: Москва Сообщений: 4422 |
Дело в неявном приведении типов Вот пример WITH t1(p) AS ( SELECT cast(1.11 as money) UNION ALL SELECT cast(1.11 as money) ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1; |
5 янв 15, 16:28 [17086858] Ответить | Цитировать Сообщить модератору |
Jovanny Member Откуда: Сообщений: 1196 |
WITH t1(p) AS ( SELECT CAST(1.11 AS decimal(4,2)) UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;
WITH t1(p) AS ( SELECT CAST(1.11 AS decimal(4,3)) UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;
WITH t1(p) AS ( SELECT CAST(1.11 AS real) UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;
WITH t1(p) AS ( SELECT CAST(1.11 AS float) UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;
|
||||||||||||||||||||||||||||
5 янв 15, 16:39 [17086894] Ответить | Цитировать Сообщить модератору |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
Нет, сервер должен определять по документации. Константа 1.11 имеет тип DECIMAL(3, 2), а 2.225 имеет тип DECIMAL(4, 3), ибо decimal и numeric (Transact-SQL) гласит:
Тип функции SUM (Transact-SQL) должен быть DECIMAL(38, 2). А после вычитания, как утверждает Точность, масштаб и длина (Transact-SQL), масштаб должен получится max(s1, s2). То есть, округления тут в принципе получится не может. Более того, явный каст суммы: WITH t1(p) AS ( SELECT 1.11 UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - CAST(SUM(t1.p) AS DECIMAL(18, 2)) a2 FROM t1; Даёт правильный результат:
|
|||||||||||||
5 янв 15, 18:02 [17087084] Ответить | Цитировать Сообщить модератору |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
|
||
5 янв 15, 18:06 [17087100] Ответить | Цитировать Сообщить модератору |
Диклевич Александр Member Откуда: Сообщений: 611 |
Dmitry V. Liseev, Хм, а вот так тоже странно WITH t1(p) AS ( SELECT 1.11 UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - CAST(2.22 AS [numeric](38, 2)) a1, 2.225 - SUM(t1.p) a2 FROM t1;
Похоже что-то не то если максимальная точность одного из слагаемых 38. Вот declare @SQL [nvarchar](MAX) = 'WITH t1(p) AS ( SELECT 1.11 UNION ALL SELECT 1.11 ) SELECT SUM(t1.p) s1, 2.225 - 2.22 a1, 2.225 - SUM(t1.p) a2 FROM t1;' SELECT name, system_type_name FROM sys.dm_exec_describe_first_result_set(@SQL, NULL, 0) ORDER BY column_ordinal;
В MSDN говорится что-то на сей счет "Точность и масштаб результата имеют абсолютный максимум, равный 38. Если значение точности превышает 38, то соответствующий масштаб уменьшается, чтобы по возможности предотвратить усечение интегральной части результата." Может поэтому? Хотя тоже интересно. |
||||||||||||||||
5 янв 15, 18:40 [17087174] Ответить | Цитировать Сообщить модератору |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
|
||
5 янв 15, 22:22 [17087742] Ответить | Цитировать Сообщить модератору |
Glory Member Откуда: Сообщений: 104751 |
Конечно не может select cast(2.225 as numeric(5,3)) - cast(2.22 as numeric(38,2)) e1 - e2 max(s1, s2) + max(p1-s1, p2-s2) + 1 = max(3,2)+max(5-3,38-2)+1 = 2+36+1 = 39 max(s1, s2) = 3 Т.к numeric(39,3) не существует, то что по вашему будет делать сервер ? |
||
6 янв 15, 09:30 [17088502] Ответить | Цитировать Сообщить модератору |
Диклевич Александр Member Откуда: Сообщений: 611 |
Glory, Так как "...значение точности превышает 38, то соответствующий масштаб уменьшается, чтобы по возможности предотвратить усечение интегральной части результата..." и получаем (38, 2). Так получается? |
6 янв 15, 11:51 [17088744] Ответить | Цитировать Сообщить модератору |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
|
||||
6 янв 15, 14:39 [17089248] Ответить | Цитировать Сообщить модератору |
Dmitry V. Liseev Member [заблокирован] Откуда: Санкт-Петербург Сообщений: 5489 |
А почему не (38,3)? Меня бы даже (5,3) в данной задаче устроило. |
||
6 янв 15, 14:42 [17089261] Ответить | Цитировать Сообщить модератору |
Glory Member Откуда: Сообщений: 104751 |
Это вы видите, что вы суммируете два раза 1.11. А оптимизатор не может заранее знать, какое именно число вернет агрегатная функция. И согласно вашей же ссылке вполне оправданно считает, что "Тип функции SUM (Transact-SQL) должен быть DECIMAL(38, 2).", в котором вполне может оказать и 1E35 |
||
6 янв 15, 16:34 [17089669] Ответить | Цитировать Сообщить модератору |
Все форумы / Microsoft SQL Server | ![]() |