ФИФО для любопытных




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

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

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

<?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='\

99 Comments

  1. Ish_2

    Глюки и ошибки сайта при создании и редактировании новой публикации

    вызывают грусть. И печальные обобщения.

    Reply
  2. Арчибальд

    (1) Поставил плюс за внятность изложения. И чуть было не снял за мизантропию 😀

    Reply
  3. Ish_2

    Не снимай ! Я тебя еще повеселю .

    Захотелось «внятно» ответить на тягучие разговоры о » жизни без последовательностей » и «отказе от партионного учета».

    Reply
  4. Шёпот теней

    (3) … хм … прекрасно всем известно … сделать можно всё … как впрочем и оправдать …

    если меня что-то и интересует то только с точки зрения экономической эффективности … а это как прАвило простота решения, пусть даже и более длинного …

    такой же принцип и в массовом производстве … так технологичесие процессы расположены вне логики ручного труда …

    … вот …

    Reply
  5. Арчибальд

    (3) А кто это отказывался от партионного учета? Мы его заклеймим!

    А жизнь без последовательностей радостна и безоблачна, и никакого отношения к партионному учету не имеет.

    Партионный учет — объективная потребность (а значит, реальность).

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

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

    Reply
  6. Ish_2

    (5) Арчибальд , ты , конечно, кавалер авторитетный и всё такое…

    Но :

    «Потребность = реальность»,

    «последовательность = химера»

    — э..э .. перехвалили тебя .

    В «восьмерке» не остались , а добавились запросы как признание столбовой дороги развития СУБД . Представленный алгоритм как раз и говорит :

    авторитетному мужчине пора завязывать с 77.

    Reply
  7. anig99

    поправь ссылочку в конце и на статью Шепота ещё можно сослаться.

    Reply
  8. Ish_2

    (7) Поправил. И Шепоту досталось.

    Reply
  9. anig99
  10. anig99
  11. Ish_2

    (10) В указанных ссылках у Шепота приводится понимание Шепотом нарастающих итогов и ни слова про их эффективное вычисление.

    Reply
  12. anig99

    (11) но там примерно так же описан пример для получения этих самых нарастающих итогов.

    Reply
  13. Шёпот теней

    существует множество разных языков … все они что делаю хорошо а что-то плохо …

    язык запросов существует для получения копий таблиц + фильтрация из БД …

    пытаться программировать, манипулировать данными на уровни запросов — утопия … и СКД это наглядно демонстрирует … Запрос+ТЗ = универсально, практично, феерично …

    запрос + тз = неограниченные возможности в манипулировании данными … быстрота в объединении этих возможностей а не в их пересечениях … вот …

    … понятно, как задача для ума может это и интересно … но не более …

    … вот …

    Reply
  14. Ish_2

    (13) Черт возьми , стал бы я практиковаться «для ума » !

    В настоящий момент я считаю такую процедуру самым быстрым и эффекивным способом получения всех движений по регистру партий (читай- перепроведения документов по регистру партий).

    Нужна ,конечно, тестовая конфигурация для подтверждения этого мнения. Пока она не представлена.

    Шепот , ты упорно не хочешь изучать СКД.

    Можно сказать , что в узком смысле СКД = запрос+тз+обработка тз.

    Уж за что 1с не должно быть стыдно , так это за СКД.

    «пытаться программировать, манипулировать данными на уровни запросов — утопия … и СКД.»

    Я не согласен с тобой. Работая в клиент-серверном варианте мы, наоборот, просто обязаны пытаться «программировать, манипулировать данными» при помощи запросов. Для тебя же запросы — средство простой выборки данных, после которой «тыканье кнопок» ,т.е. любимый кодинг.

    Скажи, Шепот , тебя убедит что текущий алгоритм не баловство «для ума » если в рамках рассматриваемой конфигурации ты получишь по сравнению с обычным перепроведением ускорение в сотни раз ?

    Reply
  15. Шёпот теней

    Ish_2 у меня совершенно нет желания принижать твой труд и его оспаривать … наоборот я им восхищаюсь равно как и трудами anig99 …

    .. хм… в сотни раз …. это конечно ты перебрал хотя упорствовать не буду … но я точно знаю что труды ВалерычА ( http://infostart.ru/profile/36029/ ) гораздо продуктивнее … он уже добился быстродействия в 100 раз а возможно и более …

    также хочется напомнить и про труд Владимира ( http://infostart.ru/profile/2905/ ) хотя и в рамках отдельной конфигурации …

    … добиваться же быстродействия в рамках запроса …? для меня очень и очень не понятно — для меня это создание исскуственных трудностей на пути поиска простых и эффективных решений …

    … соглашусь и с возможной, своей полной или частичной — НЕграмотностью …

    … вот …

    Reply
  16. Шёпот теней

    (15) + забыл … видимо не совсем точно написал : СКД как раз и демонстрирует что Запрос+ТЗ есть сила …

    … вот …

    Reply
  17. Ish_2

    (15) Шепот , принижай мой труд ! Разрешаю.

    Но убедительно — с аргументами.

    Представь себе , что я внимательно читаю и проверяю ,что ты мне написал.

    Ссылки на Валерыча и Владимира не убеждают .

    Они рассматривали совсем другие темы.

    Reply
  18. Шёпот теней

    (17) … уж нет … увольте Вас убеждать, Вас — это ваше поколение … мне хвататет этого удовольствия и в жизни … ваш молодЁжный бег по кругу меня никак не интересует …

    в 1С запрос это только «чтение» … запись не возможна … любые операции с данными гораздо проще делать в таблицах, массивах ….

    … я сам закрываю 26 счет, для подсчёта нулевой рентабельности, нууу это типа точкаБЕЗубыточности … 3 разными способами … прекрасно знаю что 1С механизмы очень долгие и добиться увеличения быстродействия на порядок, заменив их на свои, это почти без проблем ….

    ссылки на ВалерычА и Владимира считаю основными … так как эти товарищи прекрасно демонстрирует силу самостоятельного программирования … не умаляя 1С как сверхУниверсальную систему …

    … ВОТ …

    Reply
  19. Шёпот теней

    (17) спорить конечно бесПолезно т.к. рано или поздно все приходит к записи таблицы … нууу, например у тебя: «…Полученную таблицу движений можно или «подокументно» записать в регистр партий или предварительно сравнить с существующими движениями в регистре и записать только «изменения». …»

    … по сути, мы пропагандируем одно и то же решение — оптимально, 1С часто это делает неЭффективно из-за своей гиперУниверсальности, любыми доступными методами собрать данные в таблицу и записать её … здесь мы едины … просто я считаю что запрос для оперирования данными не эффективен а ты считаешь наоборот … вот …

    Reply
  20. Ish_2

    (19) Говорю тебе : молодое поколоние выбирает запросы . И осуждает Шепота.

    За что ? А вот за это :

    1. «… добиваться же быстродействия в рамках запроса …? для меня очень и очень не понятно»

    2. «просто я считаю что запрос для оперирования данными не эффективен..»

    Запрос бывает эффективен или неэффективен не вообще , а для конкретной задачи.

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

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

    Reply
  21. anig99

    (13) язык запросов 1с может и существует только для получения информации, но в БД в чистом виде всё основывается на этих запросах и их быстродействии. Если посмотреть на работы по анализу производительности Гилёва, то основа у него — разбор запросов к СУБД генерируемых платформой 1с. Если всё сводилось только к кодингу в классическом смысле, то можно было бы продолжать работать с файлами с текстовом формате. БД и были придуманы для ускорения работы с чтением и записью в огромных массивах данных. А основной язык общения с СУБД — это запросы. И чем больше объем данных, тем более эффективным является правильно построенный запрос в правильно созданной БД по сравнению с обработкой кодом.

    Естественно, запросный подход не идеален (а уж тем более запросный 2го уровня, когда запрос «транслируется» в родной язык БД), в частности, с учетом нарастающих итогов… Поэтому нужно соизмерять важность скорости получения результата и сложность достижения этой скорости. Поэтому поводу — пусть 1с самый простой и самый долгий — «перепровести всё нах» или какой-то, видимо, относительно простой, но ОЧЕНЬ долгий алгоритм примененный в документе «корректировка стоимости партий» (у меня он идет 7 часов! а результирующих движений 3000-7000 тыс на регистр, т.е. большую часть времени происходят именно расчеты). Второй путь — код и много мелких запросов — сейчас я его использую и проверка Fifo хоть и занимает несколько часов, но всё же меньше, чем проведение по партиям. 3ий неизвестный по поведению относительно производительности — расчет в одном сложном и оптимизированном запросе.

    Reply
  22. Ish_2

    (21) Конечно.

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

    Меня смущает составное поле в условиях соединения — МоментВремени.

    Индекировать врем.таблицу по нему нельзя. Означает ли это , что оптимизатор запроса будет сканировать не индекс , а основную таблицу — что приведет к замедлению ?

    Reply
  23. alexk-is

    (22) Сделай 2 поля Период и МоментВремени. Период точно можно проиндексировать.

    Reply
  24. alexk-is

    Запросы в статье можно раскрасить получше 🙂

    Reply
  25. Ish_2

    (24) Возможно, нужно раскрасить по-приличней.

    Но мы с Шепотом как-то всё по-дедовски , да по-старинке ….

    Reply
  26. Ish_2

    (23) Но тогда в условии соединения вместо

    НарРасход.МоментВремени > НарПриход.МоментВремени

    придется написать

    НарРасход.Период> НарПриход.Период ИЛИ

    НарРасход.Период = НарПриход.Период И

    НарРасход.Регистратор > НарПриход.Партия

    Насколько мне известно, оптимизатор запроса если в условии соединения есть «ИЛИ»

    вынужден сканировать не индекс , а основную таблицу. Что тоже не есть хорошо, т.к.

    таблицы НарПриход и НарРасход могут быть очень большого размера.

    Reply
  27. alexk-is

    (26) Вот без ИЛИ

    НарРасход.Период > НарПриход.Период И

    НарРасход.МоментВремени > НарПриход.МоментВремени

    Reply
  28. Ish_2

    (27) Не понял. В твоем выражении

    «НарРасход.Период>НарПриход.Период» — лишнее условие.

    Потому что из «НарРасход.МоментВремени > НарПриход.МоментВремени » совершенно очевидно следует «НарРасход.Период>=НарПриход.Период».

    И оптимизатор запроса всё равно будет проверять условие по Моменту времени.

    В чем выигрыш ?

    Reply
  29. Ish_2

    (27) Редактирование поста (28) , судя по всему невозможно. В нем ошибка.

    Мне непонятен смысл : зачем добавлять еще одно выражение , т.е.

    «НарРасход.Период > НарПриход.Период »

    если оптимизатор запроса всё равно будет проверять неиндексируемое поле МоментВремени в

    «НарРасход.МоментВремени > НарПриход.МоментВремени»

    В чем выигрыш ?

    Reply
  30. alexk-is

    В том, что во временной таблице его можно проиндексировать.

    Reply
  31. Ish_2

    (30) Мда… Браво !

    Действительно, МоментВремени НЕЛЬЗЯ влючать в индекс в основных таблицах и МОЖНО Включать в индекс во временной таблице.

    Reply
  32. ildarovich

    (22) Могу сделать следующий, на первый взгляд парадоксальный вывод:

    сравнение

    НарРасход.МоментВремени > НарПриход.МоментВремени

    в Вашем запросе НЕ ТРЕБУЕТСЯ!!!

    Эта логическая ошибка поясняется схемой в файле (рис.2). Кстати, схема, поясняет и сущность метода. На словах дело в том, что проверка нужна, чтобы избежать списаний «по-красному». Но если Вы вырезаете их такой проверкой, то почему не уменьшаете на сумму вырезанных списаний накопленный расход?

    Выход в том, чтобы списывать по-красному (тогда проверка не нужна!), либо делать третий накопленный расход (запрос будет другим)

    Reply
  33. Ish_2

    (32) Попытаюсь понять. Завтра.

    Странно, но рисунки перед опубликованием рисовал до смешного похожие на Ваши .

    Хотя, возможно, это единственный наглядный способ отображения сути соединения по двойному неравенству.

    Reply
  34. ildarovich

    Теперь о грустном…

    Оценка трудоемкости запросов 1, 2 и 3 приводит к формуле

    O(n * n / 2) + O(m * m / 2) + O(n * m / 2),

    где n — число приходов, m — число расходов. Оценка обосновывается

    методом «вложенных циклов», который используется при оптимизации запросов.

    Действительно, для каждого прихода в запросе 1, например, требуется просуммировать

    в среднем n / 2 записей (при использовании индекса по моменту времени). То есть,

    трудоемкость пропорциональна квадрату числа приходов (расходов для запроса 2).

    Ускорение по методу http://infostart.ru/public/61295/ изменит оценку на следующую

    O(n * ln(n)) + O(m * ln(m)) + O(n * m / 2),

    что, конечно, гораздо лучше, но при наличии процедурных подходов с трудоемкостью

    O(n + m),

    не требующих дополнительной памяти

    (а в Вашем случае хранится и обновляется примерно log(n) уровней итогов),

    преимуществ метода «одного запроса» не усматривается.

    Вас мог смутить реальный выигрыш по быстродействию метода

    http://infostart.ru/public/61295/ в задаче просроченной задолжности.

    Но там не было внешнего цикла! Там был переход от пропорции O(n) к пропорции O(ln(n)),

    что существенно. В задаче ФИФО есть внешний цикл — задачу накопления нужно решить для каждой накладной.

    И это все меняет.

    Не знаю, можно ли надеяться, что 1С в своей обертке SQL даст нам возможность быстрого нахождения тэта-соединений таблиц

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

    Взять, к примеру, агрегаты в 8.2.

    Но пока встроенных нарастающих итогов в запросах нет и компромиссом будут процедурные решения. 😥

    Кстати, похожий вопрос обсуждался здесь:

    http://www.sql.ru/forum/actualthread.aspx?bid=1&tid=113703&pg=1

    Reply
  35. CheBurator

    А вот что, нельзя было 3-5 предложениями описать ИДЕЙНУЮ суть алгоритма?

    Reply
  36. Ish_2

    (35) Возможно, ты прав.

    Но я побоялся рисовать что-то подобное рисунку в (32). Подумал что это не облегчит понимание , а еще больше запутает.

    Reply
  37. Шёпот теней

    (36) … за одного битого — двух не-битых дают … вот …

    Reply
  38. Ish_2

    После набора длинного ответа на (32) — ошибка сайта.

    Регулярные глюки сайта просто бесят.

    Reply
  39. Шёпот теней

    (38) … ИС — бегая за «формой» однозначно теряет в «содержании» … вот …

    Reply
  40. Ish_2

    (32) Не согласен.

    Строка в условии соединения

    «НарРасход.МоментВремени > НарПриход.МоментВремени »

    совершенно необходима.

    Если это условие убрать , то более ранний расход «спокойно» спишется с более позднего прихода.

    Как мы тогда в выходной таблице отловим эту ошибочную ситуацию ?

    Компромиссом следует считать следующий подход :

    Строка

    «НарРасход.МоментВремени > НарПриход.МоментВремени » из условий соединения убирается.

    А в поля выборки добавляется строка

    «Выбор Когда НарРасход.МоментВремени > НарПриход.МоментВремени

    Тогда Истина

    Иначе Ложь

    Конец как ПризнакСвоевременности»

    Тогда появляется возможность «отловить» в входной таблице эту ошибочную ситуацию.

    Поэтому предложение просто убрать строку

    «НарРасход.МоментВремени > НарПриход.МоментВремени »

    из условий соединения нельзя назвать верным.

    А в файле СписаниеПоМетодуФИФО.dt применено ЛЕВОЕ СОЕДИНЕНИЕ.

    С обработкой значений NULL.

    Reply
  41. Арчибальд

    (38) За одного бита дают 1/8 байта 😎

    Reply
  42. Ish_2

    (34) Теперь о грустном :

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

    Но и без формул понятно , что количество вычислений в текущем алгоритме больше , чем при «процедурном подходе».

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

    Но Ваш пост , как я понял, о другом . Из него вытекает :

    Для исходных таблиц значений Приход и Расход можно привести такой кодинг с циклами («процедурный подход») , реализующий метод ФИФО , который многократно

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

    Так ?

    Reply
  43. ildarovich

    (40) Да, правильно, если проверка и нужна, то только для вычислений «ПризнакСвоевременности», а не для отбора записей в соединяемой таблице. При этом индекс по МоментВремени не нужен.

    А вот левое соединение и обработка NULL — это неправильно, так как если расход не сделан, то следующие «своевременные» расходы должны соединяться с приходами, пропущенными в паре с несвоевременными расходами.

    Reply
  44. ildarovich

    (42) Да, так. Причем для Вашего «модельного» случая код занимает один — два десятка строк.

    Reply
  45. Ish_2
    А вот левое соединение и обработка NULL — это неправильно, так как если расход не сделан, то следующие «своевременные» расходы должны соединяться с приходами, пропущенными в паре с несвоевременными расходами.

    Для каждой значения Номенклатуры из таблицы НарРасход мы строим движения по регистру партий.

    Поэтому если N-расход по M-номенклатуре получился «красным» , то зачем нам последующие «своевременные» расходы N+1,N+2 и т.д. по M-номенклатуре ?

    Совершенно очевидно , что они не имеют смысла .

    Для М+1-номенклатуры , конечно, будет выстроена своя последовательность движений расходов. Как и для M+2,M+3 и т.д.

    Вот почему утверждение в приведенной цитате — неверно.

    Тем более если в таблице НарРасход для М-номенклатуры имеются записи со значением поля КоличествоДо больше любого КоличествоПосле в таблице НарПриход эта запись при ВНУТРЕННЕМ СОЕДИНЕНИИ просто «пропадёт» в выходной таблице «без следов».

    При ЛЕВОМ СОЕДИНЕНИИ мы достигаем того, что в выходной таблице гарантировано будут присутсвовать все регистраторы-расходы. И по полям признакам мы сможеи определить какое движение регистратор — неверное (или «красное»).

    Reply
  46. Ish_2

    (44) Согласен.

    Reply
  47. ildarovich

    (45) Не буду занудой и соглашусь, так как речь идет о реакции на ошибку пользователя. А это, в общем-то, дело вкуса. Как в анекдоте про тараканов — неважно утонут они или подорвутся на минах 😀

    Reply
  48. Ish_2

    (47) Ну и заканчивая , можно сказать :

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

    то единственной , достойной внимания особенностью представленного алгоритма является перенос в трехзвенной системе( клиент-сервер приложений- сервер БД) всех вычислений на сервер БД.

    Reply
  49. orefkov

    Все в одном запросе это конечно хорошо, но пока больше походит на то, что 1С из инструментов дала только вилку, и для поедания супа приходиться изголятся и пытаться сложить ложку из кучи вилок. В нормальной БД получение нарастающих итогов легко делается процедурным методом на сервере — обходишь курсор и подбиваешь суммы.

    Reply
  50. Арчибальд

    (49) Хоть не палочки бамбуковые 😮

    Reply
  51. truba

    (49) курсор рулит

    Reply
  52. Ish_2

    (49) Я так и не отгадал загадку :

    Почему в языке запросов 1с не разрешен Update.

    Понятно , что не стоит разрешать Update при обращении к таблицам БД.

    Но почему не разрешен Update к временным таблицам хоть убей — не пойму.

    Reply
  53. Ish_2

    (51) Конечно, так. Но по ссылке в (34) нашел цитату Aleks2 на SQL.ru

    Запомни:

    1) Если у тебя есть возможность не пользоваться курсором — не пользуйся им.

    2) Если у тебя НЕТ возможности не пользоваться курсором — ВСЕ РАВНО НЕ ПОЛЬЗУЙСЯ.

    ————-

    Запрос всегда быстрее курсора, единственное исключение: неправильный (неоптимальный) запрос.

    В общем случае это ,конечно, неверно. Но уж больно симпатично.

    Reply
  54. orefkov

    (53)

    Ну, опять же на нормальной БД нарастющие итоги на врем-таблицу можно накрутить и без курсора.

    update vt_total
    set @СуммаНачало = case when vt_total.НоваяСтрока = 0 then @СуммаКонец else vt_total.СуммаНачало
    ,@СуммаКонец = @СуммаНачало + vt_total.Оборот
    ,vt_total.СуммаНачало = @СуммаНачало
    ,vt_total.СуммаКонец = @СуммаКонец 
    Reply
  55. Ish_2

    (54) Ага,примерно так.

    И получается , что наличие в языке запросов Update делает ненужными любые разговоры об эффективном вычислении нарастающих итогов , занимающего

    львиную долю времени в текущем алгоритме.

    Reply
  56. hogik

    (55)(54)(51)

    Логотип темы — «Мы пишем запросы!».

    Позволю себе высказаться не в тему.

    Для простого и эффективного решения аналогичных задач не требуются:

    1) Наличие в языке запросов Update.

    2) Временные таблицы.

    3) Процедурные методы на сервере.

    4) Курсоры.

    5) Всякие «левые» и «правые» соединения.

    Да и сами запросы не требуются. 😉

    Печально, что движение по «столбовой дороги развития СУБД»(с) ведет в тупик. А «круглые колеса, на каких во всем мире принято ездить»(с) ускоряют это движение… 🙁

    Reply
  57. Ish_2

    (56) Хм.. Владимир, Вы упорно отстаиваете свой экстравагантный взгляд на развитие СУБД с отрицанием языка запросов SQL . И ,как обычно, не приводите хотя бы внятного обозначения альтернативного подхода.

    Впрочем , однажды Вы в своей теме привели текст кода а-ля Clipper Summer ’87, обозначающий Ваш подход к решению такого рода задач и заставивший меня смахнуть слезу :

    do while !eof()

    ………

    enddo

    Т.е. сканирование таблицы и ручной кодинг.

    Возврашаясь в 1987г , Вы отрицаете ту самую двадцатилетнюю «столбовую» дорогу :

    -Утверждение стандарта SQL от 1992г.

    -Развитие трехзвенной системы клиент-сервер приложений-сервер БД.

    Оно конечно, Вам это никто не запретит. Но думаю , Вы найдете мало сторонников.

    Если вдруг на каком -то этапе на «столбовой» дороге откажутся от языка запросов — я первый сниму перед Вами шляпу.

    Reply
  58. hogik

    (57)

    Игорь.

    Я не отрицаю язык запросов в развитии СУБД. Я утверждаю, что для наших задач надо иметь ДВА способа (ЯМД) обработки данных. И в задачах типа «Нарастающие итоги» просматривать таблицы построчно в обычном цикле на стороне клиента. Это быстрее работает, не загружает сервер лишней работой, проще писать ««ручной кодинг»». Есть алгоритмы, где эффективней использовать язык запросов.

    А в целом, наличие двух ЯМД позволяет проектировать схему БД не под средства манипулирования данными, а под предметную область. И отпадает необходимость в «трехзвенной» архитектуре, как средства преобразования одного ЯМД в другой.

    Reply
  59. rhtr

    В дохновляет! 💡

    Reply
  60. Ish_2

    (58) Истина всегда конкретна (с).

    Соображения общего плана (58) меня мало в чем убеждают.

    Разберемся конкретно .

    Мы разбираем задачу вычисления нарастающих итогов в клиент-серверной архитектуре.

    Цитататы :

    «Для простого и эффетнаективного решения аналогичных задач не требуются:

    1..5 . Да и сами запросы не требуются..»

    «И в задачах типа «Нарастающие итоги» просматривать таблицы построчно в обычном цикле на стороне клиента. Это быстрее работает, не загружает сервер лишней работой, проще писать ««ручной кодинг»».»

    Из этих цитат вытекает , что в клиент-серверной архитектуре для вычисления нарастающих итогов:

    1. БОЛЕЕ эффективно загрузить таблицу с сервера на клиента и далее на клиенте ручным кодингом просканировать таблицу в цикле (do while…skip…enddo).

    2. МЕНЕЕ эффективно оставить таблицу на сервере и одной командой Update получить таблицу нарастающих итогов см (54)

    Так ? Или я что-то напутал ?

    Reply
  61. anig99

    Кстати… С одной стороны, обработка на клиенте удобнее… С другой стороны это противоречит концепции тонкого клиента и web интерфейсов. Узкие или загруженные каналы требуют уменьшение объема передаваемой информации. Это раз. Во-вторых, клиентские машины могут быть маломощными не только из-за экономии средств. Нетбуки, наладонники и т.д. имеют возможность работы с 1с, но не могут переваривать огромные объемы информации. Поэтому нужно идти по пути переноса обработки данных с клиентских компьютеров на сервера в любом виде: будь то запрос, или инструкция к компилятору.

    Reply
  62. hogik

    (60)

    Игорь.

    1) Для обработки таблицы навигационным способом не требуется загружать таблицу с сервера на клиент. Выполняется чтение по одной записи. Вычисление и накопление нарастающего итога на клиенте для каждой строки в переменной оперативной памяти. Выводится в отчет строка вместе с вычисленным итогом. Т.е. выполняется чтений столько раз, сколько строк в таблице (обозначим — N).

    2) На сервере же формируется рабочая таблица (в простейшем случае N чтений и N записей). Далее читаем каждую строку рабочей таблицы (N чтений), вычисляем нарастающий итог и записываем его в каждую строку (N обновлений). Далее передаём все строки рабочей таблицы клиенту (N чтений). Итого 5*N чтений/записей.

    По сети, в обоих способах, предаётся одинаковое количество строк.

    Reply
  63. Ish_2

    (62) Владимир.

    Чтение (62) вызвало у меня столько вопросов, что я просто оробел что-то спрашивать.

    Допускаю, что моего разумения просто не хватает , чтобы осилить (62).

    Reply
  64. hogik

    (63)

    Игорь.

    Жалко, что Вы принципиально не используете «смайлы».

    Сообщение #63 – это шутка?

    Или намек на мою дурость?

    Reply
  65. Ish_2

    (64) Намек на мудрость.

    Reply
  66. rhtr

    Этап III .Особенно — «предварительно сравнить с существующими движениями в регистре и записать только «изменения». А на этом месте можно поподробнее.Будет очень хорошо если дополните конфу.Вам же как Гению Партий!!!.

    Пасиба 🙂

    Reply
  67. Ish_2

    (66) Место Гения давно и прочно занято.

    Вариант:

    1. Мы получили запросом ТаблицуДвижений.

    2. Делаем Полное Соединение с движениями из регистра партий.

    3. Оставляем в таблице , полученной в п.2, только расхождения , т.е. получаем ТаблицуРасхождений.

    4. Затем с помощью запроса

    «Выбрать Различные Регистратор ИЗ ТаблицаРасхождений» получаем таблицу -столбец

    с документами , которые нужно перепровести.

    5. Сканируя таблицу, полученную в п.4, для каждого документа- регистратора выбираем нужные движения из ТаблицыДвижений и записываем их в регистр.

    Reply
  68. Арчибальд

    (67)

    Место Гения давно и прочно занято.

    Кем 😮

    Reply
  69. Ish_2

    (68) Гений 1с , в миру Осипов Сергей.

    Об изгнании его с ИС я писал в теме Life «Тошнота как реакция на свободу».

    Reply
  70. Арчибальд

    (69) Фуу… А я-то понял, что его место на ИС кто-то занял 😀

    Reply
  71. Ish_2

    (71) Пока нереально.

    Если в языке запросов 1с появится Update , Declare , Create Table (для временных таблиц), то представленный алгоритм , на мой взгляд, для больших таблиц выиграет у любого другого.

    Это предсположение основывается на том , что

    вся тяжесть вычислений в алгоритме ложится на вычисление нарастающих итогов.

    С помощью команды Update нарастающие итоги считаются очень быстро.

    Reply
  72. NCCSOFT

    Два года назад я тоже самое пытался сделать для 7.7 😀 на языке MS SQL, и там есть Update, но его скорость меня не устроила, так как базу проводил за 3 года (FIFO), потом выгружал в динамические таблицы в SQL — тоже тормоза… потом плюнул на все технологии выгрузил данные в txt-файл (10 мин), на Дельфи конвертирую в свой формат (2 мин), записываю (чтобы при следующих запусках не конвертировать по-новой), и делаю расчет по FIFO. База за 3 года проводится за 1 секунду (ОДНУ СЕКУНДУ). Вот и все. Разработка тут: Разработка тут Скоро сделаю внешнюю обработку для 8.1 — выгрузка данных, чтобы можно было проверять 1С — правильно ли она по FIFO считает.

    Reply
  73. Шёпот теней

    (69) … а я не нашЁл у Вас этой статьи … нельзя ли её где-нибудь и как-нибудь по-читать-то … ? … или дайте пожалуйств ссылку НЕумелым … вот …

    Reply
  74. seleand

    (72) согласен с Маньяком. Решение задачи в лоб — это просто жесть.

    Вы ждете возможностей языка, которые позволят втиснуть ваши огромные вычисления в рамки приличий по быстродействию? А решение лежит в другой стороне. Смоьтреть надо в сторону изменения структуры регистров, которая позволит анализировать только то, что реально нужно…

    Reply
  75. Ish_2

    (73) В солнечной Анапе , чтобы выйти в интернет на почте нужно предьявить паспорт.

    Попросив уже сидевшего за компьютером человека посмотреть ИС , увидел комментарий и побежал за паспортом. Жара , скучно, на море ни ногой — делать нечего.

    Как обычно , хмыкну там где восторгается Шепот.

    Выгрузки — загрузки в txt, потом в свой формат и т.д, чтобы потом «ЗА ОДНУ СЕКУНДУ» !

    — это для кого текст ? Для специалистов ? Если — да , то для каких ?

    В статье предлагается общий алгоритм списания по методу ФИФО.

    Который может быть реализован как на платформе 1с , так и на другой платформе средствами только TSQL. В последнем случае эффективность реализации алгоритма многократно выше.

    ( с помощью Update нарастающие итоги считаются быстрее)

    Reply
  76. Ish_2

    (75) Маньяк так Маньяк. Жесть так жесть. Это понятно.

    Остальной текст «жестьтоко» загадочен.

    Reply
  77. tango

    кто выдал ишу паспорт?

    Reply
  78. NCCSOFT

    (76) Привет отдыхающим!! 😉

    Выгрузка и загрузка (конвертация) у меня происходят в 3 часа ночи… зато при открытии пользователем мгновенно загружается в динам.массив и идет работа с OLAP (по вчерашний день)….

    Метод FIFO на 1С делал применительно к расчету дебиторки / кредиторки, когда считал взаиморасчеты и самое главное кол-во дней просрочки… быстродействия хватило… «Отчеты о просрочке долгов» А вот с партиями — увы нет — 1С это не потянет!!! — точнее база будет проводится столько ко же, как при обычном проведении, ну не 6 часов, а всего 2 часа 🙂 Потом на SQL делал хранимую процедуру метода FIFO — тоже тормоза… ну не может SQL сделать update даже миллиона записей!!!! (поле себестоимость) — не может и все!! select может, а update нет….

    В общем то, статья хорошая, все нормально. Метод FIFO, LIFO,… известные. Есть даже метод «списания максимальной себестоимости» (который придумал мой знакомый)… Но мне все же нравится метод FIFO!

    Кстати, когда я практически его реализовывал — и при гашение долгов и при гашении партий — выяснилось, что «в чистую» этот метод на практике не применим, и «за один проход» не получается. А причина была в том, до метода FIFO приходится делать первый проход при котором идет гашение с учетом явных ссылок (начиная от сторно, возврат ошибочно перечисленных сумм, возврата товара и других движений….). Вот, что хотелось бы добавить к статье.

    (78) 🙂

    Reply
  79. Ish_2

    (78) Вот и ты , Миша, не любишь иша … Как эта тетка на почте :

    — Мужчина в желтых трусах ! Я же вам сказала : отойдите от компьютера.

    А трусы у меня , Миша, между прочим адидасовские — яркие ,оранжевые.

    Адидас, правда, цыганский и кореша говорят , что похож я в них не на голландца ,а на бандеровца. Но они мне нравятся и я их ношу…

    — Пустите . Я же в прошлый раз Вам паспорт показывал.

    — Мужчина мне нужно внести ваши данные . Вы это понимаете ?

    Крыть было нечем и я решился .. перегнувшись через стойку доверительно сообщил:

    — Девушка , а трусы на мне не желтые , а померанчевые ! Бачишь ?

    Пока она с трудом подбирала ответ я понял , что не попал. Мда… Здесь вам не инфостарт , «штучки-дрючки» не проходят и не дожидаясь ответа ,я поперся за паспортом.

    Reply
  80. Арчибальд

    (80) Таки тетка или девушка?

    Reply
  81. Ish_2

    (81) Кавалер к тетке обращается — «девушка!». Не знал ?

    Reply
  82. Арчибальд

    (82) Не знал. Сам пользуюсь терминами «сударыня» или «миледи» 😳

    Reply
  83. y-str

    Добрый день!

    Создал новую публикацию (http://infostart.ru/public/88999/) с возможным альтернативным алгоритмом.

    Милости прошу комментировать 🙂



    С уважением,

    Юрий Строжевский

    Reply
  84. ambal49

    Вопрос, а если приходная накладная сделана со знаком минус? получается она выпадет из последнего запроса а по идее должна скорректировать предыдущие распределения, либо надо все приходы со знаком минус переквалифицировать в расходы со знаком плюс :). Что тоже неправильно 🙂

    Reply
  85. Ish_2

    (85) Приходы с отрицательной суммой в статье не рассматривается.

    1. Или нужно дополнительно обрабатывать таблицу приходов , что избавиться от «минусов».

    2. Или алгоритм по Фифо должен быть существенно усложнен.

    Reply
  86. vers139

    В СКД в вычисляемых полях появилось возможность использовать ВЫЧИСЛИТЬВЫРАЖЕНИЕ(). Лично у меня получилось поделить долг между накладными. Берём остатки по регистру взаиморасчёты, левое соединение на регистраторы регистра взаиморасчёты, сортировка в порядке убывания даты регистратора, группируем по клиенту и договору. + вычисляемое поле. В нём я использовал выражение:

    Выбор
    Когда ВычислитьВыражение(«Сумма(СуммаДок)», , , «Первая», «Текущая») < Долг
    тогда СуммаДок
    Когда ВычислитьВыражение(«Сумма(СуммаДок)», , , «Первая», «Текущая») — Долг < СуммаДок
    тогда СуммаДок — (ВычислитьВыражение(«Сумма(СуммаДок)», , , «Первая», «Текущая») — Долг)
    Иначе 0
    конец

    Всё почти хорошо. Однако при использовании дополнительной группировки по степени просроченности долга (долг не просрочен, долг просрочен не более на 5 дней, долг просрочен на срок 5-30 дней и т.д.) вычисляемое поле вычисляется в пределах отдельной группировке по степени просроченности долга, а не в пределах клиента. Подозреваю, что надо «побаловаться» с параметрами ВычислитьВыражение(), но пока не додумал. Может у кого-то получилось понять суть этих параметров. Прошу поделиться идеями, ибо у меня уже мозг закипает.

    Reply
  87. Ish_2

    (87) Вы описали задачу НЕ ФИФО , рассматриваемую в этой теме, а ПросроченныеДолги.

    В голову даже не приходило решать эту с помощью выражений СКД.

    Впрочем, я еще даже не установил 14 релиз платформы.

    Reply
  88. vers139

    (88) простите просматривал все темы по Накопленным итогам. В этой самые последние сообщения. Тем более, что дебиторка использует ЛИФО. Так что принцип, думаю, аналогичный.

    Reply
  89. S_DS

    Прикольно!

    Reply
  90. Ish_2

    (90) Как общее соображение принимается к сведению.

    На мой вкус, только не хватает вывода или утверждения.

    Reply
  91. tormozit

    Мне другая интересная задача недавно попалась —

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

    Дата Остаток ! Дозакупка НовыйОстаток

    01 -3 3 0

    02 4 0 7

    03 -1 0 6

    04 -4 0 2

    05 -7 5 0

    06 2 0 7

    Вот нужно получить колонку Дозакупка.

    Естественно хотелось бы решить ее запросом.

    Reply
  92. Ish_2

    (92) Мммм.. неплохо. Создай тему с решением.

    Я сыграю «вторым номером», т.е. оппонентом.

    P.S. На всякий случай : эффективного решения в данный момент у меня нет.

    Reply
  93. Ish_2

    (92) Впрочем, возвращаясь к твоей задаче, замечу , что такая постановка малопригодна для практического применения. Оформляя доп.приходы по итоговым остаткам на конец дня , мы не учитываем реальную ситуацию,при которой отрицательные остатки могут возникать несколько раз в течение дня .

    Конечно , можно решать и твою задачу как некий упрощенный частный случай.

    Но для общего случая ( интересен , на мой взгляд именно он) правильно формулировать следующим образом :

    Проверить и найти все отрицательные остатки за период возникшие после момента проведения любого расходного документа. Реализовать одним запросом.

    Другими словами , на входе имеем таблицы :

    НачОстаткиНаНачалоПериода

    ВсеПриходыЗаПериод,

    ВсеРасходыЗаПериод.

    На выходе должны получить таблицу РасходныеДокументыСОтрицательнымиОстатками.

    Далее нужен анализ :

    или сдвинуть расходный документ во времени в течение дня.

    или оформить доп. приход.

    Остатки на конец периода должны остаться неизменными.

    Таким должен быть , на мой взгляд , подход к решения такой задачи.

    Reply
  94. cargobird

    Скачал, запускаю на 8.3.9 в Конфигураторе.

    Загружает.

    Задает вопрос о конвертации.

    И после подтверждения сразу в дамп.

    Разучилась, видимо, превращать базы на 8.1 в 8.2.

    Пришлось искать 8.2 для конвертации и хорошо, что нашел, сконвертировал.

    Но оказалось что все еще проще. В окне настройки инф.базы надо поменять с 8.3 на 8.2)

    Или пятница, или уже очевидные вещи вылетают из головы)

    Reply
  95. CheBurator

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

    Reply
  96. Ish_2

    (96) CheBurator,

    Привет , Чебур. Сколько лет прошло ?

    Ты написал что-то умное и серьезное.

    После школы, стало быть , еще не забыл про «монотонно убывающие функции».

    А я забыл . Но был рад тебя почитать !

    Reply
  97. maxis33

    Отличный метод!

    А LIFO из него никто не делал?

    Reply
  98. maxis33

    Создал отдельную темку на форуме про LIFO.. если кто знает, помогите плз…

    http://forum.infostart.ru/forum9/topic220953/message2246820/#message2246820

    Reply
  99. Ish_2

    (99) Давно это было..Вряд ли помогу.

    Reply

Leave a Comment

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