AVG. Типы возвращаемых значений.

PetrovichSK
Дата: 29.04.2015 08:35:59
Доброго всем времени. Разбираясь с разницей в точности значений для SUM и AVG наткнулся на веселую штуку в BOL.
AVG (Transact-SQL)

Результат выражения | Тип возвращаемого значения
категория decimal (p, s) | decimal(38, s), деленное на decimal(10, 0)

Ок. Вроде все понятно. Однако...
Точность, масштаб и длина (Transact-SQL)
Операция | Точность результата | Масштаб результата *
e1 / e2 | p1 - s1 + s2 + max(6, s1 + p2 + 1) | max(6, s1 + p2 + 1)
* Точность и масштаб результата имеют абсолютный максимум, равный 38. Если значение точности превышает 38, то соответствующее значение масштаба уменьшается, чтобы по возможности предотвратить усечение целой части результата.

Учитывая, что все кроме s1 у нас константы (p1 = 38, p2 = 10, s2 = 0) и тот факт, что s1 + p2 + 1 всегда больше 6, получаем точность AVG для любого decimal (p, s) 38+11=49 и масштаб s + 11. Используя уточнение в сноске (*) имеем, что AVG по decimal (p, s) будет иметь тип decimal (38, s). Однако это не соответствует действительности для s < 6. В этом случае он = 6.
Да и вообще зачем такая формулировка "Тип возвращаемого значения decimal(38, s), деленное на decimal(10, 0)"?
Может я где-то не прав или что-то пропустил?
Glory
Дата: 29.04.2015 08:41:38
PetrovichSK
Да и вообще зачем такая формулировка "Тип возвращаемого значения decimal(38, s), деленное на decimal(10, 0)"?

Наверное потому, что среднее = сумма / количество
PetrovichSK
Дата: 29.04.2015 08:52:54
Glory
PetrovichSK
Да и вообще зачем такая формулировка "Тип возвращаемого значения decimal(38, s), деленное на decimal(10, 0)"?

Наверное потому, что среднее = сумма / количество

Только чтобы показать, что AVG есть результат деления суммы значений на количество отобранных записей? ;)
Да ведь по итогу не дает обещанный тип данных при s<6.
Glory
Дата: 29.04.2015 09:01:29
PetrovichSK
Только чтобы показать, что AVG есть результат деления суммы значений на количество отобранных записей? ;)

Количество(делитель) - это всегда целое цисло

(все) int / (все) int есть (все) int - хоть в функции, хоть не в функции
float/ int есть float - хоть в функции, хоть не в функции
...

А вот с numeric-ами просто описано, что делитель будет decimal(10, 0)
Потому что только для decimal существуют правила для вычисления точности, масштаба и длины результата
PetrovichSK
Дата: 29.04.2015 09:17:30
Glory
Количество(делитель) - это всегда целое цисло

(все) int / (все) int есть (все) int - хоть в функции, хоть не в функции
float/ int есть float - хоть в функции, хоть не в функции
...

А вот с numeric-ами просто описано, что делитель будет decimal(10, 0)
Потому что только для decimal существуют правила для вычисления точности, масштаба и длины результата

Правильно. Однако при типе делителя decimal(10, 0) (фиксированные масштаб и длина) формула сводится к результату decimal(38, s).
Возможно в будущих версиях не напишут decimal(16, 0) и не надо будет переписывать вторую статью.
А вот почему тип не соответствует заявленному при s < 6?
Glory
Дата: 29.04.2015 09:39:21
PetrovichSK
А вот почему тип не соответствует заявленному при s < 6?

Что ?
Guf
Дата: 29.04.2015 10:14:35
Вы же сами посчитали
PetrovichSK
получаем точность AVG для любого decimal (p, s) 38+11=49 и масштаб s + 11

Для любого decimal (p, s) получаем точность AVG decimal (49, s+11).
А дальше, согласно той самой сноске, как только p = 49 > 38, сервер старается "спасти" как можно больше значащих цифр в целой части.
Как? Ни где не описано. Ни как не гарантируется.
PetrovichSK
А вот почему тип не соответствует заявленному при s < 6

По этому нет ни какого несоответствия, от s уже ничего не зависет.
PetrovichSK
Дата: 29.04.2015 10:21:45
Glory
Что ?

Точность, масштаб и длина (Transact-SQL)
Операция | Точность результата | Масштаб результата *
e1 / e2 | p1 - s1 + s2 + max(6, s1 + p2 + 1) | max(6, s1 + p2 + 1)
* Точность и масштаб результата имеют абсолютный максимум, равный 38. Если значение точности превышает 38, то соответствующее значение масштаба уменьшается, чтобы по возможности предотвратить усечение целой части результата.

declare @e1 dec(38,4) = 1., @e2 dec(10,0) = 1.
select @e1/@e2

p1 = 38, s1 = 4, p2 = 10, s2 = 0
Точность результата: p1 - s1 + s2 + max(6, s1 + p2 + 1) = 38 - 4 + max(6, 4 +10 + 1) = 49
Масштаб результата: max(6, s1 + p2 + 1) = max(6, 4 + 10 + 1) = 15
* Точность результата: 38. Масштаб результата: 15 - (49 - 38) = 4
результат должен иметь тип decimal(38, 4)
На самом деле decimal(38, 6)
Glory
Дата: 29.04.2015 10:26:30
PetrovichSK
Масштаб результата: 15 - (49 - 38) = 4

Откуда эта формула ?
PetrovichSK
Дата: 29.04.2015 10:30:41
Guf
Вы же сами посчитали
PetrovichSK
получаем точность AVG для любого decimal (p, s) 38+11=49 и масштаб s + 11

Для любого decimal (p, s) получаем точность AVG decimal (49, s+11).
А дальше, согласно той самой сноске, как только p = 49 > 38, сервер старается "спасти" как можно больше значащих цифр в целой части.
Как? Ни где не описано. Ни как не гарантируется.
PetrovichSK
А вот почему тип не соответствует заявленному при s < 6

По этому нет ни какого несоответствия, от s уже ничего не зависет.

Guf, уважаемый, т.е фразу "* Точность и масштаб результата имеют абсолютный максимум, равный 38. Если значение точности превышает 38, то соответствующее значение масштаба уменьшается, чтобы по возможности предотвратить усечение целой части результата." Вы трактуете как "сервер старается "спасти" как можно больше значащих цифр в целой части"?
Тип зависит от самих данных?