Страницы: 1
RSS
Подбор диапазона для суммирования по условиям
 
Всем добрый день!

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

Вроде просто, но смогла прописать только опираясь на номер строки в исходных таблицах (на практике порядок позиций на разных вкладках может не совпадать) и ДВССЫЛ

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

Может можно проще посчитать формулой массива? Пробовала поискать аналогичные примеры на форуме, но не нашла, либо как-то не так искала..
Изменено: Neonovaya - 07.03.2025 16:48:48
Excel 2010
 
Здравствуйте.
Попробуйте формулу
Код
=ЕСЛИОШИБКА(СУММ(ИНДЕКС(ДВССЫЛ("'"&G$2&"'!E7:E9999");ПОИСКПОЗ($B5;ДВССЫЛ("'"&G$2&"'!C7:C9999");)):ИНДЕКС(ДВССЫЛ("'"&G$2&"'!E7:P9999");ПОИСКПОЗ($B5;ДВССЫЛ("'"&G$2&"'!C7:C9999"););$C$3));СУММЕСЛИ($A:$A;$C5;G:G))

В ячейку G5, скопировать ячейку, выделить нужный диапазон таблицы, в столбцах G:H, и вставить специальной вставкой только Формулы. Не гарантирую что работать будет быстро. В книге много других расчетов которые могут тормозить.

 
Neonovaya, если даже оптимизировать все что можно, то останутся летучие функции INDIRECT./ ДВССЫЛ ,что заставляет пересчитывать все при надо и нет

Все ж можно ряд расчетов убрать, номера строк не нужны но и искать их можно и нужно один раз.
Если вы избавитесь от ДВССЫЛ в пользу корректировки формул для каждого года, то будет еще легче и проще.
Не сильно упростит, но можно количество столбцов для суммирования сразу задать, во втором блоке сделал пример.
По вопросам из тем форума, личку не читаю.
 
БМВ, gling, Всем большое спасибо, изучаю :)
Excel 2010
 
Вариант через макрос. Вставьте код в модуль листа MOSCHINO.
Код
Option Explicit
Private Const TARGET_RANGE_FIRST_ROW = "G5:H5"
Private Const TARGET_LINE_COLUMN = "A"
Private Const TARGET_REF_COLUMN = "B"
Private Const TARGET_YEAR_ROW = 2
Private Const TARGET_MONTH_CELL = "C3"
Private Const SOURCE_REF_COLUMN = "C"
Private Const SOURCE_RANGE_FIRST_CELL = "E7"

Private Sub Worksheet_Change(ByVal Target As Range)
    If Target.Address(0, 0, xlA1) = TARGET_MONTH_CELL Then Заполнить_формулы
End Sub

Sub Заполнить_формулы()
    Dim shTarget As Worksheet, rTarget As Range, aTarget As Variant, aLine As Variant, aRef As Variant, aYear As Variant, monthCount As Long
    Set shTarget = Sheets(1)
    With shTarget
        Set rTarget = .Rows(1).Resize(.Cells(.Rows.Count, 1).End(xlUp).Row)
        Set rTarget = Intersect(rTarget, .Range(TARGET_RANGE_FIRST_ROW).Resize(.UsedRange.Row + .UsedRange.Rows.Count))
        
        aLine = GetArrayFromRange(Intersect(rTarget.EntireRow, .Columns(TARGET_LINE_COLUMN)))
        aRef = GetArrayFromRange(Intersect(rTarget.EntireRow, .Columns(TARGET_REF_COLUMN)))
        aYear = GetArrayFromRange(Intersect(rTarget.EntireColumn, .Rows(TARGET_YEAR_ROW)))
        monthCount = .Range(TARGET_MONTH_CELL).Value
    End With
    
    ReDim aTarget(1 To rTarget.Rows.Count, 1 To rTarget.Columns.Count)
    FillFormulasArray aTarget, aYear, aRef, monthCount, rTarget
    
    rTarget.Formula = aTarget
End Sub

Private Sub FillFormulasArray(aTarget As Variant, aYear As Variant, aRef As Variant, monthCount As Long, rTarget As Range)
    Dim xt As Long, shSource As Worksheet
    For xt = 1 To UBound(aYear, 2)
        On Error Resume Next
        Set shSource = Sheets(CStr(aYear(1, xt)))
        On Error GoTo 0
        If Not shSource Is Nothing Then
            JobSourceSheet shSource, aRef, monthCount, aTarget, xt, rTarget
            Set shSource = Nothing
        End If
    Next
