gifts2017

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

Опубликовал Игорь Исхаков (Ish_2) в раздел Программирование - Практика программирования

Как одним запросом получить все движения расходных документов за период ?
В статье приводится альтернативный алгоритм списания по методу ФИФО .

Зачем это нужно ?

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


Постановка задачи .

Рассмотрим постановку задачи списания  по методу ФИФО в рамках простейшей конфигурации, содержащей справочник Номенклатура, документы РасходнаяНакладная и ПриходнаяНакладная, а также регистр накопления Партии. Период проведения расходных документов определен как [ДатаНачала,ДатаКонца].Получены две временные таблицы Приход и Расход (описание алгоритма будет сопровождаться демонстрационным примером).
Приход

Номенклатура

Партия МоментВремени Период Количество Сумма
Товар № 1 ПрихНакл №1            ..... 26.02.2010           100  1000
Товар № 1 ПрихНакл №2            ..... 01.03.2010           120

 1200

Таблица Приход может быть получена как объединение двух таблиц :таблица остатков партий на ДатаНачала и таблица движений документов ПриходнаяНакладная, полученная за период [ДатаНачала,ДатаКонца].

Расход

Номенклатура

Регистратор МоментВремени Период Количество Сумма
Товар № 1 РасхНакл №1            ..... 11.03.2010           80  800
Товар № 1 РасхНакл №2            ..... 14.03.2010

          40

 400

Товар № 1 РасхНакл №3            ..... 26.03.2010          100

 1000


Таблица Расход может быть получена при обращении к таблице Документы.РасходнаяНакладная за период  [ДатаНачала,ДатаКонца].

Требуется получить таблицу движений по регистру партий :

Номенклатура

Партия Период  Регистратор Количество Сумма


Алгоритм решения.

Рассмотрим упрощенный алгоритм получения движений регистра только по количеству. В демонстрационной конфигурации СписаниеПоМетодуФИФО.dt приведено более полное и подробное решение.

Этап I. 
Получим таблицы НарРасход и НарПриход , содержащие нарастающие итоги для каждой строки в колонках КоличествоДо и КоличествоПосле.

НарПриход

Номенклатура

Партия ... Период КоличествоДо КоличествоПосле
Товар № 1 ПрихНакл №1   26.02.2010           0       100 
Товар № 1 ПрихНакл №2   01.03.2010           100

      220

НарРасход

Номенклатура

Регистратор ... Период КоличествоДо КоличествоПосле
Товар № 1 РасхНакл №1   11.03.2010           0       80
Товар № 1 РасхНакл №2   14.03.2010

          80

     120

Товар № 1 РасхНакл №3   26.03.2010          120

     220

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

ВЫБРАТЬ

  
     Расход.Период,
    
Расход.МоментВремени,
     
Расход.Регистратор,
    
Расход.Номенклатура,
    
Расход.Количество,
    
Расход.Сумма,
    
СУММА(Расход1.Количество) - Расход.Количество КАК КоличествоДо,
    
СУММА(Расход1.Количество) КАК КоличествоПосле
ПОМЕСТИТЬ НарРасход
ИЗ  Расход КАК Расход
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Расход КАК Расход1
     ПО Расход.Номенклатура = Расход1.Номенклатура
     И Расход.МоментВремени >= Расход1.МоментВремени
СГРУППИРОВАТЬ ПО
    
Расход.Период,
    
Расход.МоментВремени,
    
Расход.Регистратор,
    
Расход.Номенклатура,
    
Расход.Количество,
    
Расход.Сумма

 

Этап II.
Одного внутреннего соединения таблиц НарРасход и НарПриход достаточно для получения выходной таблицы движений. Здесь мы описываем лишь суть алгоритма , поэтому в нижеприведенном тексте запроса ресурс Сумма не учитывается.

ВЫБРАТЬ
   
НарРасход.Период,
   
НарРасход.Регистратор,
   
НарПриход.Партия,
   
НарРасход.Номенклатура,
   
// Следующее поле "Количество" можно определить как
    // Мин(НарПриход.КоличествоПосле, НарРасход.КоличествоПосле)
    // - Макс(НарПриход.КоличествоДо, НарРасход.КоличествоДо)
   
ВЫБОР
     КОГДА
НарПриход.КоличествоПосле < НарРасход.КоличествоПосле
     ТОГДА НарПриход.КоличествоПосле
     ИНАЧЕ НарРасход.КоличествоПосле
     КОНЕЦ - ВЫБОР
            КОГДА
НарПриход.КоличествоДо > НарРасход.КоличествоДо
            ТОГДА НарПриход.КоличествоДо
            ИНАЧЕ НарРасход.КоличествоДо
     КОНЕЦ КАК Количество
ИЗ
  
НарРасход КАК НарРасход
   Внутреннее СОЕДИНЕНИЕ НарПриход КАК НарПриход
   ПО НарРасход.Номенклатура = НарПриход.Номенклатура
   И НарРасход.КоличествоПосле > НарПриход.КоличествоДо
   И НарРасход.КоличествоДо < НарПриход.КоличествоПосле
   И НарРасход.МоментВремени > НарПриход.МоментВремени


Таблица Движений
 

Номенклатура

Регистратор Партия Период Количество Сумма
Товар № 1 РасхНакл №1  ПрихНакл №1 11.03.2010           80  -нет
Товар № 1 РасхНакл №2  ПрихНакл №1 14.03.2010

          20

 -нет

