|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Всем привет! Имеется такая проблема. Есть таблица в SQL Server'е, в которой есть поле с типом данных "float(24)". Вывожу эту таблицу в Excel через Range.CopyFromRecordset. В этом поле есть значение "0,22". Вот результаты тестов: 1) При выводе на лист Range.CopyFromRecordset преобразует "0,22" в "0,219999998807907". 2) При выводе в "умную таблицу" значение корректно выводится - "0,22". 3) Если поменять тип данных на float(25), то есть уже 8 байт, то Range.CopyFromRecordset корректно выводит на лист "0,22". Итак, чтобы корректно вывести "0,22", мне нужно увеличить размер типа данных аж в два раза, что не очень-то политкорректно. Умная таблица тоже разочаровала: если перед записью данных очистить таблицу, то DataBodyRange будет Nothing, и из-за этого CopyFromRecordset выдаст оишбку. Чтобы этого не было, надо искусственно добавить туда что-то (хоть единичку). Это уже какие-то грязные хаки. Собственно, вопрос - как заставить Эксель, чтобы он корректно выводил float(24) на лист? :) ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 17:32 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoid, float - "в принципе" неточный, "приближённый" тип данных, и, раз его "неточность" создаёт проблему, то скорее всего выбран в таблице ошибочно. В МС СКЛ есть точные типы для хранения дробных значений - money, decimal. Так что самое правильное было бы изменить тип. Если это сделать нельзя, то можно приводить к другому типу в запросе-источнике рекордсета cast(f as decimal(18,2)) или просто round(f, 2) ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 17:42 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
castfloat - "в принципе" неточный, "приближённый" тип данных А почему тогда с float(25) нет проблем? ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 18:22 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidcastfloat - "в принципе" неточный, "приближённый" тип данных А почему тогда с float(25) нет проблем? Вот "захочешь" 3-ю, 4-ую, ...., 8-ую точную цифру, после запятой - появятся проблемы и с float(25) :) ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 18:58 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Decimal юзать тоже как-то не очень охота использовать ради того, чтобы Экселю понравилось. Может, вообще захреначить varchar - и головушку не забивать. ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 19:04 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Ну ладно... А почему умная таблица всё корректно сделала? ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2015, 19:08 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidDecimal юзать тоже как-то не очень охота использовать ради того, чтобы Экселю понравилось. Может, вообще захреначить varchar - и головушку не забивать. какого рода данные ты там хранишь? Если деньги с точностью до копеек или количество с точностью до трех знаков после запятой, то как раз стоит подумать о смене типа ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2015, 08:00 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
andreymx, Данные - не деньги. Но после запятой будет не более двух знаков - точно. Выгружал данные из скуля в Access - всё ОК. Выходит корректно 0,22. Использовать такие хаки как использование decimal или float(25) не совсем корректно ради того, чтобы в Эксель выгрузилось нормально. Преобразовывать данные на лету - тоже не хочется (тем более, что полей очень много). Это надо писать портянку из 30-40 столбцов ради того, чтобы преобразовать пару столбцов. Можно вместо CopyFromRecordset "вручную" перенести данные через While..Wend, но тут всё равно надо знать, какие столбцы преобразовывать, да и получается намного медленне. В общем, зашёл в тупик... ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2015, 23:35 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
[quot MrVoidпосле запятой будет не более двух знаков - точно[/quot]Округлите до 2 знаков после выгрузки на лист. Без цикла Код: vbnet 1.
... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 01:02 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Да все эти хаки я знаю. Можно и хранимую процедуру написать, чтобы всё красиво было. Но это всё ради капризов экселя. :( Спасибо всем! Поведение Экселя осталось невыясненным. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 09:06 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidДа все эти хаки я знаю. Можно и хранимую процедуру написать, чтобы всё красиво было. Но это всё ради капризов экселя. :( Спасибо всем! Поведение Экселя осталось невыясненным. тьху! Что ж ты никак не поймешь-то?! Не при чём тут Эксель! Там, в таблице, реально хранится 0,219999998807907, хотя сохраняли 0,22! А происходит так, потому что в експ.форме, в двоичной системе счисления, десятичное 0.22 представляется бесконечной дробью! Поиграйся http://math.semestr.ru/inf/ieee754.php Представление двоичного числа с плавающей точкой в экспоненциальном нормализованном виде. Для этого переведем число в двоичное представление. Для перевода дробной части числа последовательно умножаем дробную часть на основание 2. В результате каждый раз записываем целую часть произведения. 0.22*2 = 0.44 (целая часть 0) 0.44*2 = 0.88 (целая часть 0) 0.88*2 = 1.76 (целая часть 1) 0.76*2 = 1.52 (целая часть 1) 0.52*2 = 1.04 (целая часть 1) 0.04*2 = 0.08 (целая часть 0) 0.08*2 = 0.16 (целая часть 0) 0.16*2 = 0.32 (целая часть 0) 0.32*2 = 0.64 (целая часть 0) 0.64*2 = 1.28 (целая часть 1) 0.28*2 = 0.56 (целая часть 0) 0.56*2 = 1.12 (целая часть 1) 0.12*2 = 0.24 (целая часть 0) 0.24*2 = 0.48 (целая часть 0) 0.48*2 = 0.96 (целая часть 0) 0.96*2 = 1.92 (целая часть 1) 0.92*2 = 1.84 (целая часть 1) 0.84*2 = 1.68 (целая часть 1) 0.68*2 = 1.36 (целая часть 1) 0.36*2 = 0.72 (целая часть 0) 0.72*2 = 1.44 (целая часть 1) 0.44*2 = 0.88 (целая часть 0) 0.88*2 = 1.76 (целая часть 1) Получаем число в 2-ой системе счисления: 00111000010100011110101 0.22 = 00111000010100011110101 2 Сдвинем число на 3 разрядов вправо. В результате мы получили основные составляющие экспоненциального нормализованного двоичного числа: Мантисса M=1.11000010100011110101000 Экспонента exp2=-3 Преобразование двоичного нормализованного числа в 32 битный формат IEEE 754. Первый бит отводится для обозначения знака числа. Поскольку число положительное, то первый бит равен 0 Следующие 8 бит (с 2-го по 9-й) отведены под экспоненту. Для определения знака экспоненты, чтобы не вводить ещё один бит знака, добавляют смещение к экспоненте в половину байта +127. Таким образом, наша экспонента: -3 + 127 = 124 Переведем экспоненту в двоичное представление. 124 = 11111002 Оставшиеся 23 бита отводят для мантиссы. У нормализованной двоичной мантиссы первый бит всегда равен 1, так как число лежит в диапазоне 1 ≤ M < 2. Для экономии, единицу не записывают, а записывают только остаток от мантиссы: 11000010100011110101000 Для перевода необходимо умножить разряд числа на соответствующую ему степень разряда. 11000010100011110101000 = 222*1 + 221*1 + 220*0 + 219*0 + 218*0 + 217*0 + 216*1 + 215*0 + 214*1 + 213*0 + 212*0 + 211*0 + 210*1 + 29*1 + 28*1 + 27*1 + 26*0 + 25*1 + 24*0 + 23*1 + 22*0 + 21*0 + 20*0 = 4194304 + 2097152 + 0 + 0 + 0 + 0 + 65536 + 0 + 16384 + 0 + 0 + 0 + 1024 + 512 + 256 + 128 + 0 + 32 + 0 + 8 + 0 + 0 + 0 = 6375336 В десятичном коде мантисса выражается числом 6375336 В результате число 0.22 представленное в IEEE 754 c одинарной точностью равно 0111110011000010100011110101000. Переведем в шестнадцатеричное представление. Разделим исходный код на группы по 4 разряда. 01111100110000101000111101010002 = 0011 1110 0110 0001 0100 0111 1010 1000 2 Получаем число: 0011 1110 0110 0001 0100 0111 1010 1000 2 = 3E6147A816 Проверим правильность перевода. Чтобы записать число в стандарте IEEE 754 или восстановить его, необходимо знать три параметра: S - бит знака (31-й бит). E - смещенная экспонента (30-23 биты). M - остаток от мантиссы (22-0 биты). Формула для получения десятичного числа из числа IEEE754 одинарной точности: F = (-1)S2(E-127)(1+M/223) F = (-1)02(124-127)(1+6375336/223) = 0.125*1.75999927 = 0.21999990 Итого: если нужно точное представление дес.дробей, нужно использовать или decimal - в котором хранится двоичное представление последовательности десятичных цифр или money - в котором хранится умноженное на 10000 исх.десятичное число, как двоичное целое число ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 10:35 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
castтьху! Что ж ты никак не поймешь-то?! Не при чём тут Эксель! А почему тогда Access НЕ показывает эту бесконечную дробь? И заметьте, что я не провожу каких-либо математических операций с этой цифрой. Провёл такой тест. В скуле дёрнул эти 0,22 и сравнил с 0,22. Результат - True. Они равны. Следовательно, Эксель делает какие-то левые преобразования на лету. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 11:48 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Приведи код сравнения. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:02 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidА почему тогда Access НЕ показывает эту бесконечную дробь?потому что существует форматирование при выводе MrVoidПровёл такой тест. В скуле дёрнул эти 0,22 и сравнил с 0,22. Результат - Trueпри сравнении операнды приводятся к одному типу (неявно в данном случае), поэтому они и равны. Еще раз, в экспоненциальной форме хранятся принципиально неточные числа (они хранятся с определенной заданной точностью), для точных чисел есть неэкпоненциальные типы. Если очень хочется увидеть своими глазами, можно провести эксперимент - сложить в цикле это число N раз. Отдельно умножить это число на N. И сравнить результат. Вот наглядный пример для экселя. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:05 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidПровёл такой тест. В скуле дёрнул эти 0,22 и сравнил с 0,22. Результат - Trueвот так попробуй Код: vbnet 1. 2. 3. 4. 5. 6. 7. 8.
... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:10 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Shocker.ProMrVoidА почему тогда Access НЕ показывает эту бесконечную дробь?потому что существует форматирование при выводе Щито? Причём тут форматирование? Эксель преобразовывает , а не форматирует. Вот скрипт в скуле: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:12 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Shocker.ProMrVoidПровёл такой тест. В скуле дёрнул эти 0,22 и сравнил с 0,22. Результат - True К тому же в скуле не бывает True. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:13 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
Shocker.ProMrVoidПровёл такой тест. В скуле дёрнул эти 0,22 и сравнил с 0,22. Результат - Trueвот так попробуй Код: vbnet 1. 2. 3. 4. 5. 6. 7. 8.
Причём тут математика? Я *НЕ делаю* арифмитеческих действий. Ондастанд? ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:13 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
FК тому же в скуле не бывает True. Имелось ввиду, что они одинаковы. Не надо умничать. :) ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:17 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidПричём тут математика? Я *НЕ делаю* арифмитеческих действий. Ондастанд?А в чем у тебя тогда проблема? Ты сомневаешься, что число хранится в неточном виде - я продемонстрировал, как это увидеть, можно то же самое написать на TSQL. Ты не понимаешь, почему два одинаковых числа адекватно сравниваются? Я объяснил (или не андестенд?) Ты путаешь способ форматирования чисел при выводе и способ хранения, поэтому не понимаешь то, что видишь своими глазами. MrVoidЭксель преобразовывает , а не форматирует.Эксель ничего в данном случае не преобразовывает ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:24 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidFК тому же в скуле не бывает True. Имелось ввиду, что они одинаковы. Не надо умничать. :) Тролль детектид. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:28 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
@Shocker.Pro То есть скуль меня намахивает, когда показывает, что он хранит 0,22, а на самом деле - "0,219999998807907"? А Access тогда что делает, что корректно выводит 0,22? ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:31 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
FТролль детектид. Это ты тролль. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:33 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoid@Shocker.Pro То есть скуль меня намахивает, когда показывает, что он хранит 0,22, а на самом деле - "0,219999998807907"? наконец дошло Чтобы в этом убедиться, возьми его и просуммируй в цикле, как я показывал. Число может быть не совсем это (все будет зависеть от точности, тут похоже на одинарную точность), но оно не 0,22 ровно. Ровно будет, если будешь использовать decimal или money MrVoidА Access тогда что делает, что корректно выводит 0,22? форматирует при выводе, для твоего удобства ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:39 |
|
Неверный вывод цифр при импорте из SQL Server'а
|
|||
---|---|---|---|
#18+
MrVoidТо есть скуль меня намахивает, когда показывает, что он хранит 0,22, а на самом деле - "0,219999998807907"на самом деле, он хранит нолики и единички. Хранить их можно по-разному. Чтобы не писать тебе тут лекцию, почитай про двоично-десятичные преобразования и формат и операции с плавающей точкой (если интересно, конечно) ... |
|||
:
Нравится:
Не нравится:
|
|||
31.03.2015, 12:42 |
|
|
start [/forum/topic.php?fid=61&msg=38922208&tid=2173566]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
30ms |
get topic data: |
10ms |
get forum data: |
2ms |
get page messages: |
64ms |
get tp. blocked users: |
2ms |
others: | 12ms |
total: | 151ms |
0 / 0 |