Страницы: 1
RSS
Суммирование по множеству условий таблицы с горизонтально расположенными данными, Нужна единая суммирующая формула
 
Добрый день!
Имеется периодически заполняемая таблица 1 по горизонтали с датами, по вертикали с номером магазина и наименованиями товаров (имена товаров могут повторятся).
Нужно из Таблицы 1 напрямую в Таблицу 4 получить сумму товаров по месяцам.
Я решил эту задачу через создание дополнительной Таблицы 2  и получил результат в Таблице 3 двумя формулами:
=СУММЕСЛИ($A$2:$A$9;$A12;B$2:B$9)
=СУММЕСЛИМН($B12:$AM12;$B$11:$AM$11;">="&B$17;$B$1:$AM$1;"<"&C$17)
Но хочу избавиться от промежуточной таблицы 2, не могу придумать единую формулу. Может есть решения через другие функции?

Также моё решение очень сильно увеличивает файл в размерах, что делает работу с ним затруднительнее.
Спасибо!
 
Код
=СУММ(($A$3:$A$9=$O18)*($B$1:$AM$1>=P$17)*($B$1:$AM$1<=КОНМЕСЯЦА(P$17;0))*$B$3:$AM$9)
Вводить, как формулу массива Ctrl+Shift+Enter.
 
Добрый день. Вариант: =СУММПРОИЗВ(($B$2:$AM$9)*($A$2:$A$9=$O18)*(ТЕКСТ($B$1:$AM$1;"МММ.ГГГГ")=ТЕКСТ(P$17;"МММ.ГГГГ")))
 
Ваша таблица 3 перестанет работать в декабре, так как используется месяц из ячейки, расположенной правее. Для устранения можно:
- написать 01.01.2027 в ячейку N17
- использовать КОНМЕСЯЦА(N$17;0)
 
как вариант {...}:
=СУММ(СУММЕСЛИ($A$2:$A$9;$O18;СМЕЩ($A$2:$A$9;;P$17-$B$1+ДЕНЬ(СМЕЩ($B$1;;;;ДЕНЬ(КОНМЕСЯЦА(P$17;0)))))))
 
Или так, чтобы не было массивно
Код
=СУММПРОИЗВ(($B$1:$AM$1<=КОНМЕСЯЦА(P$17;0))*($B$1:$AM$1>=P$17)*($A$2:$A$9=$O18)*$B$2:$AM$9)
 
Всем огромное спасибо! Работает! Изучу внимательнее все варианты и выберу самый оптимальный)
 
pq
pq v2
Изменено: sotnikov - 26.03.2026 19:48:55
 
К сожалению, формулы массива сильно перегружают рабочий файл, что приводит к остановке экселя. PQ для меня слишком сложно...
Может есть какие-то менее ресурсоёмкие функции для версии экселя 2021 года
 
Код
Option Explicit

Sub Сумм_диапазон()
    Dim rSource As Range
    On Error Resume Next
    Set rSource = Application.InputBox("Выберите диапазон-источник", "Суммирование", Default:="1:9", Type:=8)
    Set rSource = Intersect(rSource, rSource.Parent.UsedRange)
    On Error GoTo 0
    If rSource Is Nothing Then Exit Sub
    
    Dim aSor As Variant
    aSor = rSource.Value
    ClearArray aSor
    
    Dim aTar As Variant, dic As Object
    aTar = GetTargetArray(aSor, dic)
    If IsEmpty(aTar) Then Exit Sub
    FillTargetArray aTar, aSor, dic, rSource
    
    Dim rTarget As Range
    On Error Resume Next
    Set rTarget = Application.InputBox("Выберите диапазон-приёмник", "Суммирование", Default:="O17", Type:=8)
    Set rTarget = Intersect(rTarget, rSource.Parent.UsedRange)
    On Error GoTo 0
    If rTarget Is Nothing Then Exit Sub
    
    PrintArray rTarget, aTar
End Sub

Private Sub PrintArray(rTarget As Range, aTar As Variant)
    Set rTarget = rTarget.Resize(UBound(aTar, 1), UBound(aTar, 2))
    
    rTarget.Formula = aTar
End Sub

Private Sub FillTargetArray(aTar As Variant, aSor As Variant, dic As Object, rSor As Range)
    Dim ys As Long, xs As Long, xt As Long, yt As Long
    For xs = 1 To UBound(aSor, 2)
        If IsDate(aSor(1, xs)) Then
            If aSor(1, xs) > 0 Then
                For xt = 2 To UBound(aTar, 2) - 1
                    If aSor(1, xs) >= aTar(1, xt) Then Exit For
                Next
                For ys = 2 To UBound(aSor, 1)
                    If aSor(ys, xs) <> 0 Then
                        yt = dic(aSor(ys, 1)) + 2
                        aTar(yt, xt) = aTar(yt, xt) & rSor.Cells(ys, xs).Address(0, 0) & " "
                    End If
                Next
            End If
        End If
    Next
    Dim ss As String
    For yt = 2 To UBound(aTar, 1)
        For xt = 2 To UBound(aTar, 2)
            If Not IsEmpty(aTar(yt, xt)) Then
                ss = aTar(yt, xt)
                ss = Trim(ss)
                ss = Replace(ss, " ", "+")
                ss = "=" & ss
                aTar(yt, xt) = ss
            End If
        Next
    Next
