gifts2017

Использование нарастающих итогов в партионном учете и не только

Опубликовал Юрий Строжевский (y-str) в раздел Программирование - Теория программирования

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

Фактически в данной статье рассматриваются альтернативы запросам, приведенным в статьях http://infostart.ru/public/61295/ и http://infostart.ru/public/68225/.

Полный текст статьи можно также найти на http://nashe1c.ru/materials-view.jsp?id=383.

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

Наименование Файл Версия Размер Кол. Скачив.
Использование запросов с нарастающим итогом.doc
.doc 129,50Kb
09.07.13
65
.doc 129,50Kb 65 Скачать

См. также

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

Комментарии

1. Игорь Исхаков (Ish_2) 25.08.11 10:18
За рекламу - спасибо.
Пробежал мельком . Пока замечание :
в статье никак не отмечено : использование нарастающих итогов "в лоб"
(т.е. использвание содинения по неравенству в запросе) для больших таблиц приведет к "падению" всего алгоритма.

По оформлению : лучше оформить статью на ИС как полагается , а не предлагать файл со статьей к скачиванию.
2. Сергей Ожерельев (Поручик) 25.08.11 10:43
Мне тоже лень скачивать файло
3. Юрий Строжевский (y-str) 25.08.11 10:49
Формально эта статья опубликована на http://www.nashe1c.ru/materials-view.jsp?id=383 (если кому "лень качать файло" :) ).
Позже еще покопаюсь здесь - не нашел сразу как вставлять в статью картинки при публикации на этом сайте.

To Ish_2: аргументируйте, пожалуйста, как именно может повлиять размер таблиц на работу этого алгоритма?
4. Игорь Исхаков (Ish_2) 25.08.11 10:57
Пока по мелочи . Что бросилась в глаза .
В объяснении текста запроса
SELECT
 tab1.Номенклатура,
 tab1.Партия,
 ( SUM( ISNULL( tab2.КоличествоОстаток, 0 ) ) + MAX( tab1.КоличествоОстаток ) ) AS НарастающийИтог ...

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

Ошибка. То есть использование функции "МАХ" в данном случае не является необходимым
Правильно :
SELECT
 tab1.Номенклатура,
 tab1.Партия,
  SUM( ISNULL( tab2.КоличествоОстаток, 0 ) ) +  tab1.КоличествоОстаток  AS НарастающийИтог ...
5. Юрий Строжевский (y-str) 25.08.11 10:59
На всякий случай уточню, что представленный в статье вид запроса как-раз и позволяет сильно ограничить количество записей в результирующем наборе. Сам по себе запрос может быть транслирован в SQL без изменений и, тем самым, позволяет работать с большими начальными таблицами, получая только необходимые выходные данные (без дополнительных обработок в последующих запросах или в текстах модулей).
6. Юрий Строжевский (y-str) 25.08.11 11:02
Ish_2 пишет:

Пока по мелочи . Что бросилась в глаза .

В объяснении текста запроса



О как :) А что, так будет работать, без MAX/MIN? Проверяли? :)
7. Игорь Исхаков (Ish_2) 25.08.11 11:14
(6) В конфигурации прикрепленной к теме "ФИФО для любопытных" http://infostart.ru/public/68225/
использован именно такой запрос без МАХ.
Почему для больших таблиц соединение по неравенству работает оч. медленно можно прочитать в теме "Подведем итоги.Нарастающме" .
Можно убедиться в этом самостятельно : создайте таблицу tab1 с количеством записей 1 000 000 .
Запустите Ваш запрос - соединение по неравенству tab1 "сама с собой" засеките время. И всё поймете... назавтра.
8. Алексей Константинов (alexk-is) 25.08.11 11:16
(0) :o

Так писать нельзя. Это же деление на 0
END * MAX( ISNULL( tab1.СуммаОстаток, 0 ) ) / MAX( ISNULL( tab1.КоличествоОстаток, 0 )
Луна5; +1 Ответить
9. Юрий Строжевский (y-str) 25.08.11 11:24
(7)В упомянутой конфигурации используется конструкция вида:

SELECT
Поле1,
СУММА( Поле2 ) + Поле1
FROM
GROUP BY Поле1

Здесь да, наличие MAX/MIN не нужно. Но в моем запросе используется поле, по которому отсутствует группировка. Так что это поле ОБЯЗАТЕЛЬНО должно включаться в выражения запроса в виде функции языка запросов. Насчет скорости исполнения - я проведу такие испытания, но еще раз скажу, что суммирование или простое сравнение по индексу для SQL выполняется очень быстро. Размер таблиц в миллион записей никак не влияет на скорость исполнения. Возможно здесь будет влиять сама 1С, но это уже другой вопрос.
10. Юрий Строжевский (y-str) 25.08.11 11:24
alexk-is пишет:

(0)



Так писать нельзя. Это же деление на 0


О, спасибо за комментарий! Учту :)
11. Юрий Строжевский (y-str) 25.08.11 11:38
(10) Исправил в статье на nashe1c, послал на модерацию. Сейчас и здесь добавлю еще один "CASE" в запрос.
Еще раз спасибо за указание на ошибку!
12. Игорь Исхаков (Ish_2) 25.08.11 11:58
(9) Мда.. Зачем спорить ? Вы попробуйте.
Вот Ваш вариант с "МАХ" :
SELECT
 tab1.Номенклатура,
 tab1.Партия,
 ( SUM( ISNULL( tab2.КоличествоОстаток, 0 ) ) + MAX( tab1.КоличествоОстаток ) ) AS НарастающийИтог