Товар № 1 РасхНакл №2  ПрихНакл №2 14.03.2010           20

 -нет

Товар № 1 РасхНакл №3  ПрихНакл №2 26.03.2010          100  -нет

Этап III .

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

Замечания.

 

Приведенный в Этапе I запрос нагляден , но чрезвычайно затратен .В практических разработках при вычислении нарастающих итогов возможно применение подхода , описанного в статье "Подведем Итоги.Нарастающие"   http://infostart.ru/public/61295/. Применение же подхода Шепота - невозможно , потому что он ничего на эти темы не писал.

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

В тексте темы использована разукрашка Aleks-is http://www.infostart.ru/public/19856/

 

 

Скачать файлы

Наименование Файл Версия Размер
СписаниеПоМетодуФИФО.dt 351
.dt 35,91Kb
05.08.10
351
.dt 35,91Kb Бесплатно

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Игорь Исхаков (Ish_2) 02.04.10 09:49
Глюки и ошибки сайта при создании и редактировании новой публикации
вызывают грусть. И печальные обобщения.
2. Александр Рытов (Арчибальд) 02.04.10 09:53
(1) Поставил плюс за внятность изложения. И чуть было не снял за мизантропию :D
3. Игорь Исхаков (Ish_2) 02.04.10 09:59
Не снимай ! Я тебя еще повеселю .
Захотелось "внятно" ответить на тягучие разговоры о " жизни без последовательностей " и "отказе от партионного учета".
4. Александр Шишкин (Шёпот теней) 02.04.10 10:33
(3) ... хм ... прекрасно всем известно ... сделать можно всё ... как впрочем и оправдать ...

...

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

...

... вот ...
5. Александр Рытов (Арчибальд) 02.04.10 10:58
(3) А кто это отказывался от партионного учета? Мы его заклеймим!
А жизнь без последовательностей радостна и безоблачна, и никакого отношения к партионному учету не имеет.
Партионный учет - объективная потребность (а значит, реальность).
Последовательность - химера, рожденная в воспаленных мозгах разработчиков. Последовательности ирреальны, ибо не встречаются в жизни.
К сожалению, в отличие от других нервно-паралитических болезней, эта (использование последовательностей) оказалась заразной. А поскольку из всех лекарств в арсенале восьмерки остались одни запросы...
6. Игорь Исхаков (Ish_2) 02.04.10 16:45
(5) Арчибальд , ты , конечно, кавалер авторитетный и всё такое...

Но :
"Потребность = реальность",
"последовательность = химера"

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

В "восьмерке" не остались , а добавились запросы как признание столбовой дороги развития СУБД . Представленный алгоритм как раз и говорит :
авторитетному мужчине пора завязывать с 77.
7. Александр Медведев (anig99) 02.04.10 17:55
поправь ссылочку в конце и на статью Шепота ещё можно сослаться.
8. Игорь Исхаков (Ish_2) 02.04.10 18:10
(7) Поправил. И Шепоту досталось.
11. Игорь Исхаков (Ish_2) 03.04.10 19:53
(10) В указанных ссылках у Шепота приводится понимание Шепотом нарастающих итогов и ни слова про их эффективное вычисление.
12. Александр Медведев (anig99) 04.04.10 07:26
(11) но там примерно так же описан пример для получения этих самых нарастающих итогов.
13. Александр Шишкин (Шёпот теней) 04.04.10 16:18
существует множество разных языков ... все они что делаю хорошо а что-то плохо ...

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

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

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

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

... вот ...
14. Игорь Исхаков (Ish_2) 04.04.10 17:46
(13) Черт возьми , стал бы я практиковаться "для ума " !
В настоящий момент я считаю такую процедуру самым быстрым и эффекивным способом получения всех движений по регистру партий (читай- перепроведения документов по регистру партий).
Нужна ,конечно, тестовая конфигурация для подтверждения этого мнения. Пока она не представлена.

Шепот , ты упорно не хочешь изучать СКД.
Можно сказать , что в узком смысле СКД = запрос+тз+обработка тз.
Уж за что 1с не должно быть стыдно , так это за СКД.

"пытаться программировать, манипулировать данными на уровни запросов - утопия ... и СКД."

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

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

15. Александр Шишкин (Шёпот теней) 04.04.10 21:46
Ish_2 у меня совершенно нет желания принижать твой труд и его оспаривать ... наоборот я им восхищаюсь равно как и трудами anig99 ...

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

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

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

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

... вот ...
16. Александр Шишкин (Шёпот теней) 04.04.10 21:54
(15) + забыл ... видимо не совсем точно написал : СКД как раз и демонстрирует что Запрос+ТЗ есть сила ...

... вот ...

17. Игорь Исхаков (Ish_2) 05.04.10 07:36
(15) Шепот , принижай мой труд ! Разрешаю.
Но убедительно - с аргументами.
Представь себе , что я внимательно читаю и проверяю ,что ты мне написал.
Ссылки на Валерыча и Владимира не убеждают .
Они рассматривали совсем другие темы.
18. Александр Шишкин (Шёпот теней) 05.04.10 07:58
(17) ... уж нет ... увольте Вас убеждать, Вас - это ваше поколение ... мне хвататет этого удовольствия и в жизни ... ваш молодЁжный бег по кругу меня никак не интересует ...

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

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

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

