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




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

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 не будет опубликован. Обязательные поля помечены *