FROM РегистрНакопления.ОстаткиНоменклатуры.Остатки AS tab1
LEFT JOIN РегистрНакопления.ОстаткиНоменклатуры.Остатки AS tab2
ON ( tab1.Номенклатура = tab2.Номенклатура ) AND ( tab1.Партия > tab2.Партия )
GROUP BY tab1.Номенклатура, tab1.Партия;
...Показать Скрыть

Вот мой без "МАХ":
SELECT
 tab1.Номенклатура,
 tab1.Партия,
 SUM( ISNULL( tab2.КоличествоОстаток, 0 ) ) +  tab1.КоличествоОстаток   AS НарастающийИтог
FROM РегистрНакопления.ОстаткиНоменклатуры.Остатки AS tab1
LEFT JOIN РегистрНакопления.ОстаткиНоменклатуры.Остатки AS tab2
ON ( tab1.Номенклатура = tab2.Номенклатура ) AND ( tab1.Партия > tab2.Партия )
GROUP BY tab1.Номенклатура, tab1.Партия;
...Показать Скрыть


Ну как ? Получилось ?
13. Юрий Строжевский (y-str) 25.08.11 12:03
(12) Конечно НЕТ, не получилось! :) Не позорьтесь, почитайте документацию, попробуйте сами подобные запросы. Это общее правило SQL запросов и оно незыблемо :)
14. Игорь Исхаков (Ish_2) 25.08.11 12:07
(13) Случай тяжелый , запущенный.
Жаль , что обсуждение так печально закончилось.
15. Юрий Строжевский (y-str) 25.08.11 12:13
(14) Нет, я правда попробывал :) Честно-честно! :) 1С мне написало "Поле не входит в группу "tab1.КоличествоОстаток"". На всякий случай: платформа 8.2.14.528
16. Юрий Строжевский (y-str) 25.08.11 12:46
(14) Я тут подумал: может Вы просто перепутали конструкции запроса? То есть существует такая конструкция как "ИТОГИ Поле1, СУММА(Поле2) ПО Поле1". Вот там в самом тексте запроса функции употреблять не надо - они применяются только в итогах. На всякий случай: по-английски это пишется как "TOTALS Поле1, SUM(Поле2) BY Поле1".
17. Игорь Исхаков (Ish_2) 25.08.11 12:46
(15) Платформа 8.2.13.205.
Проверена в работе конфигурация http://infostart.ru/public/68225/ . Содержит запрос:
               |ВЫБРАТЬ
               |	Приход.Период,
               |	Приход.МоментВремени,
               |	Приход.Партия,
               |	Приход.Номенклатура,
               |	Приход.Количество,
               |	Приход.Сумма,
//
               |	СУММА(Приход1.Количество) - Приход.Количество КАК КоличествоДо, // Внимание ! Приход.КОличество без МАХ
//
               |	СУММА(Приход1.Количество) КАК КоличествоПосле
               |ПОМЕСТИТЬ НарПриход
               |ИЗ
               |	Приход КАК Приход
               |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Приход КАК Приход1
               |		ПО Приход.Номенклатура = Приход1.Номенклатура
               |			И Приход.МоментВремени >= Приход1.МоментВремени
               |
               |СГРУППИРОВАТЬ ПО
               |	Приход.Партия,
               |	Приход.Период,
               |	Приход.МоментВремени,
               |	Приход.Номенклатура,
               |	Приход.Количество,
               |	Приход.Сумма
               |;
...Показать Скрыть


Ищите ошибку у себя.
18. Александр Медведев (anig99) 25.08.11 12:47
Я хотел бы внимание обратить на другую ошибку. В запросе оперируют данными виртуальной таблицы Остатки, что методологически неверно, т.к. остатки - это УЖЕ результат расчета с нарастающими итогами. И использование остатков в запросе с нарастающими итогами чрезвычайно ограничено.

Пока я не вижу новизну в статье, а только ошибку.

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


1
2 > 1
3 > 1 + 2
4 > 1 + 2 + 3
5 > 1 + 2 + 3 + 4


в итоге получаем таблицу

1
2 1
3 1
3 2
4 1
4 2
4 3
5 1
5 2
5 3
5 4

Вместо 5 изначальных записей, получили 11. И прогрессия эта даже не геометрическая.
ildarovich; +1 Ответить 4
19. Юрий Строжевский (y-str) 25.08.11 12:49
(17) Вот! А теперь просто уберите строчку "Приход.Количество" из блока "СГРУППИРОВАТЬ ПО" :) Еще раз: у меня используется поле, НЕ входящее в группировку.
20. Алексей Константинов (alexk-is) 25.08.11 12:49
(17) :)

