Как сделать запрос на изменение данных




Принцип обмена данными из 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='\

21 Comments

  1. CyberCerber

    Выглядит круто.

    Только я не увидел или пропустил самое главное… Как происходит само изменение данных? Стандартными объектами? Как изменяются регистры сведений, подчиненные регистратору? Удаление данных происходит без контроля ссылочной целостности?

    Reply
  2. m-rv

    (1)

    само изменение — объектами, да

    все регистры — наборами.

    удаление — без контроля ссылочной целостности (если только не начнет работать платформенный контроль по ведущим измерениям)

    Reply
  3. Aphanas

    Как насчет добавления данных? Что-то не увидел.

    Reply
  4. m-rv

    (3) Запрос ВСТАВИТЬ (INSERT) ожидается, следите за обновлениями

    Reply
  5. kote

    Самое главное, пожалуйста, скажите — использование этого подхода сильно сокращает количество кода?

    Если будет что-то с примерами — вообще шикарно будет.

    Reply
  6. Артано

    (7)Сомневаюсь, просто он будет организован по единому образцу, что по эффекту будет сопоставимо.

    Вообще язык запросов имеет большой потенциал в плане легкости чтения кода за счет строгого разделения функциональных блоков запроса.

    В любом случае лайк.

    Reply
  7. m-rv

    (7) Я на самом деле использую это в качестве консоли, когда, например, «забыли» заполнить обменом какую-нибудь единицу изменения в номенклатуре или типа того, но в целом я согласен с коллегой — в некоторых случаях количество строк сократится (когда, например, не придется вручную перебирать документы для замены номенклатуры в ТЧ), но в основном это скорее про организацию и читаемость кода

    Reply
  8. Terve!R

    (8) никакой легкости чтения кода в запросах нет. Ну разве что не использовать вложенные запросы и кучу соединений. Опытный программист конечно любой запрос прочитает, но не потому что там заложен какой-то потенциал.

    Reply
  9. m-rv

    (11) довольно спорное утверждение.

    понятно, что можно придумать ситуацию, когда чтение данных при помощи объектной модели будет «читаемее» запроса, а можно придумать и обратный пример. да и вообще «читаемость» весьма оценочная категория.

    но в некоторых случаях использование объектной модели ведет просто в ад. напишите такое на объектной модели:

    ВЫБРАТЬ РАЗЛИЧНЫЕ Ссылка ИЗ Документ.ПоступлениеТоваровУслуг.Товары ГДЕ Номенклатура В (&МассивНоменклатуры)

    А в запросе все очевидно.

    Reply
  10. vec435

    запросы на изменения пишутся руками?

    Reply
  11. m-rv

    (13) конструктор — зло )

    Reply
  12. vec435

    тогда добавь мастера который из запроса вида

    выбрать код,наименование из справочник.Номенклатура где ссылка=&ссылка

    сделает

    ИЗМЕНИТЬ Справочник.Номенклатура

    УСТАНОВИТЬ наименование = &параметр1,код=&параметр2

    где ссылка=&ссылка

    Reply
  13. acanta

    Можно добавить в текст запроса СокрЛП ?

    Reply
  14. ufedor

    + за системный подход!

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

    Обновить Т1

    установить реквизит = значение

    из

    Т1 внутреннее соединение Т2 по Т1.Ключ = Т2.Кл

    Reply
  15. m-rv

    (17) соединения в изменении выглядят весьма заманчиво, согласен, но пока на это нет времени. может быть, когда-нибудь…

    Reply
  16. Darklight

    Всё почти хорошо, но вот эти ограничения — всё портят:

    1. «изменить … значение измерения регистра сведений — это приведет к исключению.» — нельзя изменять значения в измерениях регистров сведений? Почему?

    2. «Если имеет место пакет из, например, 3-х запросов, 1-й читает, 2-й изменяет, 3-й перечитывает данные — то в результате 3-го запроса будут получены еще не измененные данные.» Бред. Нужно разделять выполнение пакетных команд. Ведь что мешает выпоонить оставшуюся часть пакета (чтение) после выполнения первой на изменение.Ведь и последующее изменение тоже может быть основано на чтении уже обновлённых данных.

    3. Отсутствие поддержки соединений тоже никуда не годится

    4. Нужна пакетная вставка в таблицу (NSERT INTO SELECT )

    А ещё хочется дополнительные операции вставки для накопительных регистров — на увеличение и уменьшение значения (упрощённый синтаксис — приход, расход) и отдельно на установку заданного значения остатка (типа как инвентаризация).

    Ну а пожелание того, чтобы такие запросы ещё можно было бы по фоновым процессам распараллеливать — будет вообще из области фантастики.

    Кстати, а как происходит обновление регистров с итогами — нужно какое-то управление из текста запроса, чтобы можно было бы обновлять итоги отдельно — после внесения всех изменений в исходные данные. Я порнима, что это всё можно было бы сделать вне запроса пррогаммно (или интеарактивно), но всё же для консоли удобно — чтобы это было в самом запросе.

    Reply
  17. m-rv

    (19) ох.. ну давайте по пунктам:

    1. попробуйте взять рс неподчиненный регистратору, прочитайте по какому-нибудь отбору, а потом в наборе измените значение измерения, по которому был установлен отбор. посмотрите на результат. понятно, что это не непреодолимая ситуация: можно один набор удалить, второй записать.. но эти алгоритмы не реализованы.

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

    3. это без комментариев, попробуйте сами такое реализовать.

    4. это есть, читайте внимательнее

    5. апдейты агрегатных таблиц — ну бросьте вы, это решается пакетом из 2-х запросов за 5 секунд.

    6. параллелизм — смотря для чего: для чтения данных — стоит ли огород городить? для записи — начнутся блокировки, надо как-то потоки разводить по типам объектов, это жутки гемор и уже уровень не беспланой фичи для инфостарта, а энтерпрайзного решения.

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

    Reply
  18. Darklight
    Reply
  19. m-rv

    (21)

    4. да конечно, это просто пример. можно сколько угодно строк вставлять. ваш последний запрос взлетит прям в таком виде.

    Reply
  20. peterxx

    (12) Угу. А самые очевидные — это запросы в ЗуП, размером с трехспальную простыню и кучей временных таблиц.

    Reply
  21. MichiMaloy

    Спасибо)

    Reply

Leave a Comment

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