Тонкости СКД: Особенности отбора при использовании временных таблиц




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

    Автозаполнение является причиной многих «проблем» (например, параметры и поля виртуальных таблиц), поэтому при использовании в отчетах, не являющихся слишком простыми, лучше отказаться от автозаполнения, либо прямо указывать поля, отборы и параметры для компоновки данных, например

    {(Организация)}

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

    P.S. Замечания по запросу: 1) временная таблица уже содержит все записи справочника «физические лица», поэтому во втором запросе не нужно опять обращаться к таблице справочника, а должно быть соединение временной таблицы со вложенной таблицей (из этой же временной). 2) Так как вы получаете записи из таблицы справочника без соединений, то достаточно использовать оператор Количество() без указания слова Различные, т.к. это дополнительная нагрузка на СУБД из-за лишнего перебора данных.

    Reply
  2. kruglay

    (1) Puk2,

    Спасибо за конструктивный комментарий.

    Почему вы считаете, что отбор сработал предсказуемо? Во временной таблице нам необходимо получить все записи справочника, а если стоит галочка «Автозаполнение», то мы получим записи соответствующие критериям отбора(рис.3 т.е. всего 4 записи вместо 48). Источники мы используем разные: временную таблицу, и справочник физЛиц. Если я буду использовать в качестве источника только временную таблицу, то никакой наглядности в данном примере не будет, хотя результат и будет тем же. Насчет различные это я поправлю.

    Reply
  3. kruglay

    (3) EmpireSer,

    Данный запрос был смоделирован, чтобы его можно было просмотреть в любой конфе в которой есть справочник физЛиц. Кому надо тот почерпнет нужную информацию.

    Reply
  4. EmpireSer

    (1), (2),

    А это имеет смысл для «демонстрационного» запроса?

    P.S. Я не считаю, что на запросах с пометкой «Запрос особой смысловой нагрузки не несет» нужно учится.

    Reply
  5. Yashazz

    Обращаться к полю из присоединяемой таблицы без ЕСТЬNULL, если соединение не внутреннее — имхо, моветон.

    Reply
  6. slazzy

    (4)

    Почему вы считаете, что отбор сработал предсказуемо?

    Потому что это принцип работы СКД, он всегда так устанавливает отборы 🙂 это базовые сведения при работе с СКД и называть их «тонкости» несколько странно.

    Автозаполнение ничего плохого не несет в себе, достаточно нужный отбор вынести в фигурные скобки и устанавливать отбор по этому полю.

    Рассмотрим пакетный запрос:
    
    ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК Ссылка,
    ФизическиеЛица.Пол
    ПОМЕСТИТЬ ВТ
    ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица
    
    ИНДЕКСИРОВАТЬ ПО
    Ссылка
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК Ссылка,
    ФизическиеЛица.Пол КАК Пол,
    ВложенныйЗапрос.Количество КАК Количество
    {ВЫБРАТЬ
    Ссылка.*,
    Пол.*,
    Количество}
    ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица
    ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВТ.Ссылка) КАК Количество
    ИЗ
    ВТ КАК ВТ) КАК ВложенныйЗапрос
    ПО (ИСТИНА)
    {ГДЕ
    ФизическиеЛица.Ссылка.* КАК СсылкаОтбор,
    ФизическиеЛица.Пол.* КАК ПолОтбор} 

    Показать

    И отборы устанавливать по полям СсылкаОтбор и ПолОтбор.

    Reply
  7. kruglay

    (6) slazzy,

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

    Я и не говорю, что автозаполнение это плохо, просто показал вариант, когда данное свойство надо использовать осторожно

    И отборы устанавливать по полям СсылкаОтбор и ПолОтбор

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

    Reply
  8. PiccaHut001

    (6) slazzy, 1C — самая логичная и предсказуемая система, созданная марсианами для людей. Признак измерения «обязательный» уже не работает, надо каждое поле заводить по 2 раза — первый для отбора, второй для выборки с запретом отбора. Всё отлично работает, жду не-дождусь конфигуратора по 6 ифон

    Reply
  9. slazzy

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

    (8) извиняюсь, но мне в страшном сне сложно представить отчет, в котором понадобится более 10 отборов. А уж про 20-30 я не буду говорить 🙂

    Reply
  10. Yimaida
    Только после прочтения Радченко я нашел причину и описал ее здесь.

    Думаю, дальше можно не комментировать. Читать книгу и делится выводами в виде статьи и даже не сделать ссылку на книгу… Гляди сейчас и посыплются особенности, тонкости и т.п. Ну и отдельное внимание заслуживает текст запроса, прям для новичков. Причем статья, как я понял, редактировалась, хотя в данном случае ЕСТЬNULL эффекта не даст, т.к. условие соединения «Истина».

    P.S. Дорогие новички, и не окрепшие умы, читайте сначала литературу, а потом инфостарт и т.п.

    Reply
  11. kruglay

    (10) Yimaida,

    Многоуважаемый старичок думаю в вашем комментарии вообще нет особого смысла. Данная статья писалась именно для тех кто недавно работает с 1с, СКД. И именно поэтому запрос простой, а если вам так хочется посмотреть на многострочные запросы и по разбираться в них откройте конфу например ЗУП. В указании первоисточника не вижу смысла, это не курсовая где указывается используемая литература. Если бы была похожая статья на инфостарте или другом источнике я бы ее указал.

    Reply
  12. Yashazz

    (11)

    «В указании первоисточника не вижу смысла, это не курсовая где указывается используемая литература»

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

    Reply
  13. echo77

    Вот еще одна публикация на тему, но здесь описывается как это обойти с установленной галкой автозаполнение

    http://infostart.ru/public/185880/

    Считаю, что для молодых специалистов лучше все же начинать изучение СКД с установленной галкой автозаполнение, но сразу же учиться пользоваться консолью отчетов с СКД и смотреть что за запрос строит СКД.

    Когда сложность отчетов вырастет и опыта наберетесь — составляйте схемы без автозаполнения

    Reply
  14. Yimaida

    (12) Запрос, как раз, не простой. Он, конечно, не сравнится с запросами в ЗУП, но в контексте данной статьи он сложный, т.к. содержит временную таблицу, соединение по ИСТИНА и функцию ЕСТЬNULL().

    Что касается сути статьи, основная идея — это научиться отлаживать итоговый запрос, который нам выдала СКД. Так вот про то как это сделать не сказано ни слова. Каким инструментом это надо делать? И даже если бы Вы указали где увидеть итоговый запрос, статья является лишь плохим пересказом давно описанных вещей. И странно, что никого не удивило наличие одинаковых параметров «&П» для пола и для ссылки.

    P.S. Мой комментарий предназначался не столько Вам лично, сколько тем кто будет читать Вашу публикацию (в терминах инфостарта)

    Reply
  15. Патриот

    Статья сводится к «при использовании автозаполнения в СКД произойдёт автозаполнение, которое не обязательно вам было необходимо» =)

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

    Reply
  16. nixel

    Я просто оставлю это здесь.

    Разработка сложных отчетов. Система компоновки данных.

    P.S. Изучайте инструмент, которым вы зарабатываете на жизнь. Помогает избежать многих «проблем».

    Reply
  17. hazd

    у меня тоже такая затыка была, разобрался.

    Reply
  18. vsozansky

    Отличный пост. Помог разобраться и намекнул, что надо копать мануал.

    Спасибо.

    Reply
  19. kruglay

    (18) vsozansky, пожалуйста))

    Reply
  20. tanais

    Спасибо! Помогло. Жалею время потраченное на самостоятельный поиск)

    Reply
  21. NN2P

    Спасибо за статью

    Reply
  22. kruglay

    (21) пожалуйста))

    Reply
  23. MCid

    Отличная статья и комментарии, помогло хотя бы немного вникнуть в происходящее у меня безобразие. Спасибо!

    Reply
  24. Kostt
    Reply
  25. Kostt

    (24) Если заказ поставщику выбрать в результате то он в первой таблице появляется. Но результат не такой как мне нужен получается. Как заставить Оптимизатор запроса 1с, всегда учитывать его во временной таблице?

    Reply
  26. Kostt

    Решил проблему поместив первую таблицу во вложенный запрос. теперь понятно почему во мноних типовых отчетов 1с использует вложенные запросы.

    Reply
  27. kruglay

    (23)

    Пожалуйста))

    Reply
  28. palsergeich

    Роль — обязательное. И все оптимизатор не будет выкидывать это поле.

    Я встречался с интересным багом — оптимизатор выкидывал одно и только одно поле поле. Ничего не помогало, ни роль, ни закладка.

    Помог только костыль следующий;

    Выбор Когда Истина тогда Поле Конец

    Reply

Leave a Comment

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