Forum Discussion

kostask's avatar
kostask
Helper II
4 years ago
Solved

Filling values for missing dates for many attribute combinations

Hi guys.

I had the community's support for a similar problem, but the specific one seems more complicated for me to resolve.

So, we have 3 attributes (Bank, CustomerNo, AccountNo), which give many possible combinations.

I created a consolidated table that gives the closing balance per date per combination (table A)

My problem is that when trying to calculate the total balance per date (and per attribute or combinations) in a time series, I have missing dates, some completely (ex 2/7/2022), and some per one attribute (ex 4/7/2022 for CustomerNo 2000), because there don't exist records for the bank to generate a closing balance for the specific dates.

 

So, I guess we need a calendar with all dates and a calculated measure that will calculate the closing balance of the missing dates, using the last available closing balance, and all above for the compilations of the 3 attributes.

 

The expected outcome is given in table B. I tried with colored backgrounds to connect the groups of records that exist (table A) with the ones that have to be generated (table B).

 

Also provide table A, in case someone wants to use it.

DateBankCustomerNoAccountNoBalance
1/7/2022A1000XXX100
4/7/2022A1000XXX120
3/7/2022A2000CCC200
3/7/2022A1000VVV300
5/7/2022A2000CCC110
3/7/2022B1000OOO50
6/7/2022B1000OOO500
6/7/2022B1000PPP25
1/7/2022B2000LLL400
3/7/2022B2000LLL100

 

Thank you in advance!

Kostas

  • Hi kostask 
    Here is the updated solution with correct subtotals https://we.tl/t-ULVbpV6vB9

     

    FinalBalance1 = 
    VAR CurrentDate =
        MAX ( 'Calendar'[Date] )
    VAR IterationTable =
        CALCULATETABLE (
            SUMMARIZE ( 'Totals', 'Totals'[Bank], 'Totals'[Company], 'Totals'[AccountNo] ),
            ALL ( 'Calendar' )
        )
    RETURN
        SUMX (
            IterationTable,
            CALCULATE (
                VAR CurrentValue =
                    SUM ( 'Totals'[FinalBalance] )
                VAR CurrentAcountTable =
                    CALCULATETABLE ( 'Totals', ALL ('Calendar' ) )
                VAR PreviousDatesTable =
                    FILTER ( CurrentAcountTable, 'Totals'[Date] < CurrentDate )
                VAR PreviousDate =
                    MAXX ( PreviousDatesTable, 'Totals'[Date] )
                VAR PreviousDateTable =
                    FILTER ( PreviousDatesTable, 'Totals'[Date] = PreviousDate )
                VAR PreviousValue =
                    SUMX ( PreviousDateTable, 'Totals'[FinalBalance] )
                RETURN
                    - COALESCE ( CurrentValue, PreviousValue )
            )
        )

     

