Исправление проблемы "CREATE UNIQUE INDEX terminated because a duplicate key was found for index…" для SQL




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2025-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='\

12 Comments

  1. harleq

    А можно узнать подробнее об этой проблеме?

    Reply
  2. antonrost

    Проблема возникает на больших sql базах при большом количестве документов, записанных в пределах одной секунды (как правило — 23:59:59).

    В этом случае иногда возникает ситуация, при которой время документа не соответствует времени проводок по этому документу. При реструктиризации таблицы _1sjourn возникают 2 записи с одинаковым ключевым полем (что недопустимо). В принципе, решается выгрузкой/загрузкой, но в один прекрасный момент наступает предел (zip > 2 Гб). В этом случае спасает только прямой SQL запрос.

    Reply
  3. antonrost

    Да, забыл… Еще решается удалением и повторным созданием проводок у проблемных документов. Или просто перепроведением (если это возможно).

    Reply
  4. Падает 1С-ка при работе данной обработки, пробовал сформировать падает, исправить запросом тоже падает. Почему ?

    Reply
  5. Да чуть не забыл, конфа комплексная 462, 7.7 25 билд, 1C++ последний

    Reply
  6. acsent

    Реально на таком ломаном английском ошибка выходит?

    Reply
  7. antonrost

    Использует 1с++ dll, поэтому падает если ранее был загружен formex.dll.

    Reply
  8. formex.dll — не загружал

    а программа падает .

    Выскакиваеттакое сообщение

    Message: [Microsoft][ODBC SQL Server Driver][SQL Server]CREATE UNIQUE INDEX terminated

    because a duplicate key was found for index ID 2. Most significant

    primary key is ‘ 43 ‘.

    Стоит 1с вер 7.7.023+ Win 2000+ SQL 2000

    Я создаю пустую базу. Загружаю МД. файл — потом выгружаю информацию.

    Загружаю в пустую базу и выдает это сообщение

    Что это может быть.

    К меня вообще никаких записей нет. Что может дублироваться?

    Спасибо заранее

    vladibor@ukr.net

    Reply
  9. Спасиб, буду знать почему такая ошибка.

    Reply
  10. LusiCat

    Спасибо, очень помогло!

    Reply
  11. sorb

    интересует один момент: был запущен пересчет итогов, в процессе вылезла сия ошибка, в базу для запуска обработки естественно уже зайти невозможно. Удалил дубли в 1scrdoc ручками, зашел, прогнал обработку, все ок (автору спасибо). НО! Неуникальных уников было порядка сорока, руками чистить утомительно. Не будет ли большого зла во временном отключении уникальности для проблемного индекса (чтобы просто в базу зайти)?

    Reply
  12. rendalina

    Антон, спасибо большое, обработка очень помогла.

    Но при исправлении дублей в _1sentry прямым sql-запросом, проводки исчезают из оборотно-сальдовой ведомости, а при перепроведении документа появляются назад.

    Можно ли потом как-то отследить такие «пропавшие» проводки?

    Не возникнет ли каких-то подобных «побочных эффектов» при удалении дублей в _1soper прямым sql-запросом? А то там много дублей возникает, перепроводить долго получается, да и не все документы перепроводятся по различным причинам. А по кнопке «Исправить список перезаписью операций» дубли не убираются.

    Reply

Leave a Comment

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