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

Есть таблица примерно 2000 строк и 300 столбцов с разными данными текст, пустые, числа.
Внимание! Файл с таблицей почти постоянно на общем доступе в локальной сети, это накладывает очень серьезные ограничения на способы решения задачи.
По строкам это реестр договоров предприятия, сгруппированный в статьи доходов и затрат (т.е. имеем порядка 200 промежуточных итогов по мини реестрам, относящимся к одной статье), по столбцам это текстовая аналитика типа предмет договора, контрагент и т.п., суммы доходов и затрат по месяцам и годам, а также аналитические признаки в отдельных столбцах.

Как вы уже догадались задача тривиальная - суммировать нужные столбцы в соответсвии с аналитическими признаками.
А вот количество условий суммирования по этим признакам, применяемых одновременно не стабильно. На данный момент это может быть от 1 до 5 условий на усмотрение пользователя. Механизм такой - если критерий задан в специальной ячейке со списком, то условие применятся, если не задан (ячейка пуста), то не применяется.
Есть еще важный момент. Диапазон строк, к которому применяется фильтрация, тоже может быть разный. Или по-умному - динамический. Но границы по строкам задаются просто - функцией строка(Имя), где имя - это именованная ячейка, они созданы для первой и последней строки всех нужных диапазонов.

В итоге получается для решения моей задачи надо создать формулу с пятикратным вызовом СУММЕСЛИМН() или СУММПРОИЗВ() внутри пяти вложений конструкции ЕСЛИ(проверка сколько условий задано; вызов СУММЕСЛИМН() с этими условиями);ЕСЛИ(...)) при этом все диапазоны задавать с помощью ДВССЫЛ() или СМЕЩ(). О, ужас! Такую конструкцию надо писать в Ворде на поллиста.
А хотелось что-то типа СУММПРОИЗВ(Диапазон суммирования*ЕСЛИ(Условие<>"";Диапазон условий=условие;1)). Все бы хорошо, если бы не ЕСЛИ, которая не хочет возвращать массив без формулы массива, а формулы массива в таком файле тормозят ужасно.
В итоге я создал пользовательскую функцию на VBA, куда и запихал весь этот ужас на поллиста. Однако я передал ей номера столбцов и строк, а не диапазоны, и она не стала отслеживать изменения значений внутри диапазонов. Т.е. работала как сводная таблица, только вместо обновить надо жать F9. Сделал её "летучей" и получил те же тормоза, что и с формулой массива, даже еще хуже. Плюс стали появлятся ошибки "Разрушительный сбой" при открытии файла. Лечил ошибку жесткой привязкой функции к листу с данными.
Фрагмент функции шапка, привязка к листу и вызов одного из вариантов СУММЕСЛИМН:
Function СуммБК(стрверх As Integer, стрниз As Integer, графасумм As Integer, грусл1 As Integer, усл1 As String, Optional грусл2 As Integer... и т.д 5 условий)
With ThisWorkbook.Sheets("БК")
If i = 1 Then
СуммБК = Application.WorksheetFunction.SumIfs(.Range(.Cells(стрверх, графасумм), .Cells(стрниз, графасумм)), .Range(.Cells(стрверх, R(1)), .Cells(стрниз, R(1))), U(1))
Exit Function
R массив номеров столбцов с критериями, U массив значений этих критериев.
Думаю, что функцию на VBA в этом виде рассматривать нет смысла, поэтому полный код не привожу, т.к. без летучести плохо работает, а с ней тормозит файл.

Собственно вопрос, как заставить работать конструкцию СУММПРОИЗВ(Диапазон суммирования*ЕСЛИ(Условие<>"";Диапазон условий=условие;1)) без формулы массива или альтернативный способ отключить условие (т.е. сделать массив из значений равных 1 нужной размерности внутри формулы) когда пользователь удалил критерий, т.е. значение условия =""
и по пути, подскажите более компактный вариант создания диапазона, сеячас я делаю ДВССЫЛ("R"&СТРОКА(имя1)&"C"&$AI$4&"R"&СТРОКА(имя2)&"C"&$AI$4;ЛОЖЬ), в ячейке AI4 номер нужного столбца. Можно и СМЕЩ, конечно. Но желательно вариант без этих "Летучих", шибко их много в файле получается.