|СГРУППИРОВАТЬ ПО
| Приход.Партия,
| Приход.Период,
| Приход.МоментВремени,
| Приход.Номенклатура,
| Приход.Количество,
| Приход.Сумма


Вот где собака порылась :)
22. Юрий Строжевский (y-str) 25.08.11 12:53
(18) Про "неправильное методологическое поведение" я комментарий опущу. А вот насчет "геометрической прогрессии": в запросе нет объединения "все со всеми", соединение с "правой" таблице нужно только для вычисления функции суммы по остаткам.
23. Игорь Исхаков (Ish_2) 25.08.11 12:54
(19) ,(20) Правильно ! Пост (12) неверен !
24. Юрий Строжевский (y-str) 25.08.11 12:55
(21) Статью я читал, спасибо за развернутый материал!
25. Юрий Строжевский (y-str) 25.08.11 12:57
(23) Супер! Очень рад, и надеюсь на дальнейшее продотворное сотрудничество! :)
26. Игорь Исхаков (Ish_2) 25.08.11 12:59
27. Александр Медведев (anig99) 25.08.11 12:59
(22) Сумма остатков! Это фигня получится.
Нач.ост = 0
Приход 10 Остаток = 10
Приход 11 Остаток = 21
Приход 5 Остаток = 26
Расход 1 Остаток = 25


Теперь нарастающий итог для последней строки с суммой остатков будет.... пырым-пым-пым ---- 10 + 21 + 26 = 57... фигня какая-то.
28. Александр Медведев (anig99) 25.08.11 13:03
(22) а про объединение...Вот именно, что ВЫЧИСЛЕНИЕ. Для каждой из 5 записей будет производится свой расчет суммы с увеличением числа слагаемых.
т.е. будет не 1+2+3+4+5 = 5 действий сложений, как если это делать с помощью цикла в коде, а будет 11 действий сложений. И число операций сложений будет расти ОЧЕНЬ быстро.
29. Юрий Строжевский (y-str) 25.08.11 13:04
(27) Эээть, вот здесь опять подробнее: движения имеют и "приход", и "уход". Так что расход добавляем с отрицательным знаком :)
30. Алексей Константинов (alexk-is) 25.08.11 13:06
(27) Это всё правильно. С остатками всё впорядке.
31. Юрий Строжевский (y-str) 25.08.11 13:07
(28) Скажем так: подсчет суммы по любому числовому полю любой SQL таблицы с помощью запроса и функции SUM() вычисляется в разы быстрее, чем с помощью перебора всех строк и дальнейшего подсчета суммы с помощью любых алгоритмов. Я придерживаюсь этого мнения.
32. Александр Медведев (anig99) 25.08.11 13:08
(29) в регистре накопления есть Вид движения Приход и Расход. Знак при этом не меняется. Это в запросе можно получить уже Приход = Количество, а Расход = Количество*-1 или в две отдельные колонки. Знак тут не принципиален. Главное невразумительность сложения ОСТАТКОВ.
33. Юрий Строжевский (y-str) 25.08.11 13:11
(32) Для меня понятие "остаток" представляет собой разность между приходом и расходом. Всегда считал это общепринятым :)
34. Алексей Константинов (alexk-is) 25.08.11 13:14
(32) Тут хитрость методологии.
Складываются остатки не по операциям движений по регистрам, а остатки по партиям. Т.е. для списания нужно набрать пул списываемых партий и, собственно, всё.
Простая задачка. Не нужно усложнять.

