Конструктор запросов для SQL




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

26 Comments

  1. nvv1970

    Интересно как виртуальные таблицы вы преобразуете в запросы sql ? )))

    Учитываете ли разделение данных? )))

    Reply
  2. user790109

    Задумка интересная, но есть много вопросов по поводу обработки таблиц) и версия 0.0.2, надеюсь не остановишься на этом.

    Reply
  3. qwinter

    Зачем такие сложности с виртуальными таблицами, если есть описание временной таблицы?

    Reply
  4. lastpioneer

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

    Reply
  5. lastpioneer

    (2) Это не обработка прямого подключения к SQLной базе 1С (хотя идея интересная 😉 ). Это обработка написания произвольного (с большими ограничениями) запроса к SQLной базе. Поэтому она не предполагает использование в конструкторе ветки метаданных 1С, только обработкой сформированные временные таблицы.

    Reply
  6. lastpioneer

    (3) не остановлюсь, если вы будете оставлять свои пожелания и комментарии, желательно в развернутом виде и они будут дополнять первоначальную концепцию. Данный механизм мной был написан и успешно внедрен (с некоторыми дополнениями) на проекте. Так как я его долго искал по просторам интернета и не нашел, решил выложить, может я не один ищущий.

    Reply
  7. AlexGroovy

    Классная штука=) Будем тестить!)

    Reply
  8. KAV2

    А зачем нужны два режима: нетиповой (слева) и типовой (справа) и маппинг между ними в виде временных таблиц. Не удобнее ли было реализовать типовой конструктор для таблиц SQL?

    Reply
  9. lastpioneer

    (9) Это вопрос ради вопроса?

    В моей обработке один режим.

    Маппинга тоже нет, есть представление таблиц SQL в виде временных таблиц, для возможности иметь доступ к полям присоединяемых таблиц.

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

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

    Reply
  10. KAV2

    (10) Извините, в самом деле, конечно же реализовать свой конструктор запросов задача еще та, поэтому предложенное Вами решение это разумный компромис между функционалом и сложностью реализации.

    Reply
  11. yurazyuraz

    (0) Код не закрыт ?

    Reply
  12. IvanPoh

    (12) Можете примерчик такого «сложного» запроса?

    Reply
  13. IvSchekin

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

    Reply
  14. lastpioneer

    (12) Думаю, что многие, я в том числе :), пользуются конструкторами, что бы не заморачиваться с вводом имен полей. Набросал, через конструктор «мясо» а потом можно и котлетки-конфетки лепить, хоть конструктором, хоть руками. И самое важно, конструктор помогает не делать грамматических ошибок ;). Да и форматнуть структуру проще через конструктор, чем руками ТАБы выставлять 🙂

    Reply
  15. lastpioneer

    (13) Открыто, входите 🙂

    Reply
  16. IvSchekin

    (17) В таком случае разве недостаточно стандартного конструктора чтобы кубики наделать а потом из них уже не в конструкторе собрать домик?

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

    Чтобы группировать одни и те же элементы справочника по разному и при этом никогда не корректировать конфигурацию и ничего не зашивать в код.

    Reply
  17. yurazyuraz

    (15) Читал , может что то упустил , где написано что код открыт ?

    Как то было дело скачал одну из обработок , а там код был закрыт.

    Вижу автор отписал уже , что открыт.

    Reply
  18. yurazyuraz

    (18) Спасибо!

    Reply
  19. mikukrnet

    (0) Повторяете функционал внешних источников данных ) Без необходимости изменения конфигурации, конечно

    Reply
  20. Dzenn

    Что-то прикольное 🙂

    Reply
  21. Shmell

    Интересная реализация. В избранное однозначно.

    Reply
  22. insurgut

    (6) а жаль, была бы бомба

    Reply
  23. nikita0832

    Нет исполняемых функций, это жаль. Ещё я себе добавил ТЗ.Сортировать(«TABLE_NAME»); чтобы отсортировать таблицы по имени перед загрузкой их на форму

    Reply
  24. nikita0832

    Короче дописал чтобы заполнял ещё и функции с параметрами и не ругался конструктор при работе с ними.

    Reply
  25. matveev.andrey.v

    Ошибка выходит на пустой конфе

    {ВнешняяОбработка.КонструкторЗапросаДляSQL.Форма.Форма.Форма(67,16)}: Переменная не определена (СтроковыеФункцииКлиентСервер)

    МассивПолей = <<?>>СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ТекстЗапроса, «,»);

    на какой то типовой ее надо запускать?

    Reply
  26. lastpioneer

    (30) да похоже, что в пустой базе не взлетит. Перепишите вызов корректно, а данную процедуру возьмите из типовой конфигурации (возможно ещё какие-то процедуры и функции потребуются из типовых)

    Reply

Leave a Comment

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