Ху, спасибо уже за то, что дочитали мой крик души.
Изменено: Сергей Идимечев - 05.12.2020 07:50:20
В топку калькулятор, только Excel, только формулы и чутка VBA
 
Цитата
Сергей Идимечев написал:
Такую конструкцию надо писать в Ворде на поллиста
судя по описанию - формула символов до 100
данные бы только увидеть, чтобы понимать что, где лежит
и букв было бы гораздо меньше, если сосредоточиться на описании задачи, а не описывать двухмесячные попытки поиска способов ее решения))
Изменено: Ігор Гончаренко - 05.12.2020 09:52:01
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Букв много примеров -ноль
Цитата
Сергей Идимечев написал:
В итоге получается для решения моей задачи надо создать формулу с пятикратным вызовом СУММЕСЛИМН()
ну и что тут такого?
В ваших 5 условиях предусмотреть замену условия с учетом числовое или текстовое поле.
По вопросам из тем форума, личку не читаю.
 
Цитата
Ігор Гончаренко написал:
судя по описанию - формула символов до 100
в каждой СУММЕСЛИ() конструкция ДВССЫЛ("R"&СТРОКА(имя1)&"C"&$AI$4&"R"&СТРОКА(имя2)&"C"&$AI$4;ЛОЖЬ) для диапазона суммирования и для диапазона/ов условий. 2+3+4+5+6=20 штук ДВССЫЛ примерно 1200 символов не считая остальной мелочи типа условий вида $AI$4. 20 штук ДВССЫЛ в каждой ячейки, где такая формула, а их около 1000, 20000 вызовов летучей функции в книге на общем доступе, которые пересчитываются всегда, даже когда работаем в другом файле.
И даже такую формулу я пережеву, но, хм,  хотелось бы что-то короче и элегантней, и не так дико грузить железо.
Цитата
БМВ написал:
предусмотреть замену условия
Не так все просто. "*" пропускает пустые, а отключенное условие не пропускает. Вот как сделать для текстовых, чтобы и пустые считал и с критерием, когда условие не задано? Числовых критериев у меня нет, текстовые и логические.
Изменено: TotalAvtomatic - 05.12.2020 15:09:49
В топку калькулятор, только Excel, только формулы и чутка VBA
 
TotalAvtomatic, а зачем по ходу темы меняете отображаемое имя? Ведь вносите неразбериху...
 
Сорян, сразу не сообразил настроить

А вот как выглядит в файле вызов моей функции, это вместо  формулы на 1200 символов:
Код
=СуммБК($N$3;$O$3;I$5;$D$3;$D$2;$E$3;$E$2;$C$3;$A15)

Есть разница?
Кому интересно аргументы слева направо:
номер верхней строки, номер нижней строки, номер столбца суммирования, номер столбеца критериев, ячейка с значением критерия и далее по порядку столбец с критерием, условие к нему
В топку калькулятор, только Excel, только формулы и чутка VBA
 
нашел вариант по-короче:
Код
= С
как вам?
первоначально было
Код
=См
но я смело сократил до
Код
= С
Изменено: Ігор Гончаренко - 05.12.2020 15:49:58
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
ну тогда так
Изменено: БМВ - 05.12.2020 16:45:04
По вопросам из тем форума, личку не читаю.
 
Цитата
Ігор Гончаренко написал:
как вам?
Да ладно вам. Мои пользователи от ДВССЫЛ вложенной в ВПР глаза округляют, когда наступят на ячейку, а от такой СУММЕСЛИМН - не дай бог увидят, никаким нашатырем не откачаю.
К тому же в посте 3 БМВ уже сделал файл с моей задачей, пока я думал как из своего файла кусок вырезать)))

Цитата
БМВ написал:
ну тогда так
Не, первый вариант (пост 3) лучше, для БДСУММ мне не получится задать названия столбцов, они же уникальные должны быть, а у меня там дублей полно. К тому же не понятно как она на общем доступе себя поведет.
В СУММПРОИЗВ я ошибся внеся Диапазон во внутрь ЕСЛИ, надо *(Диапазон=ЕСЛИ(G9="";"*";G9)), тогда работает, но не со "*", а только с критерием или пустой строкой в качестве значения критерия. Но не то.

Попробовал вставить в СУММЕСЛИМН подобно как у вас ЕСЛИ(G9="";"*";G9), почти получилось, пустые мешают, и, к сожалению, в одном столбце я не могу от пустых ячеек гарантированно избавиться.
Вот маленький кусочек моего файла, пока поставил если на контрагента (это и есть проблемный столбец) и на КПЭ (в этом столбце можно пустые заменить на 0 или сделать да и нет)
Изменено: TotalAvtomatic - 05.12.2020 20:29:34
В топку калькулятор, только Excel, только формулы и чутка VBA
 
ну значит так
=SUMIFS(R8:R22;IF($B2="";$TT8:$TT22;$B8:$B22);IF($B2="";"";$B2);IF($C2="";$TT8:$TT22;$C8:$C22);IF($C2="";"";$C2);IF($D2="";$TT8:$TT22;$D8:$D22);IF($D2="";"";$D2);IF($E2="";$TT8:$TT22;$E8:$E22);IF($E2="";"";$E2);IF($F2="";$TT8:$TT22;$F8:$F22);IF($F2="";"";$F2))
По вопросам из тем форума, личку не читаю.
 
Да, всё гениальное просто.
Вы не поверите, но вот этого приема
Цитата
БМВ написал: IF($B2="";$TT8:$TT22;$B8:$B22)
подстановки разных диапазонов с помощью ЕСЛИ я не увидел ни в одном примере на десятках страниц, посвященных динамическим диапазонам. Да и самому в голову не пришло, раз ЕСЛИ не возвращает массив, а возврат диапазона в одну ячейку вызывает ошибку без формулы массива, это еще не значит, что ЕСЛИ не может вернуть обычную ссылку на диапазон во внутрь формулы))).
Фишка заставить сравнивать пустое с пустым чтобы получить массив истин мне вообще понравилась, при этом ссылка за пределы таблицы не расширяет пользовательский диапазон - отлично!
Недостаток остался один, он есть и в моей функции на VBA - это подсчет строк с промежуточными итогами при отсутствии всех условий. Моя возвращает в таком случае 0, и здесь можно всю конструкцию вложить в ЕСЛИ и отключать расчет без критериев, это уже просто.

Итак, задача решена, с вашего позволения, подведу итог, может кому пригодится.
Включить/отключить использование критерия отбора пользователем можно конструкциями:
для СУММЕСЛИМН
Цитата
БМВ написал: IF($B2="";$TT8:$TT22;$B8:$B22);IF($B2="";"";$B2);
для СУММПРОИЗВ тоже работает --(ЕСЛИ(B2="";TT8:TT22;B8:B22)=ЕСЛИ(B2="";"";B2))
в обоих формулах:
B2 - ячейка со значением критерия или пустая, если пользователь отключил отбор по этому критерию
B8:B22 - диапазон со значениями критериев
ТТ8:ТТ22 - любой диапазон за пределами таблицы с пустыми ячейками нужной размерности.

Всем участникам спасибо, БМВ, вам огромнейшая благодарность.
В топку калькулятор, только Excel, только формулы и чутка VBA
 
Цитата
Ігор Гончаренко написал:
судя по описанию - формула символов до 100
сбылось мое пророчество?
Программисты - это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!
 
Цитата
TotalAvtomatic написал:
для СУММПРОИЗВ тоже работает --(ЕСЛИ(B2="";TT8:TT22;B8:B22)=ЕСЛИ(B2="";"";B2))
тот то проще
--ЕСЛИ(B2="";TT8:TT22="";B8:B22=B2)
По вопросам из тем форума, личку не читаю.
 
Цитата
Ігор Гончаренко написал:
сбылось мое пророчество?
без ДВССЫЛ, да. А с ней будет 400-500 - но всё же это не 1200-1500 символов, это уже можно читать в ячейке. Да и вызовов ДВССЫЛ втрое меньше будет, что есть зергуд.
В топку калькулятор, только Excel, только формулы и чутка VBA
 
