<?php // Полная загрузка сервисных книжек, создан 2025-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='\
А почему именно вложенный запрос??? Почему не временная таблица? Это и отлаживать удобнее и более понятно для глаз. Честно говоря, вообще коробит, когда такие промежуточные запросы называют «ВложенныйЗапрос», неужели нельзя дать понятное наименование?
(2). Я не изобретатель велосипеда. Просто не все учатся на курсах и читают нужные книги. Много самоучек с большим стажем работы и не факт, что они до этого дошли. Я показал как это решается. И я уверен, что найдутся те, кому это поможет в решении своей задачи. Я тоже самоучка и у меня нет сертификатов. На ресурсе я тоже вижу статьи и файлы, которые для меня не представляют ничего сложного и интересного, но тем не менее людям они помогают. И что, им тоже минусы?
(3). Ну я рассматривал вариант, когда все делается в одном запросе, а не в двух и более. Временная таблица подразумевает использование менеджера временных таблиц и программной обработки результата запроса и еще как минимум 1 запрос.
(1). Спасибо за понимание.
Менеджер временных таблиц можно и не использовать — все организовать в одном запросе, например как-то так(как красиво вставить код в ответе не знаю):
ВЫБРАТЬ
Договор.Сумма КАК Сумма,
Договор.Ссылка КАК Ссылка,
МАКСИМУМ(Руководители.Период) КАК Период,
Договор.Сотрудник КАК Сотрудник
ПОМЕСТИТЬ РуководителиДоговоров
ИЗ
Документ.Договор КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО Договор.Сотрудник = Руководители.Сотрудник
И Договор.Дата >= Руководители.Период
ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
Договор.Сумма,
Договор.Ссылка,
Договор.Сотрудник
;
ВЫБРАТЬ
РуководителиДоговоров.Ссылка КАК Договор,
РуководителиДоговоров.Сумма,
Руководители.Руководитель
ИЗ
РуководителиДоговоров КАК РуководителиДоговоров
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители КАК Руководители
ПО РуководителиДоговоров.Период = Руководители.Период
И РуководителиДоговоров.Сотрудник = Руководители.Сотрудник
Статья безусловно полезная, я думаю есть начинающие программисты на 1С, которые об этом не знают. В любом случае, именно подобные статьи и делают инфостарт таким ценным ресурсом — мы делимся опытом и сами чему-то учимся. Не пойму, зачем ставить минус, если ты знаешь об этом приеме.
Короче автору однозначно +
(6). Согласен. Работает. Еще 1 вариант. Наберу рейтинг 30, поставлю +.
(7). Спасибо.
Рассмотрим первый пример из статьи :
***************************************
ВЫБРАТЬ
Договор.Ссылка КАК Договор,
СУММА(Договор.Сумма) КАК Сумма,
РуководителиСрезПоследних.Руководитель
ИЗ
Документ.Договор КАК Договор
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Руководители.СрезПоследних(&Дата2, ) КАК РуководителиСрезПоследних
ПО Договор.Сотрудник = РуководителиСрезПоследних.Сотрудник
ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2
СГРУППИРОВАТЬ ПО
РуководителиСрезПоследних.Руководитель,
Договор.Ссылка
******************************************
Язык запросов — язык декларативный , т.е. не определяющий последовательность действий при выполнении платформой запроса.
В какой последовательности ,на взгляд автор, будет происходить исполнение
запроса :
1. Вначале будет выполнено левое соединение всей (!) таблицы Договоров с регистром сведений и лишь потом фильтрация полученной промежуточной таблицы по условию
«ГДЕ
Договор.Дата МЕЖДУ &Дата1 И &Дата2″».
2. Или вначале будет фильтрация талицы Договоров по условию «ГДЕ …»
и лишь затем левое соединение полученной промежуточной таблицы с регистром сведений.
Итак , п.1 или п.2 ?
(10) О том, как исполняется в файловом варианте — не знаю, но у движка MSSQL вроде как хватает сообразительности пойти по 2 варианту. Подцепитесь профайлером и посмотрите план исполнения запроса.
Я давно уже про это читал на Мисте:
http://www.kb.mista.ru/article.php?id=92
—
А какой собственно выигрыш при использовании временных таблиц? Мне например они как-то не по душе, вложенные запросы понятнее.
(11) Спасибо за совет. Но подождем ответа автора для для файлового и SQL вариантов.
(10). Честно говоря не знаю, да и абсолютно нет разницы для конечного результата.
(12) Ну про вложенные запросы — это на вкус и цвет, как говорится, но мне удобнее видеть выборки отдельно. Да и если выборки сложные и требующие частого вычисления одного и того-же в нескольких запросах — менеджер временных таблиц может здраво ускорить выборки.
За идею — плюс. Помню, сам парился на эту тему и решил проблему аналогичным способом )) будет полезна многим
(12)
Во временных таблицах можно строить индекс по колонкам.
(14) Конечно нет разницы для конечного результата.
Разница будет во времени исполнения . По п. 1 оно может быть очень значительным.
Чтобы исключить п.1 и не надеяться на оптимизатор запроса при файловом
или SQL-варианте в указанном тексте лучше применить временную таблицу или вложенный запрос.
Насколько мне известно , «1с» не публиковала описание оптимизатора запроса в файловом варианте.
в Укр. типовом ЗУП полно таких конструкций. Метод действительно давно уже используется — «Срез последних на разные периоды», а плюс за описание для молодежи…
(18).Ну, как вариант, можно сделать вначале выборку нужных данных во вложенном запросе. Так будет явно понятно в какой последовательности происходит выборка, но приведенный тобой запрос (10) все-равно является неверным для задачи, так как выдает неправильный результат, поэтому какой смысл его использовать?…
(20) Пример взят из описания текущей темы . И в последующем примере запроса в описании темы — та же ошибка при построении запроса.
Применение в данном случае вложенного запроса или временной таблицы —
нужно рассматривать не как один из вариантов ,
а как оптимальный вариант запроса.
Подробнее прочитать про оптимальность и неоптимальность запроса
можно в статье Павла Чистова «Пакетные запросы» из рубрики «1с рекомендует».
(21). Будет время — обязательно сделаю базу с количеством записей 20 000 на каждый объект конфигурации и проверю разницу времени выполнения запроса. На текущий момент могу сказать, что выполнение сложного запроса и построение отчета за 2 секунды целиком устраивает моих пользователей.
(22) Чтобы картина была более полной , возможно будет интересно почитать
и сторонников противоположной точки зрения
+ за просвещение самоучек (тоже была такая проблема).
(23). Вообще-то статья была на тему составления запроса для получения правильного результата, а не о оптимизации и скорости выполнения запросов. Думаю, что дальше развивать полемику на эту тему нет смысла. Для этого скорее всего и была создана тема, ссылку на которую ты указал.
Особо еще не разобрался в тонкостях, но были такие же ситуации, возможно тогда бы такое решение мне бы и помогло:))) Спасибо за ликбез
Несколько странным кажется, что люди не умеют пользоваться поиском и поисковыми машинами.
Потрачено время на то, что уже придумано другими людьми гораздо раньше. Я бы не знал куда спрятаться от стыда.
Добавил в статью вариант запроса с временной таблицей от ZyZer из поста 6.
(27). Не надо обалдевать от собственной крутости. Бывает, что просто не видишь даже вариантов решения вопроса. Как в фильме: видишь суслика? Нет. А ведь он есть. Кто-то (как ты, например) посещал немеряно курсов и знает про 1С все (ну или думает, что знает), а кто-то нигде не учился. Я например, до 1С программировал на 3 языках: Perl, VB и C#. А СрезПоследних так забивает голову, что сразу и не найдешь решение, если не вспомнишь былую практику или, как в твоем случае, курсы.
(29) про курсы анекдот какой-то, я слесарь-сборщик радиоаппаратуры и консерваториев не кончал, однако когда проблема встала с необходимостью получения данных в запросе на дату документа — нашел на мисте описалово метода и стал пользоваться, и это не моя крутость, а ваша пафосность в представлении этого баяна немного меня зацепила.
(30). Ну, никто же не мешал тебе сделать статью здесь. Я разместил статью потому, что дошел до этого своим умом, когда знакомые считали это сложноразрешимым. Более того, некоторое время сам думал, что это нереально сделать в одном запросе. Я же не написал, что это открытие века.
(31) Ндя… А просто погуглить «запрос срез последних на дату документа»?
Надо завязывать конечно с этим спором, я не размещаю статей, я не учусь на курсах, я просто прежде чем написать «я открыл Америку» пытаюсь найти информацию, не открывал ли кто-то её уже раньше. И вам советую. Во-1х экономит время сильно, во-2х не попадёте в глупое положение.
(33). Во первых, я не писал, что «я открыл Америку», а во вторых, как показало время, статья оказалась полезной другим. А то, что статей не пишете — так это вам не в плюс. Знаниями и опытом надо делиться.
Да но в этом методе есть и отрицательные стороны. На больших таблицах, будут тормоза. А еще если это связано с регистром накопления, а что если необходимо получать остатки на дату документов, а регистр к примеру партий товаров… Вот этот способ не сработает. То есть оно работать будет но ужастно долго!!!!!!
(35). Естественно, запрос будет отрабатывать дольше. Но он будет работать и выдавать правильный (!) результат. Если у Вас есть решение лучше — пожалуйста, предложите. Во всяком случае это решение будет работать гораздо быстрее, чем если обрабатывать эти вещи не в запросе, а в коде.
(36) Смотря для каких задач… Это хорошее решение и правильно что выложили его здесь… Просто не для всех оно подходит. Например мне необходимо было делать выборку по заказам покупателей и на момент заказа смотреть стоимость партии в регистре накопления «ПартииТоваров», вот этот вариант уже не подходит… Постоянный перерасчет регистра на всю номенклатуру…
Тогда приходится применять обходную хитрость что вы и сказали кодом… Делаю сперва один запрос вынимая заказы и номенклатуру в обходе результата запроса вызываю уже второй запрос, которому даю номенклатуру на которую он должен расчитать данные и дату.
Не спорю это не гуманно, но пришлось и так обходить!
(37). А вы не пробовали сравнить скорость выполнения обработки кодом и сложным запросом? Я думаю, что на среднем компьютере сложный запрос будет выполняться быстрее, чем обработка кодом. Сейчас у меня отчет на запросе в 1642 строки отрабатывает порядка 20 секунд. Я даже не представляю, сколько он отрабатывал, если бы обработки были в коде. Ведь код обрабатывается на клиентской машине, а весь запрос на сервере, который гораздо производительнее клиентской машины.
(38) Опять же спорно… Сделайте так как я говорю и вы увидите в чем прикол, структура хранения регистров сведений и регистров накоплений совершенно другая. И в запросе указывая дату расчета на каждый документ происходит постоянный перерасчет данных…
А насчет кодом у клиента, необязательно, можно клиенту отдать таблицу значений которая отработана на сервере (ну это касательно 8.2, хотя 8.1 можно построить на уровне серверных модулей схожее выполнение).
И все же яне опровергаю вашу статью и ставлю +1. Я сам пользовался и не однократно срезом регистра сведений на «динамические даты» и это пролетало, а вот с регистром накоплений к примеру «Партии товаров» можете представить себе объемность данной таблицы, долго… Так как нету фильтра на номенклатуру в этом беда, он рассчитывает таблицу в целом…. Я просто поднял свою тему так как пришлось совершенно недавно с этим столкнуться:Поднимал этот вопрос на мисте
И выкладываю этот материал как примечание чтобы взять во внимание. Спсасибо за понимание, а автору плюс за труды!
(40) Честно говоря, я стараюсь не использовать внутренние механизмы типа «Срез». Механизм «Обороты» так же в последнее время в основном не вызывается, а вместо него пишется вложенный запрос. Как показала практика, самописные выборки гораздо гибче встроенных механизмов. С «Остатками» мне почти не приходится работать, но, думаю, если придется, можно и это реализовать.
Поражаюсь. Одна критика. Я вот вчера только узнал про вложенные запросы. Для начинающих полезная статья. Автору +
(32) из-за таких как ты, все запросы в гугл отправляют тебя на страницу, где советуют обратно поискать в гугле
(32). Если уж советуешь погуглить, то приведи сразу ссылку, потому как (43) 100% прав
(43) и (44) вам почти год понадобился чтобы найти решение в гугле? 🙂 вот ссылкаhttp://kb.mista.ru/article.php?id=92 первая редакция от 16.02.06
иначе я не вижу причин, чтобы разводить флейм в теме, которая стара как мир.
(45) я не рассуждаю о свежести темы. Просто (43) прав в принципе безотносительно темы. Очень часто ищешь информацию (ЛЮБУЮ), а натыкаешся только на своеты погуглить, спросить яндекс и т.п., что не ускоряет поиск нужной информации, потому как эти советы гораздо свежее по времени самой информации.
Будет гораздо уважительнее ко всем, в т.ч. и новичкам, если пишешь про баян, то сразу дай ссылку на этот баян.
С уважением. Ничего личного.
Данная фраза не верна — нужно сделать группировку по всем измерениям регистра и по периоду — чтоб в выборке однозначно получить его ресурсы, и вообще относительноhttp://www.kb.mista.ru/article.php?id=92 пример не доделан, выборкой с группировкой мы находим конкретную запись, связываем по измерениям еще раз с регистром сведений и получаем ресурс(ы). А потом уже они выводятся в окончательный запрос. В качестве примера — регистр цен, если я сделаю группировку по ресурсу цена — никакой максимум не сработает, а так как в группировке участвуют все поля запроса 🙁
Спасибо автору за пример использования хоть и известного, но полезного подхода в работе с периодическими регистрами сведений. Иногда помишь, что такое возможно, но не помнишь как. Такие статьи помогают отыскать забытые или потерянные знания.
(47) A_kryl,
видимо столкнулся с такой проблеммой , не работает максимум , не понимаю , как решить ?
у меня в запросе два регистра сведений соединяются по Периоду
Рабочий пример для ЗУП 2.5
ВЫБРАТЬ
СУММА(ВЫБОР
КОГДА РаботникиОрганизаций.ЗанимаемыхСтавок > 0
ТОГДА 1
ИНАЧЕ -1
КОНЕЦ) КАК Количество,
табПериодов.ДатаПериод КАК ДатаПериод
ИЗ
(ВЫБРАТЬ
КОНЕЦПЕРИОДА(КурсыВалют.Период, МЕСЯЦ) КАК ДатаПериод
ИЗ
РегистрСведений.КурсыВалют КАК КурсыВалют
ГДЕ
КурсыВалют.Период МЕЖДУ &НачПериода И &КонПериода
СГРУППИРОВАТЬ ПО
КОНЕЦПЕРИОДА(КурсыВалют.Период, МЕСЯЦ)) КАК табПериодов
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ПО табПериодов.ДатаПериод >= РаботникиОрганизаций.Период
ГДЕ
НЕ РаботникиОрганизаций.ПричинаИзмененияСостояния = ЗНАЧЕНИЕ(Перечисление.ПричиныИзмененияСостояния.Перемещение)
СГРУППИРОВАТЬ ПО
табПериодов.ДатаПериод
УПОРЯДОЧИТЬ ПО
ДатаПериод