СокрЛП() в запросе или что все-таки возможно получить с помощью запросов




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

9 Comments

  1. kosmo0

    Вместо самого первого запроса можно использовать типа такого (в принципе давно известного)

    ВЫБРАТЬ 0 КАК ф

    ПОМЕСТИТЬ Цифры

    ОБЪЕДИНИТЬ ВЫБРАТЬ 1

    ОБЪЕДИНИТЬ ВЫБРАТЬ 2

    ОБЪЕДИНИТЬ ВЫБРАТЬ 3

    ОБЪЕДИНИТЬ ВЫБРАТЬ 4

    ОБЪЕДИНИТЬ ВЫБРАТЬ 5

    ОБЪЕДИНИТЬ ВЫБРАТЬ 6

    ОБЪЕДИНИТЬ ВЫБРАТЬ 7

    ОБЪЕДИНИТЬ ВЫБРАТЬ 8

    ОБЪЕДИНИТЬ ВЫБРАТЬ 9

    ;

    ВЫБРАТЬ

    Цифры2.ф+Цифры3.ф*10+Цифры4.ф*100+Цифры5.ф*1000+Цифры1.ф*10000

    ИЗ

    Цифры КАК Цифры1, Цифры КАК Цифры2, Цифры КАК Цифры3, Цифры КАК Цифры4, Цифры КАК Цифры5

    Reply
  2. AzagTot

    Интересный материал. Спасибо!

    В первом пакете запросов, скорее всего, предполагалось использовать ВТ Регистр16, а не Регистр8.

    Иначе не обрежутся строки, длиной более 256 символов.



    // Непосредственно запрос обрезающий начальные и конечные пробелы и попутно получающий реальную длину строки

    ВЫБРАТЬ

    СтрокаСПробелами КАК СтрокаСПробелами,

    МАКСИМУМ(Цикл_2.Х + 1) КАК ПоследнийЗначащийСимвол,

    МИНИМУМ(Цикл_1.Х + 1) КАК ПервыйЗначащийСимвол

    ПОМЕСТИТЬ

    ПромежуточнаяТаблица

    ИЗ

    ИсходнаяТаблица

    ЛЕВОЕ СОЕДИНЕНИЕ

    Регистр16 КАК Цикл_1

    Reply
  3. PetrPan

    (2) AzagTot,

    Да, верно. Спасибо, заменил в запросах №№ 1 и 2 ‘Регистр8’ на ‘Регистр16’. Просто опечатался.

    На самом деле, если заведомо известно, что длина строки не превышает 256 символов, то лучше ограничиться в запросе №1 соединением с таблицей ‘Регистр8’,

    а таблицу ‘Регистр16’ и не создавать вовсе. Если ‘ИсходнаяТаблица’ будет содержать много строк, то разница по времени выполнения будет существенной.

    Для остальных запросов, честно говоря, реального применения не вижу ))

    Reply
  4. PetrPan

    (1) kosmo0,

    Да, конечно, можно и так. Вообще, в запросах к реляционным БД вряд-ли уже возможно изобрести что-то новое 😉

    Reply
  5. Anesk

    Разработать будет быстрее выгрузив в таблицу значений.

    А в плане оптимизации кода, что будет работать быстрее

    этот сложный запрос

    или

    «выполнить вспомогательный запрос, выгрузить его в таблицу значений, перебрать ее в цикле выполняя СокрЛП(), и затем передать обратно в нужный запрос в виде параметра (создать временную таблицу)»?

    Reply
  6. PetrPan

    (5) Anesk,

    Если возвращаемое строковое значение нужно использовать потом уже в коде 1С, то однозначно никакого смысла в использовании сложного запроса нет.

    Встроенная функция СокрЛП() в цикле по выборке результата запроса отработает на порядок быстрее.

    «Выполнить вспомогательный запрос, выгрузить его в таблица и потом передать обратно в нужный запрос в виде параметра» — не могу ответить.

    Вообще, сложно представить зачем в запросе строка с обрезанными концевыми пробелами: при сравнении они все равно не учитываются.

    Мне в конкретной задаче нужно было получить 3 последних символа кода справочника и в зависимости от них вернуть из запроса те или иные данные.

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

    Подытожив: в плане оптимизации лучше не использовать без необходимости ничего сложного.

    Быстрее по выполнению использовать встроенные функции. За сложный запрос всегда придется заплатить временем выполнения и отсутствием масштабирования.

    Прошу смотреть на эту статью только как на иллюстрацию приемов, которые МОЖНО, но не вовсе не обязательно НУЖНО использовать в запросах ))

    Reply
  7. kiruha

    Публикация круть ) Но на практике использую не выгрузку в ТЗ как тут упоминают , а СКД с собственной функцией СокрЛП из общего модуля. Думаю это самый быстрый вариант

    Reply
  8. German_Tagil

    (7) Обьясните пожалуйста как это работает — по шагам

    СКД с собственной функцией СокрЛП из общего модуля

    Reply
  9. Serge_ASB

    В СКД:

    Вычисляемое поле:

    СтроковыеФункцииКлиентСервер.УдалитьПовторяющиесяСимволы(<Нужное_Поле_из_СКД>, » «, «справа»)

    Это — для ЗУП. Возьмем значение из поля, поищем пробелы (или другие символы), «справа» (а можно «слева»).

    Reply

Leave a Comment

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