... ВОТ ...
19. Александр Шишкин (Шёпот теней) 05.04.10 08:05
(17) спорить конечно бесПолезно т.к. рано или поздно все приходит к записи таблицы ... нууу, например у тебя: "...Полученную таблицу движений можно или "подокументно" записать в регистр партий или предварительно сравнить с существующими движениями в регистре и записать только "изменения". ..."

... по сути, мы пропагандируем одно и то же решение - оптимально, 1С часто это делает неЭффективно из-за своей гиперУниверсальности, любыми доступными методами собрать данные в таблицу и записать её ... здесь мы едины ... просто я считаю что запрос для оперирования данными не эффективен а ты считаешь наоборот ... вот ...
20. Игорь Исхаков (Ish_2) 05.04.10 08:50
(19) Говорю тебе : молодое поколоние выбирает запросы . И осуждает Шепота.
За что ? А вот за это :
1. "... добиваться же быстродействия в рамках запроса ...? для меня очень и очень не понятно"
2. "просто я считаю что запрос для оперирования данными не эффективен.."

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


21. Александр Медведев (anig99) 05.04.10 08:51
(13) язык запросов 1с может и существует только для получения информации, но в БД в чистом виде всё основывается на этих запросах и их быстродействии. Если посмотреть на работы по анализу производительности Гилёва, то основа у него - разбор запросов к СУБД генерируемых платформой 1с. Если всё сводилось только к кодингу в классическом смысле, то можно было бы продолжать работать с файлами с текстовом формате. БД и были придуманы для ускорения работы с чтением и записью в огромных массивах данных. А основной язык общения с СУБД - это запросы. И чем больше объем данных, тем более эффективным является правильно построенный запрос в правильно созданной БД по сравнению с обработкой кодом.
Естественно, запросный подход не идеален (а уж тем более запросный 2го уровня, когда запрос "транслируется" в родной язык БД), в частности, с учетом нарастающих итогов... Поэтому нужно соизмерять важность скорости получения результата и сложность достижения этой скорости. Поэтому поводу - пусть 1с самый простой и самый долгий - "перепровести всё нах" или какой-то, видимо, относительно простой, но ОЧЕНЬ долгий алгоритм примененный в документе "корректировка стоимости партий" (у меня он идет 7 часов! а результирующих движений 3000-7000 тыс на регистр, т.е. большую часть времени происходят именно расчеты). Второй путь - код и много мелких запросов - сейчас я его использую и проверка Fifo хоть и занимает несколько часов, но всё же меньше, чем проведение по партиям. 3ий неизвестный по поведению относительно производительности - расчет в одном сложном и оптимизированном запросе.
Valerich; Шёпот теней; +2 Ответить 1
22. Игорь Исхаков (Ish_2) 05.04.10 09:08
(21) Конечно.
Нужно только пробовать на твоей конфигурации , чтобы убедиться что эффективнее.

Меня смущает составное поле в условиях соединения - МоментВремени.
Индекировать врем.таблицу по нему нельзя. Означает ли это , что оптимизатор запроса будет сканировать не индекс , а основную таблицу - что приведет к замедлению ?
23. Алексей Константинов (alexk-is) 05.04.10 17:06
(22) Сделай 2 поля Период и МоментВремени. Период точно можно проиндексировать.
24. Алексей Константинов (alexk-is) 05.04.10 17:09
Запросы в статье можно раскрасить получше :)
25. Игорь Исхаков (Ish_2) 05.04.10 17:13
(24) Возможно, нужно раскрасить по-приличней.
Но мы с Шепотом как-то всё по-дедовски , да по-старинке ....
26. Игорь Исхаков (Ish_2) 05.04.10 17:26
(23) Но тогда в условии соединения вместо

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

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

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

Насколько мне известно, оптимизатор запроса если в условии соединения есть "ИЛИ"
вынужден сканировать не индекс , а основную таблицу. Что тоже не есть хорошо, т.к.
таблицы НарПриход и НарРасход могут быть очень большого размера.
27. Алексей Константинов (alexk-is) 05.04.10 17:43
(26) Вот без ИЛИ
НарРасход.Период > НарПриход.Период И
НарРасход.МоментВремени > НарПриход.МоментВремени
28. Игорь Исхаков (Ish_2) 05.04.10 18:20
(27) Не понял. В твоем выражении
"НарРасход.Период>НарПриход.Период" - лишнее условие.

Потому что из "НарРасход.МоментВремени > НарПриход.МоментВремени " совершенно очевидно следует "НарРасход.Период>=НарПриход.Период".
И оптимизатор запроса всё равно будет проверять условие по Моменту времени.
В чем выигрыш ?
29. Игорь Исхаков (Ish_2) 05.04.10 18:35
(27) Редактирование поста (28) , судя по всему невозможно. В нем ошибка.
Мне непонятен смысл : зачем добавлять еще одно выражение , т.е.
"НарРасход.Период > НарПриход.Период "
если оптимизатор запроса всё равно будет проверять неиндексируемое поле МоментВремени в
"НарРасход.МоментВремени > НарПриход.МоментВремени"
В чем выигрыш ?
30. Алексей Константинов (alexk-is) 05.04.10 20:06
В том, что во временной таблице его можно проиндексировать.
31. Игорь Исхаков (Ish_2) 05.04.10 20:27
(30) Мда... Браво !
Действительно, МоментВремени НЕЛЬЗЯ влючать в индекс в основных таблицах и МОЖНО Включать в индекс во временной таблице.
32. Сергей (ildarovich) 05.04.10 20:41
(22) Могу сделать следующий, на первый взгляд парадоксальный вывод:
сравнение
НарРасход.МоментВремени > НарПриход.МоментВремени
в Вашем запросе НЕ ТРЕБУЕТСЯ!!!
Эта логическая ошибка поясняется схемой в файле (рис.2). Кстати, схема, поясняет и сущность метода. На словах дело в том, что проверка нужна, чтобы избежать списаний "по-красному". Но если Вы вырезаете их такой проверкой, то почему не уменьшаете на сумму вырезанных списаний накопленный расход?
Выход в том, чтобы списывать по-красному (тогда проверка не нужна!), либо делать третий накопленный расход (запрос будет другим)
Прикрепленные файлы:
33. Игорь Исхаков (Ish_2) 06.04.10 00:19
(32) Попытаюсь понять. Завтра.
Странно, но рисунки перед опубликованием рисовал до смешного похожие на Ваши .
Хотя, возможно, это единственный наглядный способ отображения сути соединения по двойному неравенству.
34. Сергей (ildarovich) 06.04.10 02:11
Теперь о грустном...

Оценка трудоемкости запросов 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.
Но пока встроенных нарастающих итогов в запросах нет и компромиссом будут процедурные решения. :cry:

Кстати, похожий вопрос обсуждался здесь:
http://www.sql.ru/forum/actualthread.aspx?bid=1&tid=113703&pg=1
jafariuse; minikos; CheBurator; +3 Ответить 2
35. Сергей (Che) Коцюра (CheBurator) 06.04.10 02:34
А вот что, нельзя было 3-5 предложениями описать ИДЕЙНУЮ суть алгоритма?
36. Игорь Исхаков (Ish_2) 06.04.10 08:51
(35) Возможно, ты прав.
Но я побоялся рисовать что-то подобное рисунку в (32). Подумал что это не облегчит понимание , а еще больше запутает.
37. Александр Шишкин (Шёпот теней) 06.04.10 09:29
(36) ... за одного битого - двух не-битых дают ... вот ...
38. Игорь Исхаков (Ish_2) 06.04.10 09:35
После набора длинного ответа на (32) - ошибка сайта.
Регулярные глюки сайта просто бесят.
39. Александр Шишкин (Шёпот теней) 06.04.10 11:30
(38) ... ИС - бегая за "формой" однозначно теряет в "содержании" ... вот ...
40. Игорь Исхаков (Ish_2) 06.04.10 12:46
(32) Не согласен.
Строка в условии соединения
"НарРасход.МоментВремени > НарПриход.МоментВремени "
совершенно необходима.

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

Компромиссом следует считать следующий подход :
Строка
"НарРасход.МоментВремени > НарПриход.МоментВремени " из условий соединения убирается.
А в поля выборки добавляется строка
«Выбор Когда НарРасход.МоментВремени > НарПриход.МоментВремени
Тогда Истина
Иначе Ложь
Конец как ПризнакСвоевременности»

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

Поэтому предложение просто убрать строку
"НарРасход.МоментВремени > НарПриход.МоментВремени "
из условий соединения нельзя назвать верным.

А в файле СписаниеПоМетодуФИФО.dt применено ЛЕВОЕ СОЕДИНЕНИЕ.
С обработкой значений NULL.
41. Александр Рытов (Арчибальд) 06.04.10 12:51
(38) За одного бита дают 1/8 байта 8-)
42. Игорь Исхаков (Ish_2) 06.04.10 13:10
(34) Теперь о грустном :
К сожалению ,оценку трудоёмкости вычислений я забыл. Поэтому о верности приведенных формул мне судить трудно.
Но и без формул понятно , что количество вычислений в текущем алгоритме больше , чем при "процедурном подходе".

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

Но Ваш пост , как я понял, о другом . Из него вытекает :
Для исходных таблиц значений Приход и Расход можно привести такой кодинг с циклами ("процедурный подход") , реализующий метод ФИФО , который многократно
превзойдет текущий алгоритм с любым самым эффективным вычислением нарастающих итогов . При этом размер таблиц Приход и Расход может быть как угодно большим .
Так ?


43. Сергей (ildarovich) 06.04.10 14:37
(40) Да, правильно, если проверка и нужна, то только для вычислений "ПризнакСвоевременности", а не для отбора записей в соединяемой таблице. При этом индекс по МоментВремени не нужен.
А вот левое соединение и обработка NULL - это неправильно, так как если расход не сделан, то следующие "своевременные" расходы должны соединяться с приходами, пропущенными в паре с несвоевременными расходами.
44. Сергей (ildarovich) 06.04.10 14:44
(42) Да, так. Причем для Вашего "модельного" случая код занимает один - два десятка строк.
45. Игорь Исхаков (Ish_2) 06.04.10 16:20
А вот левое соединение и обработка NULL - это неправильно, так как если расход не сделан, то следующие "своевременные" расходы должны соединяться с приходами, пропущенными в паре с несвоевременными расходами.


Для каждой значения Номенклатуры из таблицы НарРасход мы строим движения по регистру партий.
Поэтому если N-расход по M-номенклатуре получился "красным" , то зачем нам последующие "своевременные" расходы N+1,N+2 и т.д. по M-номенклатуре ?
Совершенно очевидно , что они не имеют смысла .
Для М+1-номенклатуры , конечно, будет выстроена своя последовательность движений расходов. Как и для M+2,M+3 и т.д.

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