End Sub

Private Sub JobSourceSheet(shSource As Worksheet, aRef As Variant, monthCount As Long, aTarget As Variant, xt As Long, rTarget As Range)
    Dim dicY As Object
    Set dicY = GetDicY(shSource)
    
    Dim ss As String, st As String
    ss = GetSumColumnFormula(shSource.Name, monthCount)
    
    Dim sTotal As String, su As String
    sTotal = rTarget.Cells(1, xt).EntireColumn.Cells(1, 1).Address(0, 0, xlA1)
    sTotal = Replace(sTotal, 1, "")
    sTotal = "=SUM(" & sTotal & "beg:" & sTotal & "fin)"
    
    Dim yt As Long, ys As Long, yBeg As Long, yFin As Long, dy As Long
    dy = rTarget.Row - 1
    
    For yt = 1 To UBound(aRef, 1)
        If Not IsEmpty(aRef(yt, 1)) Then
            If dicY.Exists(CStr(aRef(yt, 1))) Then
                ys = dicY(CStr(aRef(yt, 1)))
                st = Replace(ss, "#", ys)
                aTarget(yt, xt) = st
                
                yFin = yt
                If yBeg > 0 Then
                    su = Replace(sTotal, "beg", yBeg + 1 + dy)
                    aTarget(yBeg, xt) = Replace(su, "fin", yFin + dy)
                End If
            End If
        Else
            yBeg = yt
        End If
    Next
End Sub

Private Function GetSumColumnFormula(shSource_Name As String, monthCount As Long) As String
    Dim xx As Long, arr As Variant
    ReDim arr(1 To monthCount)
    For xx = 1 To monthCount
        arr(xx) = Range(SOURCE_RANGE_FIRST_CELL).EntireColumn.Cells(1, xx).Address(0, 0, xlA1)
        arr(xx) = Replace(arr(xx), 1, "#")
        arr(xx) = "'" & shSource_Name & "'!" & arr(xx)
    Next
    GetSumColumnFormula = "=" & Join(arr, "+")
End Function

Private Function GetDicY(shSource As Worksheet) As Object
    Dim aRef As Variant
    With shSource
        aRef = .Columns(SOURCE_REF_COLUMN).Cells(Range(SOURCE_RANGE_FIRST_CELL).Row).Resize(.UsedRange.Rows.Count)
        Dim dicY As Object
        Set dicY = CreateObject("Scripting.Dictionary")
        Dim ys As Long, dy As Long
        dy = Range(SOURCE_RANGE_FIRST_CELL).Row - 1
        For ys = 1 To UBound(aRef, 1)
            If Not IsEmpty(aRef(ys, 1)) Then
                dicY(CStr(aRef(ys, 1))) = ys + dy
            End If
        Next
    End With
    
    Set GetDicY = dicY
End Function

Private Function GetArrayFromRange(rr As Range) As Variant
    Dim arr As Variant
    If rr.Cells.CountLarge = 1 Then
        ReDim arr(1 To 1, 1 To 1)
        arr(1, 1) = rr.Value
    Else
        arr = rr.Value
    End If
    GetArrayFromRange = arr
End Function
Изменено: МатросНаЗебре - 10.03.2025 11:06:17 (Файл)
 
Цитата
Neonovaya:   ...ДВССЫЛ...
...файлу явно тяжело пересчитывать всё по этим формулам...
странно почему? )
можно выбором их, например:
=СУММЕСЛИ(Num_month;"<="&$C$3;ВЫБОР(G$2-2023;ИНДЕКС(SI_last_year_pcs;ПОИСКПОЗ($B91;Ref_last_year;); );ИНДЕКС(SI_current_year_pcs;ПОИСКПОЗ($B91;Ref_current_year;); )))
еще шустрее будет высчитывать сумму на каждом листе:
=СУММЕСЛИ(E$1:P$1;"<="&MOSCHINO!$C$3;E7:P7)
и ВПРить...:
=ВЫБОР(G$2-2023;ВПР($B91;'2024'!$C:$AF;30;);ВПР($B91;'2025'!$C:$AF;30;))
конечно для двух листов это все баловство (проще  здесь для года свой впр)
 
МатросНаЗебре, Павел \Ʌ/,  Спасибо вам большое! :)
Excel 2010
Страницы: 1
Читают тему
Наверх