См. (18)
Пока я не вижу новизну в статье
35. Юрий Строжевский (y-str) 25.08.11 13:18
(34) Конечно, ничего сложного! Просто мне было нужно, чтобы все вычислялось в рамках одного запроса, а не 7-ми как в http://infostart.ru/public/61295/. Я долго копался в Интернете, думал, что кто-то ведь наверняка должен был до этого додуматься - не нашел. Если есть ссылки на другие варианты решения задач, описанных в моей статье - буду очень благодарен!
36. Александр Медведев (anig99) 25.08.11 13:22
(31) Вопрос в том, что sum() будет вызываться столько раз, сколько записей в таблице. И каждый раз ему для расчетов будет передаваться такое число все большее число записей. В отличие от этого подхода, в цикле можно хранить предыдущий итог и прибавлять уже к нему (в sql это тоже можно организовать, но речь идет о запросе 1с, которые не умеет делать такого). В результате наступит такой момент, когда время выполнения Sum() с n записей будет выполнятся дольше, чем сложение двух цифр ПромежуточныйИтог + ТекущееЧисло в очередной итерации цикла. Это одна сторона. Другая сторона, что вообще время выполнения запроса 1с СУЩЕСТВЕННО увеличится. Проблема такого подхода в запросе, что вычисления для каждой записи каждый раз выполняеются ЗАНОВО с возрастающей нагрузкой на выч.ресурсы. В коде же нагрузка постоянна (ну кроме, увеличения объема памяти под хранения итогов).
Запрос "в лоб" выигрывает на маленьких объемах данных, цикл на больших. Но они оба проигрывают оптимизированному алгоритму запроса 1с или прямому запросу sql с организацией цикла прямо в запросе.
37. Александр Медведев (anig99) 25.08.11 13:27
(34) не понимаю, какое практическое значение информации о остатке партии + сумма всех остатков партии до него?
38. Юрий Строжевский (y-str) 25.08.11 13:29
(36) Не согласен! Использование "курсоров" вместо функций языка запросов - основная проблема производительности. Кто-то здесь уже делал тестовую базу под нарастающие итоги и проверял скорость работы запросов. Я поищу кто это был и постараюсь представить документальные доказательства.
39. Алексей Константинов (alexk-is) 25.08.11 13:32
(37) Посчитать сколько ещё положить в ведерко, пока ведерко не наполнится :)
40. Юрий Строжевский (y-str) 25.08.11 13:33
(37) Это, собственно, нарастающий итог остатка :) На определенном значении он превысит необходимое количество для списания и искомый список партий для списания будет готов.
41. Александр Медведев (anig99) 25.08.11 13:33
(35) решение "в лоб" опубликовано на мисте уже давно. Я ещё повторю, ничего нового, кроме непонятного практического значения остаток по партии + сумма остатков партий до него. Хотя нет. Понял. Новизны нет. Всё тот же запрос в "лоб"

7 запросов нужно для оптимизации расчетов.
42. Юрий Строжевский (y-str) 25.08.11 13:36
(41) А можно ссылку на "решение в лоб" на мисте?
43. Юрий Строжевский (y-str) 25.08.11 14:34
Приведу преимущества приведенного в моей статье подхода:
1) Использование только одного запроса для получения полного списка партий для списания для всего перечня номенклатуры;
2) Относительная простота применяемого запроса для понимания;
3) Применение функций языка запросов для ускорения обработки вместо прямого перебора в коде;
4) Возможность дальнейшей оптимизации использования данного запроса;
45. Александр Медведев (anig99) 25.08.11 14:51
(43) вот бы если полный код процедуры списания партий на замену штатному...и замеры производительности на больших объемах.
46. Алексей Константинов (alexk-is) 25.08.11 14:58
+45 ...по всем документам движения за месяц. :)
47. Юрий Строжевский (y-str) 25.08.11 15:06
(45)(46) Насчет "полный код процедуры списания на замену штатному":
1) Выполняем запрос, получаем все реквизиты для формирования движений списания (период, вид движений, номенклатура, партия, количество, сумма);
2) Загружаем в реквизит объекта документа "Движения" результат выполнения запроса;
3) Записываем "Движения";

Провести полноценный тест запроса не имею возможности. Но чисто теоретически он должен выполнятся крайне быстро и эффективно. Я верю в него :)
48. Александр Медведев (anig99) 25.08.11 15:15
(47)
1) для одного документа или всех сразу?

на одном документе разница будет незаметна, т.к. больше времени уходит на запись, а не чтение.
49. Юрий Строжевский (y-str) 25.08.11 15:20
(44)На мой взгляд приведенный "запрос в лоб на мисте" выглядит неоптимальным: применяется вложенный запрос по периодом (получается список неповторяющихся периодов), потом соединяется с полным списком периодов (не уникальный список периодов), а потом еще и группируется вновь по периодам, подсчитывая сумму.

Более логичным было бы использование такого запроса:

SELECT
tab1.Период КАК Время,
SUM( tab2.СуммаОборот ) КАК Сумма
FROM РегистрНакопления.ПродажиПоДисконтнымКартам.Обороты(, , Регистратор, ДисконтнаяКарта = &Ссылка) AS tab1
LEFT JOIN РегистрНакопления.ПродажиПоДисконтнымКартам.Обороты(, , Регистратор, ДисконтнаяКарта = &Ссылка) AS tab2
ON tab1.Период >= tab2.Период
GROUP BY tab1.Период
50. Юрий Строжевский (y-str) 25.08.11 15:23
(48) Можно сделать и для всех документов сразу: в качестве "таблицы ограничений" для моего запроса можно использовать таблицу с полями "регистратор + номенклатура + количество списания" и в самом запросе просто добавить еще одну группировку по регистратору. Вот и все :)
51. Александр Медведев (anig99) 25.08.11 15:39
(49) это просто подход к проблеме - простое соединение по условию ">="

и вообще вложенные запросы признаны самой 1с неэффективными. Нужно использовать пакетные запросы. Кстати, формально, те 7 запросов, объединенные в качестве пакетных, являются 1 запросом.
52. Юрий Строжевский (y-str) 25.08.11 15:52
(51) На мисте используется точно такое же соединение по условию ">=" :) В моем варианте запроса исправлены недостатки запроса с мисты.
Еще раз по запросу на мисте:
1) В первом вложенном запросе выбирается список уникальных периодов;
2) Затем во втором вложенном запросе выбирается полный список периодов () вместе с их суммами оборотов;
3) Затем эти два подзапроса соединяются: получается что весь список уникальных периодов соединяется со списком неуникальных периодов;
4) Затем происходит группировка по периодом, то есть опять происходит процедура формирования списка уникальных периодов;