Цитата
TotalAvtomatic написал:
ДВССЫЛ("R"&СТРОКА(имя1)&"C"&$AI$4&"R"&СТРОКА(имя2)&"C"&$AI$4;ЛОЖЬ)
Оно не короче, но и не летуче
ИНДЕКС($1:$1048576;СТРОКА(имя1);$AI$4):ИНДЕКС($1:$1048576;СТРОКА(имя2);$AI$4): но ведь можно в имена убрать, для компактности.\

Цитата
Ігор Гончаренко написал:
сбылось мое пророчество?
Игорь, тут ты не совсем прав, если делать с учетом включения или отключения условий в зависимости от введено ли то или иное значение, то вариантов будет 2^n и формула будет уже длинной, ну если не прятать в имена конкретные варианты, хотя производительность её будет, на мой взгляд лучше.
Изменено: БМВ - 06.12.2020 08:45:28
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал: тот то проще--ЕСЛИ(B2="";TT8:TT22="";B8:B22=B2)
Не сработает, это я сразу пробовал. ЕСЛИ возвращает только результат первого сравнения, далее несовпадение размерности и ошибка. Причем по F9 показывает массив значений, но через команду меню "Вычислить формулу", где по шагам видно - там одно значение, только для первого сравнения (для строки 8 и всё).
я это и имел ввиду во фразе:
Цитата
TotalAvtomatic написал:  раз ЕСЛИ не возвращает массив,
Такое ЕСЛИ только через CTRL+SHIFT+ENTER работает. Что уже не зергуд, не для файла на общем доступе такое счастье.

Цитата
БМВ написал: Оно не короче, но и не летуче но ведь можно в имена убрать, для компактности.
Вот еще подарок от БМВ, как раз вовремя. Сижу сейчас и пытаюсь обойти СМЕЩ() для первого аргумента ИНДЕКС))). Начитался А1:ИНДЕКС и решил, что ИНДЕКС нельзя ставить первым. Нет чтобы попробовать))).

Цитата
БМВ написал: ...ведь можно в имена убрать,
Имена? Пожалуй, да, всего 6 имен надо, если закинуть в них диапазоны, то должно быть вообще зергуд.

Хм, здорово, пойду воплощать.
В топку калькулятор, только Excel, только формулы и чутка VBA
 
Цитата
TotalAvtomatic написал:
Не сработает, это я сразу пробовал. ЕСЛИ возвращает только результат первого сравнения,
просто его надо правильно готовить, массивно
=SUM(D2:D9*IF(G2="";E2:E9="";A2:A9=G2)*IF(H2="";E2:E9="";B2:B9=H2)*IF(I2="";E2:E9="";C2:C9=I2))
или даже так
=SUM(D2:D9*IF(G2="";1;A2:A9=G2)*IF(H2="";1;B2:B9=H2)*IF(I2="";1;C2:C9=I2))
Изменено: БМВ - 06.12.2020 16:32:54
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
просто его надо правильно готовить, массивно
да, к сожалению

Закатал я новую формулу на главный лист и отключил летучесть своей функции, файлик ожил заметно. С именами даже небольшая вышла.
возникло пара вопросов
1 в ИНДЕКС я попытался заменить  ИНДЕКС($1:$1048576 на ИНДЕКС($1:$3000, больше строк не предвидится и номера строк поплыли, начали меняться при пересчете, причем в ячейке с формулой для диапазона суммирования незначительно, а вот в имени начался полный хаос, вплоть до того, что верхняя строка стала больше нижней. Что это было? Циклическая ссылка, т.к. ячейка с формулой внутри диапазона ИНДЕКС($1:$3000, почему тогда ваш вариант с последней строкой не сбивается с нумерации, непонятно.
2 в имени попытался использовать ВПР для возврата номера столбца из справочника на другом листе и получил н/д, правда я имена объявил на уровне листа. Что это - конфликт видимости имени и ссылки на другой лист в ВПР, или просто ВПР нельзя использовать в формуле имени?
В топку калькулятор, только Excel, только формулы и чутка VBA
Страницы: 1
Наверх