Forum Discussion

kazuma6666's avatar
kazuma6666
Helper II
4 years ago
Solved

From one record to multiple records (enumerate dates)

Hello there,

 

I am a beginner in Power BI.

I have a membership table (from Dynamics), and need to do reporting on it. Users will for example ask "How many members of this type do I have in 2021?".

We have multi year membership also (1-6 years). So in the table we have "date begin", "date end".

 

For the user to be able to ask for a specific year, as far as I know, I need to have multiple lines for each multi-year membership.

In the past I would do this in access, and create a new table. For example, a member from 2018 to 2022 will have 5 lines, one for each year. As access has more and more problems, I have to stop using it.

How can I do the same in PowerBI? I basically need to enumerate each year between "date begin" and "date end", then add a line for each year.

 

Example:

Source

membership1    01-01-2018          01-12-2022

 

Destination

membership1    2018

membership1    2019

membership1    2020

membership1    2021

membership1    2022

 

Thanks in advance for your time.

 

PS: this is the first of about a 100 queries I need to do for my membership reporting. Should I ask my management for an SQL server to do the SQL part before sending to PowerBI? From what I have seen online, some really simple things in SQL seems to be completely arcane in Power query.

 

Regards,

 

Benjamin.

 

  • Hi kazuma6666 ,

     

    The answer to your explicit question of how to split out year rows is this: create a new custom column in Power Query and add this as the calculation:

    {Date.Year([startDate])..Date.Year([endDate])}

    Expand the resulting list to new rows and it should duplicate rows for each year covered.

     

    However, the answer to your tacit question is this: You don't need to split out anything into year rows. You need to create a proper calendar table, use this to slice your report for, say, year, then write measures that count the distinct number of memberID's where [startDate] <= MIN(calendar[Date]) and [endDate] >= MAX(calendar[Date]).

    There's a bit more to it than this depending on exactly how you want to report, but this is the correct way to leverage Power BI's skills, not by duplicating data rows.

     

    Pete

  • BA_Pete's avatar
    BA_Pete
    4 years ago

    Hello again 🙂

     

    For this example, you won't have a relationship between your calendar table and your fact table.

     

    Your measures should look something like this:

     

    This measure will count a membership as being active within your selected timeframe if it has been active AT ANY POINT within that timeframe:

    _noofActiveMemberships_Partial =
    CALCULATE(
      DISTINCTCOUNT(factTable[membershipID]),
      FILTER(
        factTable,
        factTable[startDate] <= MAX(calendar[date])
        && factTable[endDate] >= MIN(calendar[date])
      )
    )

     

    This measure will only count a membership as being active if it spans the ENTIRE timeframe:

    _noofActiveMemberships_Complete =
    CALCULATE(
      DISTINCTCOUNT(factTable[membershipID]),
      FILTER(
        factTable,
        factTable[startDate] <= MIN(calendar[date])
        && factTable[endDate] >= MAX(calendar[date])
      )
    )

     

    Use the timeframes ([Year], [Month], [Date] etc.) from your calendar table in your visuals along with these measures and it should do what you need.

     

    Pete

  • BA_Pete's avatar
    BA_Pete
    4 years ago

    kazuma6666 ,

     

    I think you may need to review your relationships and see if you can reasonably update this table to a MANY type.

    This is now essentially a fact table, so would not be expected to operate as the ONE side of any relationships.

     

    Pete

  • BA_Pete's avatar
    BA_Pete
    4 years ago

    kazuma6666 ,

     

    Ok, the relationship itself seems fine.

     

    Check that your calendar table spans all the dates in your fact table and vice versa.

    Check that you have marked your calendar table as the date table for the model (right-click calendar in field list and go to 'Mark as date table').

    Check that your calendar table has been properly created and contains a contiguous list of dates as the [Date] column.

    Double-check that you are using the Calendar[Year] column correctly in your slicer.

     

    Beyond this, I would probably need to look at the actual PBIX itself to troubleshoot as could be one of a hundred little variables causing the issue.

     

    Pete

     

  • BA_Pete's avatar
    BA_Pete
    4 years ago

    kazuma6666 ,

     

    TA DA!

     

     

    Your [SubsDateList] data type is wrong. You have it set as Text, but you need to change it in Power Query to Date type.

     

    When you have finished building your queries in PQ, ALWAYS ALWAYS ALWAYS go through all of your table columns and assign them the correct data type.

    For example, your calendar table is almost completely untyped columns.

     

     

    Go through all of your query columns and, where you see ABC123, click on this little icon and select the correct data type before applying back to the model. It will save you (and possible me!) a billion headaches in future!

     

    Pete

33 Replies

  • Hi kazuma6666 ,

     

    The answer to your explicit question of how to split out year rows is this: create a new custom column in Power Query and add this as the calculation:

    {Date.Year([startDate])..Date.Year([endDate])}

    Expand the resulting list to new rows and it should duplicate rows for each year covered.

     

    However, the answer to your tacit question is this: You don't need to split out anything into year rows. You need to create a proper calendar table, use this to slice your report for, say, year, then write measures that count the distinct number of memberID's where [startDate] <= MIN(calendar[Date]) and [endDate] >= MAX(calendar[Date]).

    There's a bit more to it than this depending on exactly how you want to report, but this is the correct way to leverage Power BI's skills, not by duplicating data rows.

     

    Pete

    • kazuma6666's avatar
      kazuma6666
      Helper II

      BA_Pete 

      Thanks for the answer. Especially the explanations about a calendar table. I much prefer finding the correct way to do this instead of just doing the way I always did it.

       

      I have no more time today, but will try to implement this Thursday. 

    • kazuma6666's avatar
      kazuma6666
      Helper II

      Hello again BA_Pete ,

       

      I'm trying to get your second solution working. I have created a date table (using this explanation: https://blog.crossjoin.co.uk/2013/11/19/generating-a-date-dimension-table-in-power-query/). If I understand right, I should use these dates for my CountMembers measure. I am not sure what to use for my measure in this case.

      I think what the measure needs to do is look at the input date, and output all the members who have this date between [date begin] and [date end] of their membership. Is that what's needed, or did I miss something?

      Is there a specific function I can use that does that?

      Thanks in advance for your time!

       

      PS: If you have a link to an explanation/tutorial about this, that would be perfect too!

      PPS: Should I create a new topic for this question?

      • BA_Pete's avatar
        BA_Pete
        Super User

        Hello again 🙂

         

        For this example, you won't have a relationship between your calendar table and your fact table.

         

        Your measures should look something like this:

         

        This measure will count a membership as being active within your selected timeframe if it has been active AT ANY POINT within that timeframe:

        _noofActiveMemberships_Partial =
        CALCULATE(
          DISTINCTCOUNT(factTable[membershipID]),
          FILTER(
            factTable,
            factTable[startDate] <= MAX(calendar[date])
            && factTable[endDate] >= MIN(calendar[date])
          )
        )

         

        This measure will only count a membership as being active if it spans the ENTIRE timeframe:

        _noofActiveMemberships_Complete =
        CALCULATE(
          DISTINCTCOUNT(factTable[membershipID]),
          FILTER(
            factTable,
            factTable[startDate] <= MIN(calendar[date])
            && factTable[endDate] >= MAX(calendar[date])
          )
        )

         

        Use the timeframes ([Year], [Month], [Date] etc.) from your calendar table in your visuals along with these measures and it should do what you need.

         

        Pete

  • BA_Pete 

    Thanks for your solution. It is now implemented (the simple version) and works perfectly 🙂

     

    Greg_Deckler 

    I also accepted your solution, but I'm a real beginner in PowerBI. I could not test it, as I don't really know how to use it right now. I'll learn at some point.

  • hello again,

     

    I have come back to this project, but for some reason my custom column 

     

    {Date.Year([startDate])..Date.Year([endDate])}

     

    gives me an error now. This is the error:

    Expression.Error: A cyclic reference was encountered during evaluation.

    this is the line that gives the error:

     

    = Table.AddColumn(#"Renamed Columns3", "year_membership", each {Date.Year(si_membershipsubscribers[creation date])..Date.Year(si_membershipsubscribers[Valid to])})

     

    Does anyone have an idea why this doesn't work anymore?

    Thanks in advance!

    • kazuma6666's avatar
      kazuma6666
      Helper II

      I have found the reason for the cyclic error. I need to do this before renaming or reordering columns, otherwise it gives me the error.

      Just in case someone else has the error.

      • BA_Pete's avatar
        BA_Pete
        Super User

         

        Kudos for keeping the thread updated with your findings to help others in the future. Good job 🙂

         

        Pete