Очевидно, что запрос на мисте не оптимален.

Насчет "7 запросов, объединенных в качестве пакетных": у меня запрос только один :) Судя по текстовому алгоритму из упоминаемой статьи этот алгоритм может быть разбит МИНИМУМ на 3 подзапроса. Еще раз - у меня эта задача решена в один запрос, понятный и ясный для понимания.
53. Юрий Строжевский (y-str) 25.08.11 16:14
(51) А вообще-то мой запрос еще можно оптимизировать: если "РегистрНакопления.ПродажиПоДисконтнымКартам" является только оборотным регистром, то можно вместо виртуальной таблицы оборотов и детализации периодов до регистратора использовать просто полный список движений по регистру. Получилось бы еще быстрее и понятнее.

Вот как-то так:

SELECT
tab1.Период КАК Время,
SUM( tab2.СуммаОборот ) КАК Сумма
FROM РегистрНакопления.ПродажиПоДисконтнымКартам AS tab1
LEFT JOIN РегистрНакопления.ПродажиПоДисконтнымКартам AS tab2
ON tab1.Период >= tab2.Период
WHERE (tab1.ДисконтнаяКарта = &Ссылка) AND (tab2.ДисконтнаяКарта = &Ссылка)
GROUP BY tab1.Период
54. Сергей (ildarovich) 25.08.11 16:19
Если автор более точно сформулирует решаемую им задачу, станет понятно, что утверждение
Фактически в данной статье рассматриваются альтернативы запросам, приведенным в статьях http://infostart.ru/public/61295/ и http://infostart.ru/public/68225/.

ошибочно.
Как я понял, автор предлагает вместо получения запросом таблицы партий из регистра накопления "остатки партий товаров" и последующего построения в цикле таблицы списания партий, решать задачу в запросе. Не вижу в этом проблемы. Думаю, что в большинстве решений, поддерживающих партионный учет, так и сделано.
Чаще всего таблице ненулевых остатков партий (по одной номенклатуре) - одна - две строки, что там оптимизировать?
55. Юрий Строжевский (y-str) 25.08.11 16:23
(54) В моей статье в качестве последнего запроса приведено прямое решение для задачи из http://infostart.ru/public/61295/. Приведенное мною решение более компактно и понятно. Использования запросов такого вида где-либо еще (в типов ли конфигурациях или просто на просторах Интернета) я не нашел - буду благодарен за любую ссылку на подобный материал!
56. Игорь Исхаков (Ish_2) 25.08.11 17:02
(55) Вышел с "больничного".
Реализация метода ФИФО предполагает получение движений для всех документов расхода за период.
Именно в такой постановке рещается задача в "ФИФо для любопытных".

В Вашей постановке задачи априори мы имеем таблицу, определяющую количество списания , с колонками :
• Столбец «Номенклатура»;
• Столбец «Количество» - общее количество, которое должно быть списано со всех партий для данной номенклатурной единицы;
Т.е. здесь мы имеем суммарное по всем документам расхода количество для списания - это серьезное упрощение
задачи. Вычислить движения по партиям нужно ведь в разрезе каждого документа расхода .

На практике при реализации метода ФИФО на входе имеем не таблицу с итогами количества по списанию ,
а таблицу с колонками
• Столбец «ДокументРасходнаяНакладная»;
• Столбец «Номенклатура»;
• Столбец «Количество» - количество списания по накладной

А это значит на выходе мы должны получить НЕ Вашу таблицу с колонками :
• Столбец «Номенклатура»;
• Столбец «Партия»;
• Столбец «КоличествоСписания» - количество списания по накладной
• Столбец «СуммаСписания» - количество списания по накладной

А другую таблицу
Столбец «ДокументРасходнаяНакладная»;
• Столбец «Номенклатура»;
• Столбец «Партия»;
• Столбец «КоличествоСписания» - количество списания по накладной
• Столбец «СуммаСписания» - количество списания по накладной
57. Юрий Строжевский (y-str) 25.08.11 17:09
(55) Вспомнилась фраза из старого фильма, сказанная со смешной интонацией - "Не вижу препятствий!" :) Этот вопрос я уже обсуждал в (50): очень просто вместо таблицы только с номенклатурой и количеством получить таблицу с документом, всей номенклатурой и всеми количествами. Точно также используем ее в запроса, добавляя только группировку по регистратору. То есть в "ТаблицеНоменклатуры" будет еще одно поле - "РасходнаяНакладная" (или лучше назвать это поле сразу "Регистратор" для последующей выгрузки результата запроса в набор записей движений).

Повторюсь - запросы в статье открыты для экспериментов и оптимизаций, все в Ваших руках! :)
58. Игорь Исхаков (Ish_2) 25.08.11 17:37
(57) Статья была обозначена как альтернатива статье "Фифо для любопытных".
Я из этого и исхожу.
Но Ваша постановка задачи есть частный случай и сильное упрощение постановки задачи в "ФИФО для любопытных".
Т.е. никакая НЕ альтернатива.

С другой стороны , если Вы представите текст запроса для случая , когда на входе
таблица
• Столбец «ДокументРасходнаяНакладная»;
• Столбец «Номенклатура»;
• Столбец «КоличествоСписания»;

нам будет легко сравнивать альтернативные запросы.
И будет о чем поговорить. Пока нечего сравнивать.
59. Юрий Строжевский (y-str) 25.08.11 17:49
(58) Моя статья предназначена для демонстрации другого способа получения списка партий для списания вместе со всеми количествами/суммами. Демонстрация превосходств того или иного метода - тема для отдельного исследования и статьи :) Возможно я этим и займусь, но позже.
Но все, что нужно для модификации моего запроса я уже даже описал сам :)
60. Игорь Исхаков (Ish_2) 25.08.11 18:01
(59) Жаль.
1. При решении задачи полноценного ФИФО , т.е. получения движений для каждого документа расхода Вас ждут сюрпризы. И описанной Вами модификацией - лишь "добавляя только группировку по регистратору" - Вы ничего не добьетесь.
2. Остался без проверки главный подводный камень, на который налетают при использовании соединения по неравенству. При приличных объемах входных данных Ваш алгоритм - "рухнет".
См. Пример с таблицей 1 000 000 записей, которая соединяется сама с собой по неравенству.

Если бы было найдено решение , учитывающее 1 и 2 и которое принципиально отличалось бы от уже опубликованных на ИС - тогда бы мы поговорили всерьез.
61. Юрий Строжевский (y-str) 25.08.11 18:10
(60) Обещаю, что написание полноценного запроса под "полноценное ФИФО" будет темой моей следующей статьи :)
62. Игорь Исхаков (Ish_2) 25.08.11 18:11
63. Сергей (ildarovich) 25.08.11 18:21
(55)
приведено прямое решение для задачи из http://infostart.ru/public/61295/

- опять ошибаетесь!
Вы решаете другую задачу.
Вы считаете известной на ткущий момент ТаблицуДолгов с колонками: Контрагент, Накладная, СуммаДолга.
Чтобы ее получить, нужно один за другим последовательно провести документы по регистру взаиморасчетов по документам расчетов.
В решении http://infostart.ru/public/61295/ этого не требуется.
То есть оно работает при отсутствии в конфигурациях регистра взаиморасчетов по документам расчетов.
Как, кстати и не требуется перепроведения при изменении документов задним числом.
Другая задача - другие методы, как можно сравнивать?
Вы привели очевидное решение своей задачи.
Очевидное потому, что по-другому запрос и не записать, поставив задачу получить запросом списываемые партии из регистра партий.
И если бы не заблуждения относительно того, что это решение чего-то проще и компактней, то статья вполне может здесь пригодиться.
64. Юрий Строжевский (y-str) 25.08.11 18:26
(63) Я вот цитату приведу из http://infostart.ru/public/61295/:
Постановка задачи.

Даны две таблицы:
Таблица «Долги» ...


Я что-то путаю? Решаю другую задачу? Или привожу давно всем известное и избитое решение? Буду благодарен за любые ссылки на "аналоги" :)
65. Сергей (ildarovich) 25.08.11 18:42
(64) Именно так! - Путаете! В http://infostart.ru/public/61295/ в таблице долги нет колонки "Накладная".
Там для одного контрагента - одна строка: Сумма долга (текущая) и дата отсрочки.

Не знаю, насколько кому это решение известное.
Оно очевидное.
Потому что любой опытный программист напишет такое же.
Труднее написать по-другому.
Ну а очевидность для публикации здесь не препятствие.
66. Юрий Строжевский (y-str) 25.08.11 18:44
(60) Насчет "алгоритм рухнет". На самом деле "сравнение по неравенству" применяется в базах повсеместно. Прежде всего при сортировке строк - ведь всем известно, что любые алгоритмы сортировки используют "сравнение по неравенству", иначе отсортировать строки невозможно. Естественно, что для эффективной сортировки необходимо чтобы на сортируемых столбцах стоял уникальный индекс. Сортировка будет работать и без него, вот только в этом случае конечно "алгоритм рухнет" - будет выполнятся ооочень долго и с огромными затратами памяти. Но все в наших руках, и установить индекс по измерению регистра мы можем. Так что все впорядке :)
67. Юрий Строжевский (y-str) 25.08.11 18:48
(65) Ах, теперь мы уже говорим про таблицу "ТаблицаОборотов"? :) В ней накладная в первичной статье есть, ищите.

А выпады вроде "да это все фигня, любой так бы написал" - это уже без обсуждений :)
68. Игорь Исхаков (Ish_2) 25.08.11 18:53
(66) Разумеется , предварительно для таблицы, которая соединятся сама с собой , создается индекс по полю соединения. Лишь после получения индекса мы запускаем соединение "сама с собой" и засекаем время (таблица
имеет 1 000 000 записей).
..Дольше мне писать , чем Вам попробовать.
69. Юрий Строжевский (y-str) 25.08.11 19:00
(68) Дык вот попробывать то нет возможности, я бы с радостью - у меня только "Версия для обучения программированию" со встроенным 1С ограничением размера таблиц :) Как только найду нормальную систему - обязательно попробую!
70. Алексей Константинов (alexk-is) 25.08.11 20:40
(69) Так с этого и нужно было начинать... :)
72. hany (Hany) 25.08.11 22:12
Я плюсую за простоту кода и его дальнейшую понятность для остальных программистов в случае доработок даже без коммментариев.

Сегодня этот код успешно применен и протестирован на рабочей базе.
Оговорюсь, что вместо виртуальных таблиц Обороты использовала уже заранее сформированные временные таблицы в одном немаленьком запросе (таким образом СКЛю будет несложно выбрать оптимальный план запроса).
Так как запрос изначально был немаленьким, то вставлять в него еще 7 подзапросов считаю перегрузом. А так всего десяток строк - и наглядно и просто. Keep it simple!
P.S. У меня в соединяемых временных таблицах никогда не будет 1 000 000 записей, поэтому не боюсь, что запрос рухнет на огромном массиве данных.

Спасибо автору!
73. Юрий Строжевский (y-str) 25.08.11 22:13
(70) На контекст моей статьи из-за версии программного обеспечения влияния нет.
74. Юрий Строжевский (y-str) 25.08.11 22:14
75. Юрий Строжевский (y-str) 25.08.11 22:22
(71) В моей статья я показал другой метод получения списка партий для списания, отличный от всего, что я нашел на просторах Интернета. Он реально работает, он компактен и по своему красив. Среди всего множества людей наверняка есть и такие, кто его уже знают - я это допускаю. Кому-то он поможет, кому-то нет. Но своей цели я уже достиг - несколько человек посчитали статью стоящей и полезной.

Я полностью уверен, что при любых условиях хранения движений (остатков/оборотов), будь то регистр или справочник - этот запрос будет работать. Еще раз - доказывать кому-то что мой запрос лучше или хуже у меня цели нет. Считаете, что моя статья недостойна внимания - я буду работать с другими, которым она полезна.
ildarovich; +1 Ответить
76. Сергей (ildarovich) 25.08.11 23:34
(54) (63) (65) - в этих комментариях я ошибся в части задачи задолженности :cry: : задача о просроченной задолженности одна и та же!

Тем не менее, когда документов по одному контрагенту станет достаточно много,
приведенный запрос будет работать слишком долго - зависимость от числа документов квадратичная (показано в комментарии (18)).
А ведь срок давности документов в запросе не ограничен.

А вот запрос для списания партий вполне рабочий: ведь не списанных партий обычно немного (чаще даже одна).

(71) внимания, как я уже говорил, статья достойна.

Цель моих комментариев - исправить замеченные неточности относительно "альтернативности" подхода.

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

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

Простоту также считаю большим плюсом.
77. Юрий Строжевский (y-str) 26.08.11 09:39
(76) Приведенный запрос успешно посчитает "просроченные долги" при любом количестве документов. Долго ли, али нет - дело ума того, кто будет применять это на практике :)
Вопросы оптимизации умышленно вынесены за рамки моей статьи в угоду простоте изложения материала и его понятности, о чем и сказано в последнем абзаце текста статьи.
78. Юрий Строжевский (y-str) 30.09.11 18:58
(62)Написал статью, как и обещал. Но в итоге получилось две: Вычисление нарастающего итога для N таблиц в рамках одного запроса и Получение реквизитов движений для множества документов в рамках одного запроса.
В понедельник с утра опубликую их и здесь - хотелось бы привлечь к статьям больше внимания и конструктивной критики. Пока можно попытаться обсудить статьи здесь :)
79. Юрий Строжевский (y-str) 30.09.11 19:38
(62) Ish_2, мой предыдущий пост для Вас :)
80. Александр Медведев (anig99) 30.09.11 20:52
(78) обязательно нужно указать в статье, что запросы эти ресурсоёмкие, у чем больше записей в начальный таблицах, тем дольше он будет выполняться - по нарастающей. Я не привык читать сложные запросы из текста, но постараюсь разобраться в них.
81. Юрий Строжевский (y-str) 30.09.11 21:40
(80) anig99, насчет "ресурсоемкости" - проверки на эту характеристику для моих запросов у меня отсутствуют. Если кто-то смог бы их проверить на больших объемах данных (с выкладыванием статистики) то я был бы очень благодарен.
82. Александр Медведев (anig99) 30.09.11 22:25
(81) насчет статистики не могу помочь пока. Но запрос с нарастающими итогами по взаиморасчетам за 3 года выполнялся около 30 минут. Просто логически рассуди - к каждой записи присоединяются все предыдущие и конечная таблица перед группировкой возрастает многократно. Представь 10 записей в начальной - это 1 + (1+1) + (1 + 1 + 1) + (1 + 1 + 1 + 1). Формула f(n) = (n² + n) / 2. 10 объединяемых записей выльется в 55 записей, которые нужно сгруппировать, 100 в 5050

График.
Прикрепленные файлы:
83. Юрий Строжевский (y-str) 01.10.11 10:44
(82) anig99, то, что я привел в статьях это вычисление нарастающего итога с одновременным применением больших ограничений на размер выборки. Так что однозначно говорить о "ресурсоемкости" приведенных мною запросов нельзя, по-крайней мере нельзя без предварительных практических экспериментов.
84. Александр Медведев (anig99) 01.10.11 12:05
(83) даже жесткие ограничения на выборку могут не помочь - слишком быстро растёт количество объединяемых записей. Попробую получше посмотреть запросы и определить гарантируют ли ограничения оптимизацию выполнения.
85. Игорь Исхаков (Ish_2) 01.10.11 15:04
(82) Кхы.. кхы..
Сумму членов арифметической прогресии находил когда -то маленький Гаусс на уроке:
(А1+АN)*N/2
Если в начальной таблице 100 записей, то при соединении каждой записи со всеми предыдущими получаем :
А1=1,АN=100,N=100.
(1+100)*100/2 = 5050
Итак ,При соединении каждой записи со всеми предыдущими получаем получаем в итоговой таблице 5050 записей.
Промежуточная таблица возросла в 55 раз.
(83) Игнорировать такое возрастание невозможно. Любые алгоритмы , игнорирующие это обстоятельство нельзя рассматривать всерьез.
86. Юрий Строжевский (y-str) 01.10.11 15:34
(85) Ish_2, я придерживаюсь общепринятой позиции, что любая теория подлежит проверке на практике.
87. Александр Медведев (anig99) 01.10.11 19:12
(86) даже, что при достаточном количестве взрывов водородных бомб возможен запуск цепной реакции термоядерного синтеза тяжелой воды в мировом океане?
88. Юрий Строжевский (y-str) 01.10.11 20:12
(87) anig99, как-раз сейчас ищу "достаточное количество водородных бомб" для данного эксперимента :)
89. Игорь Исхаков (Ish_2) 01.10.11 21:55
(86) Я к эксперименту и призываю . Месяц назад в (7) был предлжено :
Можно убедиться в этом самостятельно : создайте таблицу tab1 с количеством записей 1 000 000 .
Запустите Ваш запрос - соединение по неравенству tab1 "сама с собой" засеките время. И всё поймете... назавтра.


Попробуете ?
90. Юрий Строжевский (y-str) 01.10.11 22:00
(89) Ish_2, месяц назад я написал пост (69).
91. Алексей Константинов (alexk-is) 01.10.11 22:25
(78) Про счетчики прикольно.
92. Алексей Константинов (alexk-is) 01.10.11 22:33
(90) Могу что-нибудь потестировать. :)
Есть все версии платформы и почти все типовые конфигурации фирмы 1С.
Могу развернуть как файловые, так и SQL базы данных (кроме Oracle).
93. Юрий Строжевский (y-str) 01.10.11 22:36
(92) alexk-is, супер! К статье Получение реквизитов движений для множества документов в рамках одного запроса прикреплена конфигурация. Там все очень "заточено" под одну задачу, но тем не менее данная конфигурация подходит для тестирования. Если у Вас получиться прогнать на ней нагрузочное тестирования и представить результаты я буду очень благодарен.
94. Алексей Константинов (alexk-is) 01.10.11 23:25
(93) Скачал. Установил. Как её подготовить к нагрузочным тестам? И где эти тесты?
Вообще-то я расчитывал на что-то вроде этого http://forum.infostart.ru/forum26/topic41810/message451107/#message451107
В плане того, что мне останется только понажимать кнопочки и опубликовать результаты. А тут получается, что нужно и данные набить, и методику нагрузочного тестирования придумать?
95. Юрий Строжевский (y-str) 02.10.11 08:27
(94) alexk-is, хорошо, я приготовлю как специализированную конфигурацию, так и все остальные обработки. На следующей неделе постараюсь сделать и известить Вас.
96. Алексей Константинов (alexk-is) 02.10.11 08:52
(95) Возможно, что специализорованная конфигурация и не нужна вовсе. Нужны обработки для заполнения базы данных и обработки для тестирования. Конфигурацию для тестирования можно взять любую. Даже ту, что уже есть.
97. Юрий Строжевский (y-str) 02.10.11 10:31
(96) alexk-is, на самом деле я решил провести тестирование сам на SQL Server 2008R2: сделаю имитацию таблиц партий и документов, затем заполню необходимым количеством данных и запущу запрос. Заодно нормально просмотрю план выполнения запроса.
98. Игорь Исхаков (Ish_2) 02.10.11 17:48
(96) Ставлю на тебя - 1 $m. Смотри не подведи.
99. Алексей Константинов (alexk-is) 02.10.11 19:50
(98) Вообще-то я предлагал помощь, а не соревнование...
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа