Исправление ошибки арифметического переполнения при преобразовании numeric к типу данных numeric при расчете себестоимости




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

22 Comments

  1. v3rter

    Плюсану, поскольку сталкивался и лечил такие проблемы в самопальных складских программах.

    Reply
  2. alex_4x

    В данном случае помогло, но это не факт, что всегда поможет.

    Проблема может быть не только с длиной целой части, но и длиной дробной части.

    Суть ошибки в том, что во время вычисления — SQL не может преобразовать тип внутри вычисления как правило умножения или деления. Решается не обязательно увеличением разрядности, достаточно ВЫРАЗИТЬ( Значение , ХХ,ХХ) использовать для всех вычисляемых аргументов в том числе внутри скобок. Тогда SQL не занимается самодеятельностью по выбору типа внутри самого вычисления и ошибка не происходит.

    Ну примерно так:

    Было:

     ВЫРАЗИТЬ(СУММА(ЕСТЬNULL(ВтТаблицаРешений.ПостояннаяРазница, 0) * ЕСТЬNULL(ПеремещенияСписания.Количество, 0)) КАК ЧИСЛО(23, 10)))
    

    Будет

    ВЫРАЗИТЬ
    СУММА(ВЫРАЗИТЬ ЕСТЬNULL(ПеремещенияСписания.Количество, 0) КАК ЧИСЛО(23, 10) *
    ВЫРАЗИТЬ ЕСТЬNULL(ПеремещенияСписания.Количество, 0) КАК ЧИСЛО(23, 10) )
    КАК ЧИСЛО(23, 10)
    Reply
  3. v3rter

    При таких расчетах могут накапливаться и ошибки округления дробной части, здесь это нивелируется десятью знаками после запятой ЧИСЛО(…, 10). Попутно может всплыть проблема сравнения итогов с нулём или константой, так как из-за накопления ошибок округления дробной части выглядеть она будет как -0.0001 < x <0,0001

    Reply
  4. a.artemov

    Коллеги прошу помощи.

    Увеличение разрядности не помогло.

    Ошибка осталась. Кто может помочь?

    Ошибка при выполнении обработчика — ‘ОбработкаПроведения’

    по причине:

    {ОбщийМодуль.КорректировкаСтоимостиУчетЗатрат.Модуль(403)}: Ошибка при вызове метода контекста (Выполнить)

    Док.Записать(РежимЗаписиДокумента.Проведение);

    по причине:

    Ошибка выполнения запроса

    по причине:

    Ошибка при выполнении операции над данными:

    Microsoft SQL Server Native Client 11.0: Ошибка арифметического переполнения при преобразовании numeric к типу данных numeric.

    HRESULT=80040E57, SQLSrvr: SQLSTATE=22003, state=8, Severity=10, native=8115, line=1

    Код такой:

    СУММА(ВЫРАЗИТЬ(
    |  ВЫБОР КОГДА УчетЗатрат.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) ТОГДА
    |   УчетЗатрат.Стоимость
    |  ИНАЧЕ
    |   0
    |  КОНЕЦ
    | КАК ЧИСЛО(38,10))) КАК Стоимость
    Reply
  5. Al-77

    (5) Какая конфигурация?

    Reply
  6. Al-77

    Какая конфигурация?

    Reply
  7. a.artemov

    Управление производственным предприятием, редакция 1.3 (1.3.89.2)

    Если есть возможность помочь для более оперативного общения контакты на почту прислать? У меня каждый день на счету.

    Reply
  8. rintik

    А если попробовать поменять

    | КАК ЧИСЛО(38,10))) КАК Стоимость

    на

    | КАК ЧИСЛО(32,10))) КАК Стоимость
    Reply
  9. корум

    (9) читаем статью, «не хватает знаков ДО запятой», метод решения:

    Если есть строчки ВЫРАЗИТЬ(<ВыбранноеПоле> КАК ЧИСЛО (23,10)) изменяем их на ВЫРАЗИТЬ(<ВыбранноеПоле> КАК ЧИСЛО (25,10)) и радуемся результату.

    Читаем (9) и понимаем, что уменьшение знаков до запятой не поможет…

    Reply
  10. Al-77

    У меня такая же ситуация, только последняя УТ 11.3.3.231 я уже 2 месяца пытаюсь найти в данных проблему. пробовал увеличить разрядность, помогло на два месяца потом опять стала ошибка.

    Reply
  11. a.artemov

    (9) Начинали с 25,10 дошли до 38,10 не помогает. ТЬочнее попробовал 40,10 ругнулась что перебор…

    Reply
  12. a.artemov

    Проблема не решена. Помогите кто может.

    Reply
  13. Napalmmm

    Вот и я попал. (37,10) стояло больше двух лет, сейчас не спасло. Решения нет?

    Reply
  14. see888

    Теперь и я) как перевел базу на с 11.1 на 11.3.4… даже не пойму что он там по кругу выполняет,с каждым выполнением отклонение растет. Что это такое вообще? Кто сможет объяснить:

    Дополнительная информация об этапе:

    — Отклонение на текущей итерации: 42 631,8

    — Отклонение на текущей итерации: 24 780

    — Отклонение на текущей итерации: 21 311,8

    — Отклонение на текущей итерации: 17 797,43

    — Отклонение на текущей итерации: 7 800

    — Отклонение на текущей итерации: 20 588,5568513129

    — Отклонение на текущей итерации: 20 588,556851313

    — Отклонение на текущей итерации: 73 530,5601832607

    — Отклонение на текущей итерации: 73 530,5601832608

    — Отклонение на текущей итерации: 262 609,1435116457

    — Отклонение на текущей итерации: 262 609,1435116456

    — Отклонение на текущей итерации: 937 889,7982558771

    — Отклонение на текущей итерации: 937 889,798255877

    — Отклонение на текущей итерации: 3 349 606,4223424179

    — Отклонение на текущей итерации: 3 349 606,422342418

    — Отклонение на текущей итерации: 11 962 880,07979435

    — Отклонение на текущей итерации: 11 962 880,07979435

    — Отклонение на текущей итерации: 42 724 571,71355125

    — Отклонение на текущей итерации: 42 724 571,71355125

    — Отклонение на текущей итерации: 152 587 756,1198258929

    — Отклонение на текущей итерации: 152 587 756,119825893

    — Отклонение на текущей итерации: 544 956 271,8565210464

    — Отклонение на текущей итерации: 544 956 271,8565210464

    — Отклонение на текущей итерации: 1 946 272 399,4875751657

    — Отклонение на текущей итерации: 1 946 272 399,4875751656

    — Отклонение на текущей итерации: 6 950 972 855,3127684486

    — Отклонение на текущей итерации: 6 950 972 855,3127684486

    — Отклонение на текущей итерации: 24 824 903 054,688458745

    — Отклонение на текущей итерации: 24 824 903 054,688458745

    — Отклонение на текущей итерации: 88 660 368 052,4587812321

    — Отклонение на текущей итерации: 88 660 368 052,458781232

    — Отклонение на текущей итерации: 316 644 171 615,9242186857

    Это то что под приложением выдал из состоянии расчета.

    А в отладчике последнее значение было таково :

    267 488 214 754 648 642 684 559 809,9800832

    и это на 85 Итерации из 200 как он показывает.

    Что тут вообще происходит?)

    Reply
  15. Glav

    Такая же проблема. Увеличение разряда не помогает УТ 11.3.4.124

    Reply
  16. jefjef

    Смысл ошибки можно сформулировать проще.

    Запрос не может выразить полученное при исполнении числовое значение, так как в результате получено число больше, чем разрешено условиями запроса.

    Если будет конструкция ВЫРАЗИТЬ(1,0) а запросу попадется число 11, то он не сможет выразить его числом от 0 до 9.

    Так то у вас все написано правильно, но к сути проблемы докопаться сложно.

    Reply
  17. dap

    (3)

    Странно, но ошибка эта может вываливаться просто на счетчике.

    Вот строка запроса в обработке базопузомера:

    Подсчитывалось количество записей в регистре сведений

    | СУММА(1) КАК Счетчик

    Вот этот счетчик и выдал ошибку. Количество записей в самом большом регистре было около 62 млн. записей

    и нормально заработала по вашему совету вот так:

    | СУММА(ВЫРАЗИТЬ (1 КАК Число(23,0))) КАК Счетчик

    плюсую

    Reply
  18. svetanik
    Reply
  19. Afandi

    Такая же проблема. Запрос к регистру ВыручкаИСебестоимостьПродаж показал что каждый документ записан 2 раза один раз с правильным количеством товара и суммы. а второй раз с правильной суммой а количество равное нулю. После отмены проведения и повторно ручного проведения запись документа в этом регистре с нулевым количеством исчезает. Это стандартное поведение или ошибка в системе?

    Reply
  20. TelekaevAB
    Reply
  21. kabantus
    Reply
  22. Red_Devil

    (3)тоже самое. Пришлось всем полям ВЫРАЗИТЬ писать. Тогда ошибка ушла

    СУММА(ВЫРАЗИТЬ(
    |  ВЫБОР КОГДА ВЫРАЗИТЬ(УзлыКорректировкиСтоимостиСписания.Количество КАК ЧИСЛО(23, 10)) <> 0 ТОГДА
    |   ВЫРАЗИТЬ(ТаблицаРешений.Стоимость КАК ЧИСЛО(23, 10)) *
    |   (ВЫБОР КОГДА ВЫРАЗИТЬ(ВложенныйЗапрос.Количество КАК ЧИСЛО(23, 10)) = 0 ТОГДА
    |    ВЫРАЗИТЬ(ВложенныйЗапрос.Стоимость КАК ЧИСЛО(23, 10))
    |   ИНАЧЕ
    |    ВЫРАЗИТЬ(ВложенныйЗапрос.Количество КАК ЧИСЛО(23, 10))
    |   КОНЕЦ) /
    |   ВЫРАЗИТЬ(УзлыКорректировкиСтоимостиСписания.Количество КАК ЧИСЛО(23, 10))
    |  ИНАЧЕ
    |   0
    |  КОНЕЦ
    | КАК ЧИСЛО(23,10))) КАК Стоимость

    Показать

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *