<?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='\
А что по производительности по сравнению с постобработкой? Стоит ли оно того в свете поддержки/доработки?
(1) CratosX, а что имеется ввиду под «постобработкой»?
В контексте решенных мной задач про прайсы такая техника позволила избавиться от кучи циклов при выводе табличного документа, и уменьшила время работы.
Обработка строк в итоговом запросе логически занимает отдельный блок и может быть беспроблемно вырезана/модифицирована, на содержательную часть про получение остатков /или цен она не влияет.
Допускаю, что в каких-либо других задачах, на каких-то более специфичных данных, предложенный алгоритм будет уступать процедурной обработке. Все ж зависит…
Поставил плюс за развитие темы.
По задаче 2 есть три замечания.
1) Сначала мелкое:
Условие проверки нечетности
лучше записать как
2) Замена группировки на соединение не было сделано вполне сознательно, учитывая, что вот это условие
в соединении почти наверняка приведет к сканированию второй таблицы, то есть для 1000 соединяемых строчек потребуется 500х1000 проверок. Тогда как при группировке операций будет не больше 1000. Чтобы работал ХэшМатч в этом соединении сравнение должно быть на равенство полей. Этого можно добиться, вычисляя номер пары для соединения заранее (в предшествующем запросе), поэтому при большом желании соединение все же можно использовать, но запись получается длиннее.
3) Упрощение, достигнутое отказом от предварительного разбиения строк на буквы, имеет границы применимости (об этом в исходной статье написано). Это как ответ на вопрос: сколько сигарет поместится в объеме блока сигарет: всего двадцать, если в каждой пачке будет лежать по одной. Здесь также: если строка будет объявлена длиной 50, а равна «а», то в итоге можно будет получить только строку «аааааааааааааааа» (длиной 16), выполнив вполовину меньшее максимального число соединений.
(3) ildarovich, спасибо за комментарий.
По пунктам:
1) согласен, в какой-то момент при написании включилось «безобразно, зато единообразно».
2) запись получается длиннее совсем ненамного:
Показать
3) возможно, мне не хватает понимания глубинных механизмов работы запросов в 1С, но каким образом длина строки повлияет на количество соединений, мне не ясно.
(4)
2) можно и так
3) Я провел эксперимент и выяснил, что при выполнении запроса
возникает ошибка, если длина строк в сумме превышает 1024 (или 2048 в некоторых случаях).
Аналогично
тоже будет давать ошибку, если длина исходных строк будет, например, равна 40. Потому, что тогда итоговая строка окажется длиной 1280 и не поместится в длину 1024, которая является ограничением при манипуляции со строками в запросе. Например, нельзя написать ВЫРАЗИТЬ(СтрокаХ КАК Строка(1280)). Я сделал вывод, что при выполнении операции Строка1 + Строка2 длина итогового поля не переменная, а фиксированная и равна сумме фиксированных длин строк-аргументов. Это логично для операций с таблицами.
Используя пять парных соединений, мы фактически реализуем то же самое выражение
. Значит, длина исходных строк не может быть больше 32. Или должно быть меньше соединений.
Максимальное количество соединений можно сделать тогда, когда исходные строки имеют длину 1. Тогда можно сделать десять соединений и получить в итоге строку длиной 1024, заполненную «до отказа». Поэтому и нужно предварительно разбивать строки на отдельные буквы.
Если написал непонятно, просто попробуйте задать длину наименования справочника 500, записать четыре элемента с наименованием «Первый», «Второй», «Третий», «Четвертый» и двумя парными соединениями получить конкатенацию вида «ПервыйВторойТретийЧетвертый».
(5) ildarovich, готово!
и
Показать
в результате:
Также без проблем отработало
Показать
P.S. Я допускаю возможность получить ошибку или некорректный результат, если в результате сложения получим «непустую» строку длиной свыше ХХХХ символов.
При разбиении сначала на единичные символы и фиксированном числе повторений, чтобы результат не был длинее этого ХХХХ, мы гарантировано ошибки избежим, тут я согласен.
Скриншоты из предыдущего сообщения в нормальном размере:http://imgur.com/a/kv28Z
(6) да, сделали все в точности, но … не могли бы (все уже настроено) проверить вариант с длиной 600. Дело в том, что 500х4 = 2000 < 2048, а 600х4 = 2400 > 2048. Максимальная 2048 — это не документированная фитча для файловой (?) версии.
(8) ildarovich, при длине в 600 интересная вещь получается: просто скопировать текст запроса как в посте выше не удается.
Вызов конструктора выдает ошибку, в обработке написать что типа
то ошибка возникает при попытке открыть обработку.
Видимо, 1С на этапе анализа запроса проверяет, какой длины строки получатся. Сужу по тому, что при замене
на
все нормально.
Так что, видимо, можно остановиться таки на том, что
1) если итоговая строка может быть больше 2000 символов — требуется разбиение на символы и ограничение повторений в запросе, дальше только процедурно.
2) если длина строки 2000 не превысит — можно мой механизм использовать.
(9) я бы написал: … если суммарная максимальная(объявленная) длина соединяемых строк может быть больше 1024 символов, то …
(1024 — чтобы учесть MS SQL и Postgre). Но занудствовать не люблю и спорить больше не буду.