DWH-ETL-OLAP
August 30, 2019

Деления и временные таблицы на SQL Server

Только что прошелся по довольно болезненным граблям. Болезненным в плане самооценки :)

Кейс следующий, есть продажи в определенных разрезах, есть бонусы от контрагентов, в укрупненных, относительно продаж разрезах. Т.е. если продажи по куче разных атрибутов (дата, организация, контрагент, номенклатура, договор, счет БУ и тд), то бонусы только в разрезах (дата, организация, контрагент). И соответственно надо как то добавить их в отчетную таблицу, т.е. сджойнить 2 таблицы фактов (да-да, так делать нельзя, но бонусы - очень маленькая таблица фактов и бизнес-логика требует распределить бонусы по остальным атрибутам пропорционально продажам), и представить их в виде отчетной таблицы для потребителей BI.

Решение следующее, считаем агрегаты по сумме продаж в разрезах "дата, организация, контрагент". Затем пропорционально детальным суммам продаж распределяем бонусы. НО. Если мы чтото делим, то, как правило, получаем значением с БОЛЬШИМ количеством значащих символов после запятой, чем исходные делимое и делитель. 1/3 = 0,33333... . Но SELECT 1 / 3 выдаст 0, тк возьмет тип данных результата из исходных типов, а там - целое число в обоих случаях, в итоге происходит округление результата до целого.

Если исходные типы вида numeric, то в общем случае там все нормально при делении. Результат формируется с нужным количеством десятичных знаков, гораздо большим чем у исходных типов. Но магия начинается если мы огульно используем SELECT INTO #temptable. Исходные типы - numeric(15,4), а во временной таблице - numeric(38,4) ! И затем при делении numeric(38,4) на numeric(38,4), получаем numeric(38,6) !!! Чего может быть уже не достаточно для точного распределения.

Отсюда вывод, необходимо точно прописывать все временные таблицы, используемые в расчетах.