10 Replies

  • tamerj1's avatar
    tamerj1
    Community Champion

    Hi kostask 
    In order to obtain correct totals please follow updated sample file https://we.tl/t-W0y5fERFnF

    The new measure refers to the original measure using switch statement

     

    Closing Balance = 
    VAR CurrentDate = MAX ( 'Date'[Date] )
    VAR CurrentValue = SELECTEDVALUE ( Sheet1[Value] )
    VAR CurrentAcountTable = CALCULATETABLE ( Sheet1, ALLEXCEPT ( Sheet1, Sheet1[Account] ) )
    VAR PreviousDatesTable = FILTER ( CurrentAcountTable, Sheet1[Date] < CurrentDate )
    VAR PreviousDate = MAXX ( PreviousDatesTable, Sheet1[Date] )
    VAR PreviousDateTable = FILTER ( PreviousDatesTable, Sheet1[Date] = PreviousDate )
    VAR PreviousValue = MAXX ( PreviousDateTable, Sheet1[Value] )
    RETURN
        COALESCE ( CurrentValue, PreviousValue )
    Total Colsing Balance = 
    SWITCH (
        TRUE ( ),
        ISINSCOPE ( Sheet1[Account] ) && ISINSCOPE ( 'Date'[Date] ), [Closing Balance],
        ISINSCOPE ( Sheet1[Account] ), SUMX ( VALUES ( 'Date'[Date] ), [Closing Balance] ),
        SUMX ( CROSSJOIN ( VALUES ( 'Date'[Date] ), ALL ( Sheet1[Account] ) ), [Closing Balance] )
    )

     

    • kostask's avatar
      kostask
      Helper II

      Hi, tamerj1 .

      Really very similar and based on the same problem. The solution worked fine.

      The final request came with more than one attributes. I tried to solve it by making changes at ALLEXCEPT  function (added bank and customer),but didn't manage to reach the right result.

      Do I miss something?

       

      Thanks 

      Kostas

      • tamerj1's avatar
        tamerj1
        Community Champion

        kostask 
        we may connect tomorrow via zoom or teams so you can explaing your issue. Meanwhile please check the updated solution above and see if it may help.

  • tamerj1's avatar
    tamerj1
    Community Champion

    Hi kostask 
    Here is the updated solution with correct subtotals https://we.tl/t-ULVbpV6vB9

     

    FinalBalance1 = 
    VAR CurrentDate =
        MAX ( 'Calendar'[Date] )
    VAR IterationTable =
        CALCULATETABLE (
            SUMMARIZE ( 'Totals', 'Totals'[Bank], 'Totals'[Company], 'Totals'[AccountNo] ),
            ALL ( 'Calendar' )
        )
    RETURN
        SUMX (
            IterationTable,
            CALCULATE (
                VAR CurrentValue =
                    SUM ( 'Totals'[FinalBalance] )
                VAR CurrentAcountTable =
                    CALCULATETABLE ( 'Totals', ALL ('Calendar' ) )
                VAR PreviousDatesTable =
                    FILTER ( CurrentAcountTable, 'Totals'[Date] < CurrentDate )
                VAR PreviousDate =
                    MAXX ( PreviousDatesTable, 'Totals'[Date] )
                VAR PreviousDateTable =
                    FILTER ( PreviousDatesTable, 'Totals'[Date] = PreviousDate )
                VAR PreviousValue =
                    SUMX ( PreviousDateTable, 'Totals'[FinalBalance] )
                RETURN
                    - COALESCE ( CurrentValue, PreviousValue )
            )
        )

     

    • kostask's avatar
      kostask
      Helper II

      Amazing solution and great work tamerj1 

      Works perfectly!

      Thank you very much !

      Kostas

  • Hi kostask ,

     

    I did two ways to create a new table

    1. Using DAX

     

    Table 2 =
    var _t= SUMMARIZE('A',[Bank],[AccountNo],[CustomerNo],"Min",MIN('A'[Date]),"Max",MAX('A'[Date]))
    
    var _t2=  CROSSJOIN( _t , CALENDAR(MIN('A'[Date]),MAX('A'[Date])))
    
    return FILTER( _t2,[Date]>=[Min] && [Date]<=[Max])

     

    1. In Power Query:

    Group by --> Add custom column -->Expand and Change type

     

     

    Output:

     

     

    Here is the M code:

     

    let
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("fdA9CsAgDAXgu2QuNEm1nVtXQScRpPe/RlMjFLE4+CTw8fwpBWg9VkZmWOCURYgoW85ZB7iXAmZmWM3WG1bjnNPhz7SelJLk1oyd9BANPdfXE0KQtEr2KZmZGON7rq2EetJu472XNOOrBlN/8H4A", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Date = _t, Bank = _t, CustomerNo = _t, AccountNo = _t, Balance = _t]),
        #"Changed Type with Locale" = Table.TransformColumnTypes(Source, {{"Date", type date}}, "en-GB"),
        #"Changed Type" = Table.TransformColumnTypes(#"Changed Type with Locale",{{"Bank", type text}, {"CustomerNo", Int64.Type}, {"AccountNo", type text}, {"Balance", Int64.Type}}),
        #"Grouped Rows" = Table.Group(#"Changed Type", {"Bank", "CustomerNo", "AccountNo"}, {{"Max", each List.Max([Date]), type nullable date}, {"Min", each List.Min([Date]), type nullable date}}),
        #"Added Custom" = Table.AddColumn(#"Grouped Rows", "Custom", each {Number.From([Min])..Number.From([Max])}),
        #"Expanded Custom" = Table.ExpandListColumn(#"Added Custom", "Custom"),
        #"Changed Type1" = Table.TransformColumnTypes(#"Expanded Custom",{{"Custom", type date}})
    in
        #"Changed Type1"

     

    When the table is created, add a new column:

     

    Balance = CALCULATE(MAX('A'[Balance]),FILTER('A',[Bank]=EARLIER('New Table'[Bank]) && [AccountNo]=EARLIER('New Table'[AccountNo]) && [CustomerNo]=EARLIER('New Table'[CustomerNo]) && [Date]<=EARLIER('New Table'[Date])))

     

    Final output:

     

    Best Regards,

    Jianbo Li

    If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.