Обращение к результатам пакетного запроса по именам




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

28 Comments

  1. Поручик

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

    Reply
  2. Yashazz

    Ах да, естественно, имя результата должно удовлетворять нотации имён переменных в 1С.

    Reply
  3. karpik666

    Я так понимаю, любое неосторожное использование конструктора запроса затрет эти имена таблиц, не помню только в 1С добавил поддержку комментариев в конструкторе или нет, но идея интересная.

    Reply
  4. Yashazz

    (3) karpik666, затрёт, конечно. Но подобные монструозные запросы уже и не рассчитаны на конструктор. Они собираются по частям, иногда в разных блоках кода, изобилуют нечитаемыми для конструктора кусками, и потому… Терять особо нечего.

    Reply
  5. tormozit

    Конструктор запроса из подсистемы «Инструменты разработчика» не затрет такие комментарии.

    Reply
  6. tormozit

    Для тех, кто имеет доступ на партнерский форум 1С, приведу ссылку на одну из тем где это обсуждалось https://partners.v8.1c.ru/forum/topic/1182939

    Думаю скоро это добавят в платформе.

    Reply
  7. Yashazz

    (6) tormozit, ага, оно самое. Приятно, что не мне одному сие показалось неудобно; спасибо за ссылку.

    Честно говоря, вообще впервые имел дело с большим пакетным запросом, раньше как-то везло. А тут… Не вынесла душа поэта))

    Reply
  8. TODD22

    (6) tormozit,

    Думаю скоро это добавят в платформе.

    Из топика по ссылке таких выводов сделать нельзя…

    Reply
  9. konstruktiv

    (4) круто, а ведь наверное можно «идентификатор» результата в пакете поместить не как комментарий, а в виде фиктивного поля в выборке в самом запросе:



    ;

    ВЫБРАТЬ

    «МояНужнаяВыборка» КАК IDРезультат,

    Крайние.Виновник.Фамилия,

    Крайние.Виновник.Адрес …

    или



    0 КАК ID_МояНужнаяВыборка,

    Ну и доработать функцию, которая строит соответствие. Плюс в том, что эта конструкция не затрется, а минус в том, что дополнительное поле не должно повлиять на сам конечный результат вопроса, но оно вроде в большинстве случаев и не повлияет.

    Reply
  10. Патриот

    (9) konstruktiv, ну тогда уж лучше фиктивная выборка. Никаких минусов и данных хранить в ней можно сколько душе угодно.

    ВЫБРАТЬ
    «Это фиктивный пакет для записи любого количества сведений о нижеидущем пакете, которые не будут стираться конструктором запросов.» КАК МаркерФиктивности,
    «МояНужнаяВыборка» КАК ИмяРезультата,
    «любой текст 1» КАК Параметр1,
    «любой текст 2» КАК Параметр2,
    «любой текст 3» КАК Параметр3
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    

    Показать

    Reply
  11. PrinzOfMunchen

    (10) Патриот, не, тогда уж лучше так

    //Пакет основных запросов
    ……………………………………
    ……………………………………
    //Служебный запрос
    ВЫБРАТЬ РАЗРЕШЕННЫЕ
    &КоличествоЗапросовВПакете — 2 Как МойВажныйЗапрос,
    &КоличествоЗапросовВПакете — 3 Как МойВлажныйЗапрос,
    &КоличествоЗапросовВПакете — 4 Как МойХорошийЗапрос,
    &КоличествоЗапросовВПакете — 5 Как ЗапросЛайкаБосс
    

    Показать

    А потом

    РезультатыЗапроса = Запрос.ВыполнитьПакет();
    ВыборкаПакетов = РезультатыЗапросов[РезультатыЗапросов.Количество() — 1].Выбрать();
    ВыборкаПакетов.Следующий();
    
    РезультатЗапросаЛайкаБос = ПолучитьРезультатПакетаЗапросовПоИмени(ВыборкаПакетов, «ЗапросЛайкаБосс», РезультатыЗапроса);
    
    …………………………………………………………..
    
    Функция ПолучитьРезультатПакетаЗапросовПоИмени(ХранилищеПакетов, ИмяПакета, ПакетРезультатов)
    
    Возврат ПакетРезультатов[ХранилищеПакетов.ИмяПакета];
    
    КонецФункции
    
    

    Показать

    Ну это если без проверок. )))))

    Reply
  12. NazarovV

    Ну раз супруга сказала…) Мне пригодиться, спасибо!

    Reply
  13. konstruktiv

    (10) Патриот, тогда при редактировании запроса в конструкторе придется следить за положением запросов для идентификации результатов, быть особенно аккуратным при изменении места запроса в очереди, которая в конструкторе выглядит просто «запрос1/запрос2/…/запросN».

    Reply
  14. konstruktiv

    (11) PrinzOfMunchen, что-то я не разобрался спросонья, получается в последнем запросе опять же нужно вручную указать где какой результат, и при редактировании исходного запроса следить, чтобы эти места соответствовали реальным — от чего и хотел избавиться автор публикации?

    Reply
  15. PrinzOfMunchen

    (14) konstruktiv, да. ) Но это так, в порядке бреда, в ответ на пост (10).

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

    Reply
  16. МимохожийОднако

    Может быть, в каждый выходной запрос добавить поле как идентификатор очередного результата?

    Reply
  17. konstruktiv

    (16) МимохожийОднако, см. 9)

    Reply
  18. tormozit

    В следующей версии подсистемы «Инструменты разработчика» будет широкая поддержка имен запросов и частей объединений.

    Reply
  19. zqzq

    Я обычно пишу:

    последний результат запроса:

    МассивРезультатов.Получить(МассивРезультатов.Количество() — 1);

    Предпоследний:

    МассивРезультатов.Получить(МассивРезультатов.Количество() — 2);

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

    Reply
  20. Xershi

    Сегодня наткнулся на такой запрос. Его же сложно понять, в чем специфика? Скорость?

    Reply
  21. TODD22

    (20) Xershi,

    Его же сложно понять, в чем специфика? Скорость?

    В том что ты читаешь данные один раз. И возвращаешь результаты нескольких запросов за один раз. А не выполняешь трижды(или сколько у тебя пакетов) чтение из базы.

    Reply
  22. Xershi

    (21) TODD22, т.е. только скорость и не более?

    Reply
  23. TODD22

    (22) Xershi, Уменьшение количества обращений к базе.

    Reply
  24. starik-2005

    (20) Xershi, в базовом функционале последних версий типовых пакетный запрос часто используется для сборки всех движений, Но там грамотно сделано, а не как у автора заметки — там используются функции, возвращающие текст запросов, которые в итоге объединяются в один пакет и за раз отправляются на сервер. Обычно первая часть запроса — это временные таблицы, в которые выбираются ТЧ документа и прочие нужные параметры.

    Лично я так бы делать не стал, как в статье описано.

    Reply
  25. sss999

    У меня в консоли запросов есть парсинг по именам таблиц может пригодится,сделал для упр форм тоже,раньше были только обычные формы.http://infostart.ru/public/64616/

    Reply
  26. killovolt

    На платформе 8.3.8

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

    Реализован метод Запрос.ВыполнитьПакетСПромежуточнымиДанными(). Реализовано свойство МенеджерВременныхТаблиц.Таблицы.

    Reply
  27. tormozit

    В версии 3.61 подсистемы «Инструменты разработчика» реализовано:

    Консоль запросов

    +Реализовано чтение имен запросов и частей объединений при построении дерева запроса

    +Над таблицей результата пакета добавлен флажок «По именам» для вывода только именованных элементов

    +Добавлен параметр мРезультатПоИменам обработчика результата для доступа к именованным элементам результата пакета

    Конструктор запроса

    +Реализована возможность присвоения имен запросам и частям объединений с чтением и сохранением их в комментариях

    Пример текста запроса:

    //{Запрос: МойЗапрос1 ////////////////////////////////////////
    ВЫБРАТЬ
    1 КАК _1
    ;
    //{Запрос: МойЗапрос2 ////////////////////////////////////////
    ВЫБРАТЬ
    2 КАК _2
    ОБЪЕДИНИТЬ
    //{Выборка: МояВыборка1 ////////////////////////////////////////
    ВЫБРАТЬ
    5 КАК _2

    Показать

    На скриншотах показан вид этого текста в дереве запроса консоли запросов и конструкторе запросов.

    Пример кода:

    РезультатПакета = Запрос.ВыполнитьПакет();
    РезультатПоИменам = ПолучитьСтруктуруРезультатаПакетногоЗапроса(Запрос.Текст);
    РезультатЗапросаМойЗапрос1 = РезультатПакета[РезультатПоИменам.МойЗапрос1];
    Reply
  28. Пацталоцци

    (6)

    Для тех, кто имеет доступ на партнерский форум 1С, приведу ссылку на одну из тем где это обсуждалось https://partners.v8.1c.ru/forum/topic/1182939

    Думаю скоро это добавят в платформе.

    чёто прошло два с половиной года, а воз и ныне там.

    Автору спасибо и плюс, полезная фишка.

    Reply

Leave a Comment

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