Тем более если в таблице НарРасход для М-номенклатуры имеются записи со значением поля КоличествоДо больше любого КоличествоПосле в таблице НарПриход эта запись при ВНУТРЕННЕМ СОЕДИНЕНИИ просто "пропадёт" в выходной таблице "без следов".
При ЛЕВОМ СОЕДИНЕНИИ мы достигаем того, что в выходной таблице гарантировано будут присутсвовать все регистраторы-расходы. И по полям признакам мы сможеи определить какое движение регистратор - неверное (или "красное").
46. Игорь Исхаков (Ish_2) 06.04.10 16:41
47. Сергей (ildarovich) 06.04.10 17:49
(45) Не буду занудой и соглашусь, так как речь идет о реакции на ошибку пользователя. А это, в общем-то, дело вкуса. Как в анекдоте про тараканов - неважно утонут они или подорвутся на минах :D
48. Игорь Исхаков (Ish_2) 06.04.10 18:03
(47) Ну и заканчивая , можно сказать :
т.к. в рамках рассматриваемой простейшей конфигурации "запросный" метод значительно уступит по быстродействию "процедурному подходу" (т.е. "вручную" просканировать две исходные таблицы Приход и Расход для получения движений),
то единственной , достойной внимания особенностью представленного алгоритма является перенос в трехзвенной системе( клиент-сервер приложений- сервер БД) всех вычислений на сервер БД.
49. Александр Орефков (orefkov) 07.04.10 09:23
Все в одном запросе это конечно хорошо, но пока больше походит на то, что 1С из инструментов дала только вилку, и для поедания супа приходиться изголятся и пытаться сложить ложку из кучи вилок. В нормальной БД получение нарастающих итогов легко делается процедурным методом на сервере - обходишь курсор и подбиваешь суммы.
50. Александр Рытов (Арчибальд) 07.04.10 09:54
(49) Хоть не палочки бамбуковые :o
51. vlad kan (truba) 07.04.10 10:13
52. Игорь Исхаков (Ish_2) 08.04.10 10:09
(49) Я так и не отгадал загадку :
Почему в языке запросов 1с не разрешен Update.
Понятно , что не стоит разрешать Update при обращении к таблицам БД.
Но почему не разрешен Update к временным таблицам хоть убей - не пойму.
53. Игорь Исхаков (Ish_2) 08.04.10 10:19
(51) Конечно, так. Но по ссылке в (34) нашел цитату Aleks2 на SQL.ru
Запомни:
1) Если у тебя есть возможность не пользоваться курсором - не пользуйся им.
2) Если у тебя НЕТ возможности не пользоваться курсором - ВСЕ РАВНО НЕ ПОЛЬЗУЙСЯ.
-------------
Запрос всегда быстрее курсора, единственное исключение: неправильный (неоптимальный) запрос.


