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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2026-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 не будет опубликован. Обязательные поля помечены *