End Sub

Private Function GetTargetArray(aSor As Variant, dic As Object) As Variant
    Dim xs As Long, dtMin As Date, dtMax As Date
    For xs = 1 To UBound(aSor, 2)
        If IsDate(aSor(1, xs)) Then
            If aSor(1, xs) > 0 Then
                If dtMax < aSor(1, xs) Then
                    dtMax = aSor(1, xs)
                End If
                If dtMin = 0 Then
                    dtMin = aSor(1, xs)
                ElseIf dtMin > aSor(1, xs) Then
                    dtMin = aSor(1, xs)
                End If
            End If
        End If
    Next
    If dtMax = 0 Then Exit Function
    If dtMin = 0 Then Exit Function
    
    dtMin = DateSerial(Year(dtMin), Month(dtMin), 1)
    dtMax = DateSerial(Year(dtMax), Month(dtMax), 1)
    
    Dim dtCur As Long
    xs = 0
    dtCur = dtMin
    Do
        xs = xs + 1
        If dtCur = dtMax Then Exit Do
        dtCur = DateSerial(Year(dtCur), Month(dtMin) + 1, 1)
        DoEvents
    Loop
    
    Dim aTarg As Variant
    ReDim aTarg(1 To 1 + xs)
    
    Set dic = CreateObject("Scripting.Dictionary")
    Dim ys As Long
    For xs = 1 To UBound(aSor, 2)
        If IsDate(aSor(1, xs)) Then
            If aSor(1, xs) > 0 Then
                For ys = 2 To UBound(aSor, 1)
                    If aSor(ys, xs) <> 0 Then
                        If Not dic.Exists(aSor(ys, 1)) Then
                            dic(aSor(ys, 1)) = dic.Count
                        End If
                    End If
                Next
            End If
        End If
    Next
    If dic.Count = 0 Then Exit Function
    
    ReDim aTarg(1 To 1 + dic.Count, 1 To UBound(aTarg))
    For ys = 0 To dic.Count - 1
        aTarg(ys + 2, 1) = dic.Keys()(ys)
    Next
    
    dtCur = dtMin
    For xs = 2 To UBound(aTarg, 2)
        aTarg(1, xs) = dtCur
        dtCur = DateSerial(Year(dtCur), Month(dtMin) + 1, 1)
    Next
    GetTargetArray = aTarg
End Function

Private Sub ClearArray(arr As Variant)
    Dim ya As Long
    Dim xa As Long
    For ya = LBound(arr, 1) To UBound(arr, 1)
        For xa = LBound(arr, 2) To UBound(arr, 2)
            If IsError(arr(ya, xa)) Then
                arr(ya, xa) = Empty
            End If
        Next
    Next
End Sub

Private Sub CloseEmptyWb()
    Dim wb As Workbook
    For Each wb In Application.Workbooks
        If wb.Path = "" Then wb.Close False
    Next
End Sub
 
Цитата
jonika-net написал: для версии экселя 2021 года
Код
=СУММ(ФИЛЬТР(ФИЛЬТР($B$2:$AM$9;$A$2:$A$9=$A18;0);МЕСЯЦ($B$1:$AM$1)=МЕСЯЦ(B$17);0))
Согласие есть продукт при полном непротивлении сторон
 
Цитата
написал:
=СУММ(ФИЛЬТР(ФИЛЬТР($B$2:$AM$9;$A$2:$A$9=$A18;0);МЕСЯЦ($B$1:$AM$1)=МЕСЯЦ(B$17);0))
Спасибо! Это - то, что нужно
 
Добрый день! Подскажите, почему выборка по месяцам работает:
Код
=СУММ(ФИЛЬТР(ФИЛЬТР($B$3:$AK$8;$A$3:$A$8=$A12;0);МЕСЯЦ($B$2:$AK$2)=МЕСЯЦ(B$11);0))
а по неделям:
Код
=СУММ(ФИЛЬТР(ФИЛЬТР($B$3:$AK$8;$A$3:$A$8=$A19;0);НОМНЕДЕЛИ($B$2:$AK$2;21)=НОМНЕДЕЛИ(B$17;21);0))

не работает?

Обе функции возвращает порядковый номер, по идее, должны одинаково работать...

 
Потому что функция НОМНЕДЕЛИ не работает с масивами дат. Поэтому для определения номера недели лучше использовать функцию НОМНЕДЕЛИ.ISO (). В итоге ваша формула примет вид
Код
=СУММПРОИЗВ($B$3:$AK$8;($A$3:$A$8=$A19)*(НОМНЕДЕЛИ.ISO($B$2:$AK$2)=НОМНЕДЕЛИ.ISO(B$17)))
Не столь важно что ты делаешь, важно как ты это делаешь! (Джимми Лансфорд)
Страницы: 1
Читают тему
Наверх