В общем случае это ,конечно, неверно. Но уж больно симпатично.
54. Александр Орефков (orefkov) 09.04.10 12:39
(53)
Ну, опять же на нормальной БД нарастющие итоги на врем-таблицу можно накрутить и без курсора.
update vt_total
set @СуммаНачало = case when vt_total.НоваяСтрока = 0 then @СуммаКонец else vt_total.СуммаНачало
,@СуммаКонец = @СуммаНачало + vt_total.Оборот
,vt_total.СуммаНачало = @СуммаНачало
,vt_total.СуммаКонец = @СуммаКонец 
...Показать Скрыть
55. Игорь Исхаков (Ish_2) 09.04.10 15:20
(54) Ага,примерно так.
И получается , что наличие в языке запросов Update делает ненужными любые разговоры об эффективном вычислении нарастающих итогов , занимающего
львиную долю времени в текущем алгоритме.
56. Владимир (hogik) 09.04.10 17:52
(55)(54)(51)
Логотип темы - «Мы пишем запросы!».
Позволю себе высказаться не в тему.
Для простого и эффективного решения аналогичных задач не требуются:
1) Наличие в языке запросов Update.
2) Временные таблицы.
3) Процедурные методы на сервере.
4) Курсоры.
5) Всякие «левые» и «правые» соединения.
Да и сами запросы не требуются. ;-)
Печально, что движение по «столбовой дороги развития СУБД»(с) ведет в тупик. А «круглые колеса, на каких во всем мире принято ездить»(с) ускоряют это движение… :-(
57. Игорь Исхаков (Ish_2) 10.04.10 17:44
(56) Хм.. Владимир, Вы упорно отстаиваете свой экстравагантный взгляд на развитие СУБД с отрицанием языка запросов SQL . И ,как обычно, не приводите хотя бы внятного обозначения альтернативного подхода.
Впрочем , однажды Вы в своей теме привели текст кода а-ля Clipper Summer '87, обозначающий Ваш подход к решению такого рода задач и заставивший меня смахнуть слезу :

do while !eof()
.........
enddo

Т.е. сканирование таблицы и ручной кодинг.
Возврашаясь в 1987г , Вы отрицаете ту самую двадцатилетнюю "столбовую" дорогу :
-Утверждение стандарта SQL от 1992г.
-Развитие трехзвенной системы клиент-сервер приложений-сервер БД.

Оно конечно, Вам это никто не запретит. Но думаю , Вы найдете мало сторонников.
Если вдруг на каком -то этапе на "столбовой" дороге откажутся от языка запросов - я первый сниму перед Вами шляпу.
58. Владимир (hogik) 10.04.10 18:44
(57)
Игорь.
Я не отрицаю язык запросов в развитии СУБД. Я утверждаю, что для наших задач надо иметь ДВА способа (ЯМД) обработки данных. И в задачах типа «Нарастающие итоги» просматривать таблицы построчно в обычном цикле на стороне клиента. Это быстрее работает, не загружает сервер лишней работой, проще писать ««ручной кодинг»». Есть алгоритмы, где эффективней использовать язык запросов.
А в целом, наличие двух ЯМД позволяет проектировать схему БД не под средства манипулирования данными, а под предметную область. И отпадает необходимость в «трехзвенной» архитектуре, как средства преобразования одного ЯМД в другой.
59. rhtr Иванов (rhtr) 10.04.10 19:34
60. Игорь Исхаков (Ish_2) 10.04.10 20:10
(58) Истина всегда конкретна (с).
Соображения общего плана (58) меня мало в чем убеждают.
Разберемся конкретно .
Мы разбираем задачу вычисления нарастающих итогов в клиент-серверной архитектуре.
Цитататы :
"Для простого и эффетнаективного решения аналогичных задач не требуются:
1..5 . Да и сами запросы не требуются.."
"И в задачах типа «Нарастающие итоги» просматривать таблицы построчно в обычном цикле на стороне клиента. Это быстрее работает, не загружает сервер лишней работой, проще писать ««ручной кодинг»»."

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

1. БОЛЕЕ эффективно загрузить таблицу с сервера на клиента и далее на клиенте ручным кодингом просканировать таблицу в цикле (do while...skip...enddo).
2. МЕНЕЕ эффективно оставить таблицу на сервере и одной командой Update получить таблицу нарастающих итогов см (54)

Так ? Или я что-то напутал ?
61. Александр Медведев (anig99) 10.04.10 22:21
Кстати... С одной стороны, обработка на клиенте удобнее... С другой стороны это противоречит концепции тонкого клиента и web интерфейсов. Узкие или загруженные каналы требуют уменьшение объема передаваемой информации. Это раз. Во-вторых, клиентские машины могут быть маломощными не только из-за экономии средств. Нетбуки, наладонники и т.д. имеют возможность работы с 1с, но не могут переваривать огромные объемы информации. Поэтому нужно идти по пути переноса обработки данных с клиентских компьютеров на сервера в любом виде: будь то запрос, или инструкция к компилятору.
62. Владимир (hogik) 10.04.10 22:44
(60)
Игорь.
1) Для обработки таблицы навигационным способом не требуется загружать таблицу с сервера на клиент. Выполняется чтение по одной записи. Вычисление и накопление нарастающего итога на клиенте для каждой строки в переменной оперативной памяти. Выводится в отчет строка вместе с вычисленным итогом. Т.е. выполняется чтений столько раз, сколько строк в таблице (обозначим - N).
2) На сервере же формируется рабочая таблица (в простейшем случае N чтений и N записей). Далее читаем каждую строку рабочей таблицы (N чтений), вычисляем нарастающий итог и записываем его в каждую строку (N обновлений). Далее передаём все строки рабочей таблицы клиенту (N чтений). Итого 5*N чтений/записей.
По сети, в обоих способах, предаётся одинаковое количество строк.
63. Игорь Исхаков (Ish_2) 11.04.10 11:31
(62) Владимир.
Чтение (62) вызвало у меня столько вопросов, что я просто оробел что-то спрашивать.
Допускаю, что моего разумения просто не хватает , чтобы осилить (62).
64. Владимир (hogik) 11.04.10 13:56
(63)
Игорь.
Жалко, что Вы принципиально не используете «смайлы».
Сообщение #63 – это шутка?
Или намек на мою дурость?
65. Игорь Исхаков (Ish_2) 11.04.10 14:01
66. rhtr Иванов (rhtr) 13.04.10 03:28
Этап III .Особенно - "предварительно сравнить с существующими движениями в регистре и записать только "изменения". А на этом месте можно поподробнее.Будет очень хорошо если дополните конфу.Вам же как Гению Партий!!!.
Пасиба :)
67. Игорь Исхаков (Ish_2) 13.04.10 08:11
(66) Место Гения давно и прочно занято.
Вариант:
1. Мы получили запросом ТаблицуДвижений.
2. Делаем Полное Соединение с движениями из регистра партий.
3. Оставляем в таблице , полученной в п.2, только расхождения , т.е. получаем ТаблицуРасхождений.
4. Затем с помощью запроса
"Выбрать Различные Регистратор ИЗ ТаблицаРасхождений" получаем таблицу -столбец
с документами , которые нужно перепровести.
5. Сканируя таблицу, полученную в п.4, для каждого документа- регистратора выбираем нужные движения из ТаблицыДвижений и записываем их в регистр.
68. Александр Рытов (Арчибальд) 13.04.10 08:16
(67)
Место Гения давно и прочно занято.
Кем :o
69. Игорь Исхаков (Ish_2) 13.04.10 08:23
(68) Гений 1с , в миру Осипов Сергей.
Об изгнании его с ИС я писал в теме Life "Тошнота как реакция на свободу".
70. Александр Рытов (Арчибальд) 13.04.10 08:27
(69) Фуу... А я-то понял, что его место на ИС кто-то занял :D
71. Eugeneer (Eugeneer) 13.04.10 08:55
Это просто нереальная жесть использовать для списания получение данных за период.
72. Игорь Исхаков (Ish_2) 13.04.10 09:09
(71) Пока нереально.
Если в языке запросов 1с появится Update , Declare , Create Table (для временных таблиц), то представленный алгоритм , на мой взгляд, для больших таблиц выиграет у любого другого.
Это предсположение основывается на том , что
вся тяжесть вычислений в алгоритме ложится на вычисление нарастающих итогов.
С помощью команды Update нарастающие итоги считаются очень быстро.
73. Павел Кучеренко (NCCSOFT) 09.08.10 08:02
Два года назад я тоже самое пытался сделать для 7.7 :D на языке MS SQL, и там есть Update, но его скорость меня не устроила, так как базу проводил за 3 года (FIFO), потом выгружал в динамические таблицы в SQL - тоже тормоза... потом плюнул на все технологии выгрузил данные в txt-файл (10 мин), на Дельфи конвертирую в свой формат (2 мин), записываю (чтобы при следующих запусках не конвертировать по-новой), и делаю расчет по FIFO. База за 3 года проводится за 1 секунду (ОДНУ СЕКУНДУ). Вот и все. Разработка тут: Разработка тут Скоро сделаю внешнюю обработку для 8.1 - выгрузка данных, чтобы можно было проверять 1С - правильно ли она по FIFO считает.
Шёпот теней; +1 Ответить 1
74. Александр Шишкин (Шёпот теней) 09.08.10 08:12
(69) ... а я не нашЁл у Вас этой статьи ... нельзя ли её где-нибудь и как-нибудь по-читать-то ... ? ... или дайте пожалуйств ссылку НЕумелым ... вот ...
75. Андрей Селезнев (seleand) 09.08.10 09:10
(72) согласен с Маньяком. Решение задачи в лоб - это просто жесть.
Вы ждете возможностей языка, которые позволят втиснуть ваши огромные вычисления в рамки приличий по быстродействию? А решение лежит в другой стороне. Смоьтреть надо в сторону изменения структуры регистров, которая позволит анализировать только то, что реально нужно...
76. Игорь Исхаков (Ish_2) 11.08.10 16:33
(73) В солнечной Анапе , чтобы выйти в интернет на почте нужно предьявить паспорт.
Попросив уже сидевшего за компьютером человека посмотреть ИС , увидел комментарий и побежал за паспортом. Жара , скучно, на море ни ногой - делать нечего.
Как обычно , хмыкну там где восторгается Шепот.
Выгрузки - загрузки в txt, потом в свой формат и т.д, чтобы потом "ЗА ОДНУ СЕКУНДУ" !
- это для кого текст ? Для специалистов ? Если - да , то для каких ?

В статье предлагается общий алгоритм списания по методу ФИФО.
Который может быть реализован как на платформе 1с , так и на другой платформе средствами только TSQL. В последнем случае эффективность реализации алгоритма многократно выше.
( с помощью Update нарастающие итоги считаются быстрее)
77. Игорь Исхаков (Ish_2) 11.08.10 16:38
(75) Маньяк так Маньяк. Жесть так жесть. Это понятно.
Остальной текст "жестьтоко" загадочен.
78. Михаил Ражиков (tango) 11.08.10 16:51
79. Павел Кучеренко (NCCSOFT) 11.08.10 21:12
(76) Привет отдыхающим!! ;-)

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

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

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

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

(78) :-)
80. Игорь Исхаков (Ish_2) 16.08.10 11:45
(78) Вот и ты , Миша, не любишь иша ... Как эта тетка на почте :

- Мужчина в желтых трусах ! Я же вам сказала : отойдите от компьютера.
А трусы у меня , Миша, между прочим адидасовские - яркие ,оранжевые.
Адидас, правда, цыганский и кореша говорят , что похож я в них не на голландца ,а на бандеровца. Но они мне нравятся и я их ношу...
- Пустите . Я же в прошлый раз Вам паспорт показывал.
- Мужчина мне нужно внести ваши данные . Вы это понимаете ?

Крыть было нечем и я решился .. перегнувшись через стойку доверительно сообщил:
- Девушка , а трусы на мне не желтые , а померанчевые ! Бачишь ?

Пока она с трудом подбирала ответ я понял , что не попал. Мда... Здесь вам не инфостарт , "штучки-дрючки" не проходят и не дожидаясь ответа ,я поперся за паспортом.
81. Александр Рытов (Арчибальд) 16.08.10 11:49
(80) Таки тетка или девушка?
82. Игорь Исхаков (Ish_2) 18.08.10 10:07
(81) Кавалер к тетке обращается - "девушка!". Не знал ?
83. Александр Рытов (Арчибальд) 18.08.10 10:25
(82) Не знал. Сам пользуюсь терминами "сударыня" или "миледи" :oops:
84. Юрий Строжевский (y-str) 25.08.11 10:05
Добрый день!

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

---
С уважением,
Юрий Строжевский
85. ambal49 ambal49 (ambal49) 19.10.11 10:51
Вопрос, а если приходная накладная сделана со знаком минус? получается она выпадет из последнего запроса а по идее должна скорректировать предыдущие распределения, либо надо все приходы со знаком минус переквалифицировать в расходы со знаком плюс :). Что тоже неправильно :)
86. Игорь Исхаков (Ish_2) 19.10.11 11:07
(85) Приходы с отрицательной суммой в статье не рассматривается.
1. Или нужно дополнительно обрабатывать таблицу приходов , что избавиться от "минусов".
2. Или алгоритм по Фифо должен быть существенно усложнен.
87. vers139 (vers139) 09.11.11 18:57
В СКД в вычисляемых полях появилось возможность использовать ВЫЧИСЛИТЬВЫРАЖЕНИЕ(). Лично у меня получилось поделить долг между накладными. Берём остатки по регистру взаиморасчёты, левое соединение на регистраторы регистра взаиморасчёты, сортировка в порядке убывания даты регистратора, группируем по клиенту и договору. + вычисляемое поле. В нём я использовал выражение:
Выбор 
Когда ВычислитьВыражение("Сумма(СуммаДок)", , , "Первая", "Текущая") < Долг 
тогда СуммаДок 
Когда ВычислитьВыражение("Сумма(СуммаДок)", , , "Первая", "Текущая") - Долг < СуммаДок 
тогда СуммаДок - (ВычислитьВыражение("Сумма(СуммаДок)", , , "Первая", "Текущая") - Долг) 
Иначе 0 
конец
...Показать Скрыть

Всё почти хорошо. Однако при использовании дополнительной группировки по степени просроченности долга (долг не просрочен, долг просрочен не более на 5 дней, долг просрочен на срок 5-30 дней и т.д.) вычисляемое поле вычисляется в пределах отдельной группировке по степени просроченности долга, а не в пределах клиента. Подозреваю, что надо "побаловаться" с параметрами ВычислитьВыражение(), но пока не додумал. Может у кого-то получилось понять суть этих параметров. Прошу поделиться идеями, ибо у меня уже мозг закипает.
88. Игорь Исхаков (Ish_2) 09.11.11 19:12
(87) Вы описали задачу НЕ ФИФО , рассматриваемую в этой теме, а ПросроченныеДолги.
В голову даже не приходило решать эту с помощью выражений СКД.
Впрочем, я еще даже не установил 14 релиз платформы.
89. vers139 (vers139) 09.11.11 20:45
(88) Ish_2, простите просматривал все темы по Накопленным итогам. В этой самые последние сообщения. Тем более, что дебиторка использует ЛИФО. Так что принцип, думаю, аналогичный.
90. Dmitry Smirnov (S_DS) 23.11.11 09:26
91. Игорь Исхаков (Ish_2) 23.11.11 10:09
(90) Как общее соображение принимается к сведению.
На мой вкус, только не хватает вывода или утверждения.
92. Сергей Старых (tormozit) 24.11.11 22:01
Мне другая интересная задача недавно попалась -
Получить таблицу минимальных дозакупок на каждый день месяца для того чтобы вывести в ноль все ежедневные отрицательные остатки задним числом. Пример
Дата Остаток ! Дозакупка НовыйОстаток
01 -3 3 0
02 4 0 7
03 -1 0 6
04 -4 0 2
05 -7 5 0
06 2 0 7

Вот нужно получить колонку Дозакупка.
Естественно хотелось бы решить ее запросом.
93. Игорь Исхаков (Ish_2) 25.11.11 08:38
(92) Мммм.. неплохо. Создай тему с решением.
Я сыграю "вторым номером", т.е. оппонентом.

P.S. На всякий случай : эффективного решения в данный момент у меня нет.
94. Игорь Исхаков (Ish_2) 05.12.11 11:09
(92) Впрочем, возвращаясь к твоей задаче, замечу , что такая постановка малопригодна для практического применения. Оформляя доп.приходы по итоговым остаткам на конец дня , мы не учитываем реальную ситуацию,при которой отрицательные остатки могут возникать несколько раз в течение дня .
Конечно , можно решать и твою задачу как некий упрощенный частный случай.
Но для общего случая ( интересен , на мой взгляд именно он) правильно формулировать следующим образом :

Проверить и найти все отрицательные остатки за период возникшие после момента проведения любого расходного документа. Реализовать одним запросом.
Другими словами , на входе имеем таблицы :
НачОстаткиНаНачалоПериода
ВсеПриходыЗаПериод,
ВсеРасходыЗаПериод.

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

Таким должен быть , на мой взгляд , подход к решения такой задачи.
95. Даниил Матвеев (cargobird) 14.10.16 15:09
Скачал, запускаю на 8.3.9 в Конфигураторе.
Загружает.
Задает вопрос о конвертации.
И после подтверждения сразу в дамп.
Разучилась, видимо, превращать базы на 8.1 в 8.2.
Пришлось искать 8.2 для конвертации и хорошо, что нашел, сконвертировал.
Но оказалось что все еще проще. В окне настройки инф.базы надо поменять с 8.3 на 8.2)
Или пятница, или уже очевидные вещи вылетают из головы)
96. Сергей (Che) Коцюра (CheBurator) 15.10.16 15:08
осциллирующую функцию остатков разложить на сумму монотонно убывающих функций. каждая входящая партия остатков может только убывать. соответсвенно если по партии есть отрицательный остаток - нужно дозакупить этот отрицательный остаток. найти дату по минусовому хвосту - плвеое дело.
97. Игорь Исхаков (Ish_2) 06.11.16 09:43
(96) CheBurator,
Привет , Чебур. Сколько лет прошло ?
Ты написал что-то умное и серьезное.
После школы, стало быть , еще не забыл про "монотонно убывающие функции".
А я забыл . Но был рад тебя почитать !
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа