To better measure financial performance across departments, our client asked us to create a dashboard in Power BI that displays year-over-year general ledger (GL) account balances, using the GL data they have stored within Microsoft Dynamics GP. This seemed simple enough, but turns out tables using Dynamics GP datasets require a lot of data manipulation to produce helpful visualizations in Power BI. I’ve provided the methodology we used to optimize Dynamics GP data to produce an intuitive table for creating a GL account summary dashboard.Creating an Efficient Table to Load Into PowerBI I started with this resource to first create a GL account summary table that includes the Dynamics GP datasets I wanted in my table: the beginning balance, ending balance, and net change throughout the months.Typical GL Trial Balance Although the table above contains the datasets I desired, the formatting of the data would require Power BI to perform row level aggregation and unnecessary data manipulation in a SQL view to produce dashboard visualizations that made sense to the end user. Instead, it would be more efficient and user-friendly to retain data structures from Dynamics GP and perform the aggregations within SQL views on the backend, as opposed to making Power BI and its end users do the work on the front end.When attempting to write a SQL view to perform the aggregations, the first issue I ran into was that not all ending balances for accounts are calculated the same. For example, all income statement accounts are to be calculated starting at $0.00 on the first day of the fiscal year; whereas balance sheet accounts have rolling balances from year to year. To further complicate our scenario, account specific information, which is normally available in the Dynamics GP table, was not in their system—it was provided to us as a separate flat file. In this scenario, the relevant account information (balance sheet and non-balance sheet) was included in the AccountType column within the separate flat file.With this knowledge, I created a SQL view and divided it into two parts: balance sheet and non-balance sheet accounts.SQL used to create my STG view:The first part of the view is a common table expression (CTE) that calculates the cumulative balance of all non-balance sheet accounts. This CTE was broken into two parts to get both current and historical accounts summary information. To arrive at the cumulative balance, I performed a windowing function SUM on the Dynamics GP field PERDBLNC, with a partition by ACTINDX and year being ordered by period. As a result, when the user filters on period 12 (final period of the year), the dashboard displays the cumulative balance. Noting that PERIODID = 0 is used for balance sheet accounts, which Dynamics GP stores the previous year balance, I chose to filter out all period 0’s and any balance sheet account types for this CTE.STG View Part 1: Non-Balance Sheet AggregationCREATE VIEW [STG].[v_Fact_GLSnapshot] AS WITH CumulativeBalance_CTE AS (–All non balance sheetClick to view full SQLSELECTLTRIM(RTRIM(AIM.ACTNUMST)) AS AccountNumber,AIM.ACTINDX,RTRIM(ACSM.YEAR1) AS FiscalYear,CASE WHEN ACSM.PERIODID = 0 THEN DATEFROMPARTS(RTRIM(ACSM.[YEAR1])-1,12,31) ELSE DATEFROMPARTS(RTRIM(ACSM.[YEAR1]),ACSM.[PERIODID],1) END AS PeriodStartDate,ACSM.DEBITAMT AS DebitAmount,ACSM.CRDTAMNT AS CreditAmount,ACSM.PERIODID,ACSM.PERDBLNC,SUM(ACSM.PERDBLNC) OVER (PARTITION BY ACSM.ACTINDX, YEAR1 ORDER BY ACSM.PERIODID ASC) AS CumulativeBalanceFROM GL10110 AS ACSM –Account Current Summary Master LEFT JOIN GL00105 AS AIM –Account Index Master ON ACSM.ACTINDX = AIM.ACTINDXLEFT JOIN ChartOfAccounts COA –Chart Of Accounts Flat File ON AIM.ACTNUMST = COA.AccountWHERE COA.AccountType != ‘Balance Sheet’AND ACSM.PERIODID != 0 UNION SELECTLTRIM(RTRIM(AIM.ACTNUMST)) AS AccountNumber,AIM.ACTINDX,RTRIM(ASH.YEAR1) AS FiscalYear,CASE WHEN ASH.PERIODID = 0 THEN DATEFROMPARTS(RTRIM(ASH.[YEAR1])-1,12,31) ELSE DATEFROMPARTS(RTRIM(ASH.[YEAR1]),ASH.[PERIODID],1) END AS PeriodStartDate,ASH.DEBITAMT AS DebitAmount,ASH.CRDTAMNT AS CreditAmount,ASH.PERIODID,ASH.PERDBLNC,SUM(ASH.PERDBLNC) OVER (PARTITION BY ASH.ACTINDX, YEAR1 ORDER BY ASH.PERIODID ASC) AS CumulativeBalanceFROM GL10111 AS ASH –Account Summary History LEFT JOIN GL00105 AS AIM –Account Index Master ON ASH.ACTINDX = AIM.ACTINDXLEFT JOIN ChartOfAccounts COA –Chart Of Accounts Flat File ON AIM.ACTNUMST = COA.AccountWHERE COA.AccountType != ‘Balance Sheet’AND ASH.PERIODID != 0 ), The second part of the view is a CTE to calculate the cumulative balance for balance sheet accounts. Almost the same calculations noted above are being performed in this CTE; however, I am no longer excluding PERIODID = 0, because this period contains the cumulative balance of the previous year and is needed in the current year calculation. Additionally, this CTE is filtered to only include account types defined as balance sheet.STG View Part 2: Balance Sheet AggregationCumulativeBalance_CTE2 AS (–All balance sheetClick to view full SQLSELECTLTRIM(RTRIM(AIM.ACTNUMST)) AS AccountNumber,AIM.ACTINDX,RTRIM(ACSM.YEAR1) AS FiscalYear,CASE WHEN ACSM.PERIODID = 0 THEN DATEFROMPARTS(RTRIM(ACSM.YEAR1)-1,12,31) ELSE DATEFROMPARTS(RTRIM(ACSM.YEAR1),ACSM.[PERIODID],1) END AS PeriodStartDate,ACSM.DEBITAMT AS DebitAmount,ACSM.CRDTAMNT AS CreditAmount,ACSM.PERIODID,ACSM.PERDBLNC,SUM(ACSM.PERDBLNC) OVER (PARTITION BY ACSM.ACTINDX, YEAR1 ORDER BY ACSM.PERIODID ASC) AS CumulativeBalanceFROM GL10110 AS ACSM –Account Current Summary Master LEFT JOIN GL00105 AS AIM –Account Index Master ON ACSM.ACTINDX = AIM.ACTINDXLEFT JOIN ChartOfAccounts COA –Chart of Accounts Flat File ON AIM.ACTNUMST = COA.AccountWHERE COA.AccountType = ‘Balance Sheet’ UNION SELECTLTRIM(RTRIM(AIM.ACTNUMST)) AS AccountNumber,AIM.ACTINDX,RTRIM(ASH.YEAR1) AS FiscalYear,CASE WHEN ASH.PERIODID = 0 THEN DATEFROMPARTS(RTRIM(ASH.YEAR1)-1,12,31) ELSE DATEFROMPARTS(RTRIM(ASH.YEAR1),ASH.[PERIODID],1) END AS PeriodStartDate,ASH.DEBITAMT AS DebitAmount,ASH.CRDTAMNT AS CreditAmount,ASH.PERIODID,ASH.PERDBLNC,SUM(ASH.PERDBLNC) OVER (PARTITION BY ASH.ACTINDX, YEAR1 ORDER BY ASH.PERIODID ASC) AS CumulativeBalanceFROM GL10111 AS ASH –Account Summary History LEFT JOIN GL00105 AS AIM –Account Index Master ON ASH.ACTINDX = AIM.ACTINDXLEFT JOIN ChartOfAccounts COA –Chart of Accounts Flat File ON AIM.ACTNUMST = COA.AccountWHERE COA.AccountType = ‘Balance Sheet’ )The final part of the view is to combine the above two CTEs while also adding: an Active column, ISNULL to PeriodEndBalance, and PeriodBeginBalance.STG View Part 3: Non-Balance Sheet & Balance Sheet UnionSELECT CBAL.FiscalYear,Click to view full SQL CBAL.PERIODID AS FiscalPeriod, CBAL.PeriodStartDate, CBAL.AccountNumber, CBAL.DebitAmount, CBAL.CreditAmount, CASE WHEN AM.ACTIVE = 1 THEN ‘Yes’ WHEN AM.ACTIVE = 0 THEN ‘No’ ELSE ‘Default’ END AS Active ,ISNULL(CBAL.CumulativeBalance,0) AS PeriodEndBalance ,ISNULL(CBAL.CumulativeBalance,0) – CBAL.PERDBLNC AS PeriodBeginBalance ,CBAL.PERDBLNC AS PeriodNetChangeFROM CumulativeBalance_CTE CBAL –CTE LEFT JOIN GL00100 AS AM –Account Master ON CBAL.ACTINDX = AM.ACTINDX UNION ALL SELECT CBAL2.FiscalYear, CBAL2.PERIODID AS FiscalPeriod, CBAL2.PeriodStartDate, CBAL2.AccountNumber, CBAL2.DebitAmount, CBAL2.CreditAmount, CASE WHEN AM.ACTIVE = 1 THEN ‘Yes’ WHEN AM.ACTIVE = 0 THEN ‘No’ ELSE ‘Default’ END AS Active ,ISNULL(CBAL2.CumulativeBalance,0) AS PeriodEndBalance ,ISNULL(CBAL2.CumulativeBalance,0) – CBAL2.PERDBLNC AS PeriodBeginBalance ,CBAL2.PERDBLNC AS PeriodNetChangeFROM CumulativeBalance_CTE2 CBAL2 –CTE2 LEFT JOIN GL00100 AS AM –Account Master ON CBAL2.ACTINDX = AM.ACTINDX GO It’s a hefty query, but once executed, the resulting view provides me with all the columns I want. Here’s an example output for a non-balance sheet and balance sheet account:STG View Part Output Example The Issue: Missing PeriodsThe query works great for the non-balance sheet and balance sheet calculations; however, now we see that the accounts have missing period information for 2, 4, 5, 7, 10, 11, and 12 (on non-balance sheet account) and 1-12 (on the balance sheet account). In this example, we need period 12 because we want Power BI to filter on that period to get the GL account summary for the year. After digging, I found that periods do not exist in Dynamics GP when there is no account activity for the period.To work around this Dynamics GP feature, I added two SQL queries that will execute in the ETL process I have in place to load the staging table from the view.1.) The first query is related to non-balance sheet accounts. The query will search for any accounts that do not have a period 12, then roll up the most recent period and create a period 12 with the most recent period end balance. This ensures when Power BI is looking at period 12 for the year summary all accounts will be included even if they had no activity in period 12.ETL Query #1: Non-Balance Sheet Missing Period 12withCTE1 as (SELECT Click to view full SQL AccountNumber, FiscalYear, MAX(FiscalPeriod) as LatestPeriod FROM STG.t_Fact_GLSnapshot GROUP BY AccountNumber, FiscalYear ), CTE2 AS (SELECT GLSnapshotID, AccountNumber, FiscalYear, FiscalPeriod, PeriodEndBalance, PeriodStartDate, DebitAmount, CreditAmount, Active, PeriodBeginBalance, PeriodNetChange,FROM STG.t_Fact_GLSnapshot CTE2), CTE3 as (SELECT CTE2.GLSnapshotID, COA.PillarGroup, CTE1.AccountNumber, CTE1.FiscalYear, CTE1.LatestPeriod, CTE1.PeriodEndBalance, CTE1.PeriodStartDate, CTE1.DebitAmount, CTE1.CreditAmount, CTE1.Active, CTE1.PeriodBeginBalance, CTE1.PeriodNetChange, FROM CTE1 LEFT JOIN CTE2 ON CTE1.AccountNumber = CTE2.AccountNumber AND CTE1.FiscalYear = CTE2.FiscalYear AND CTE1.LatestPeriod = CTE2.FiscalPeriod LEFT JOIN ChartOfAccounts COA ON CTE2.AccountNumber = COA.Account WHERE CTE1.LatestPeriod != ’12’ AND COA.PillarGroup != ‘Balance Sheet’) Insert Into STG.t_Fact_GLSnapshot (GLSnapshotID, FiscalYear, FiscalPeriod, PeriodStartDate, AccountNumber, DebitAmount, CreditAmount, Active, PeriodEndBalance, PeriodBeginBalance, PeriodNetChange, DataSourceID, STGLoadDateUTC, AuditBatchLoadID) SELECT GLSnapshotID FiscalYear, ’12’ as FiscalPeriod, PeriodStartDate, AccountNumber, DebitAmount, CreditAmount, Active, PeriodEndBalance, PeriodBeginBalance, PeriodNetChange,FROM CTE3 2.) The second query is related to balance sheet accounts. The query will search for any accounts that do not have a period 12, then will update the period net change as a 0 in the created period 12. This is needed because balance sheet accounts have a rolling balance from year to year, and the period net change will affect the balance total in future years. As such, the period net change for the created period 12 is to be 0, accurately reflecting the actual net change for those periods when there was no activity.ETL Query #2: Balance Sheet Missing Period 12withCTE1 as (SELECT Click to view full SQL AccountNumber, FiscalYear, MAX(FiscalPeriod) as LatestPeriod FROM STG.t_Fact_GLSnapshot GROUP BY AccountNumber, FiscalYear ), CTE2 AS (SELECT GLSnapshotID, AccountNumber, FiscalYear, FiscalPeriod, PeriodEndBalance, PeriodStartDate, DebitAmount, CreditAmount, Active, PeriodBeginBalance, PeriodNetChange, FROM STG.t_Fact_GLSnapshot CTE3), CTE3 as (SELECT CTE2.GLSnapshotID, COA.PillarGroup, CTE1.AccountNumber, CTE1.FiscalYear, CTE1.LatestPeriod, CTE2.PeriodEndBalance, CTE2.PeriodStartDate, CTE2.DebitAmount, CTE2.CreditAmount, CTE2.Active, CTE2.PeriodBeginBalance, CTE2.PeriodNetChange, FROM CTE1 LEFT JOIN CTE2 ON CTE1.AccountNumber = CTE2.AccountNumber AND CTE1.FiscalYear = CTE2.FiscalYear AND CTE1.LatestPeriod = CTE2.FiscalPeriod LEFT JOIN ChartOfAccounts COA ON CTE2.AccountNumber = COA.Account WHERE CTE1.LatestPeriod != ’12’ AND COA.PillarGroup = ‘Balance Sheet’) Insert Into STG.t_Fact_GLSnapshot (GLSnapshotID, FiscalYear, FiscalPeriod, PeriodStartDate, AccountNumber, DebitAmount, CreditAmount, Active, PeriodEndBalance, PeriodBeginBalance, PeriodNetChange) SELECT GLSnapshotID, FiscalYear, ’12’ as FiscalPeriod, PeriodStartDate, AccountNumber, DebitAmount, CreditAmount, Active, PeriodEndBalance, PeriodBeginBalance, 0.00 as PeriodNetChange,FROM CTE4 After executing the above view and two insert queries during the ETL process, we get a more complete table with period 12 now accounted for (since there is no change over periods that do not exist, I chose to not worry about those and only focus on period 12 for purposes of the dashboard):Post ETL Table Output Example Changing Negative Values to PositivesThere is one more cosmetic change I wanted to make for the BI dashboard to display the data more clearly. I noticed for all accounts that are increased in Dynamics GP by a credit, they show up as a negative value which could make for a confusing dashboard. To reflect these accounts as positive values, I created another view and added a calculation to the PeriodEndBalance and PeriodBeginBalance. This calculation multiples the total value by “-1” for any liability, retained earnings, and revenue account types. See below for the query I used in this view.Final Table Cosmetic ChangesCREATE VIEW [FACT].[v_GLSnapshot] ASClick to view full SQL SELECT GLS.FiscalYear, GLS.FiscalPeriod, GLS.PeriodStartDate, GLS.AccountNumber, (GLS.DebitAmount) AS DebitAmount, (GLS.CreditAmount) AS CreditAmount, CASE WHEN COA.AccountType IN (‘Liability’,‘Retained Earnings’,‘Revenue’) THEN -1.0 * (GLS.PeriodEndBalance) ELSE GLS.PeriodEndBalance END AS PeriodEndBalance, CASE WHEN COA.AccountType IN (‘Liability’,‘Retained Earnings’,‘Revenue’) THEN -1.0 * (GLS.PeriodBeginBalance) ELSE (GLS.PeriodBeginBalance) END AS PeriodBeginBalance, (GLS.PeriodNetChange) AS PeriodNetChangeFROM STG.t_Fact_GLSnapshot GLS LEFT JOIN ChartOfAccounts COA ON GLS.AccountNumber = COA.AccountNumber Loading a Well-Designed Table for an Intuitive Data VisualizationFrom this view, we’re ready to load the table into our BI dashboard. Once loaded, we set the filter to Period 12, and the summary total for all accounts (balance sheet and income statement) are accurately presented. In the below example, you can clearly see revenue, expense, and retained earning account types, and the values are all positive.Final Data Visualization with Optimized Data Load No aggregations were performed in PowerBI to create this dashboard, and only one filter is needed. If the original Standard GL Trial Balance table above was loaded, Power BI would have had to aggregate the data, and multiple filters would have been necessary to arrive at such an intuitive dashboard. In this case, with a simple Period filter set to 12, we see GL account totals for the year.We created an optimized GL account summary table for Power BI, and our client now has the visuals they need to quickly understand their financials and make timely business decisions. I hope this helps anyone running into issues when creating a GL account summary table in Dynamics GP. Please share other effective approaches you may have used!Need help with software evaluation and selection?With the analytics industry changing at such a rapid pace, we know it’s a challenge to keep up with new features and technologies. As data and analytics consultants, we have experience with a wide range of BI products and can help you cut through the noise to determine which tools can solve the problems you’re facing.Talk With a Data Analytics Expert"*" indicates required fieldsFirst Name* First Last Name* Last Email* Phone Number*Job PositionPlease SelectIT- DeveloperIT- AnalystIT- Systems EngineerIT- ManagerIT- Dir/VPCIOCOOCTOMarketing- PractitionerMarketing- MgrMarketing- Dir/ VPMarketing- CMOSales- ProfessionalSales- Mgr/DirSales- VP/ExecProject ManagerFinance- ProfessionalFinance- Mgmt/ ExecCEO/PresidentConsultantCustomer ServiceJob Seeker/StudentOtherCompany Name*Company Location*Please SelectUnited StatesCanadaAustriaBelgiumBulgariaCroatiaCyprusGreeceDenmarkLuxembourgIrelandHungaryFinlandFranceGermanyPortugalPolandItalySpainNetherlandsSwedenSlovakiaSouth AfricaSwitzerlandAustraliaUnited KingdomNew ZealandMexicoEthiopiaPhilippinesSwazilandKenyaLiberiaIndonesiaSaudi ArabiaTrinidad and TobagoColombiaSyriaPeople's Republic of ChinaUnited Arab EmiratesKoreaNigeriaNepalAlgeriaPakistanGhanaChileHong KongArgentinaCzech RepublicPeruSierra LeoneIvory CoastKuwaitZimbabweRwandaBrazilIranUgandaEcuadorEgyptCameroonMauritiusAlbaniaIsraelSaint Kitts and NevisJapanTurkeyRomaniaSloveniaBangladeshSingaporeTunisiaIndiaLithuaniaUkraineGuatemalaNorwayRussiaMalaysiaBoliviaSerbiaUruguaySenegalDominicaChinaVietnamBahrainYemenEast TimorBelarusPalestinian TerritoryMaltaPanamaTaiwanQatarMadagascarLebanonJamaicaChristmas IslandSudanAndorraHaitiEstoniaAntigua and BarbudaKazakhstanPuerto RicoCosta RicaGuamSomaliaSri LankaBermudaTogoJerseyMayotteAmerican SamoaLatviaBahamasOmanEl SalvadorAfghanistanBotswanaSouth SudanCôte d'IvoireMoroccoChadThailandVenezuelaAngolaArmeniaAntarcticaGambiaCubaGrenadaAnguillaBeninBurkina FasoMontserratZambiaCuracaoNorth KoreaBonaire, Saint Eustatiusand SabaAland IslandsFrench PolynesiaDemocratic Republic of the CongoMaliHondurasCentral African RepublicRepublic of the CongoBarbadosNigerRussian FederationNicaraguaCocos (Keeling) IslandsFrench GuianaMontenegroTanzaniaNamibiaJordanUnited States MinorOutlying IslandsDominican RepublicIcelandFijiBurundiArubaIraqMacedoniaBruneiMongoliaParaguayPapua New GuineaCambodiaMalawiSolomon IslandsTongaAzerbaijanSan MarinoGeorgiaDjiboutiUzbekistanState*Please SelectAlabamaAlaskaAmerican SamoaArizonaArkansasCaliforniaColoradoConnecticutDelawareDistrict of ColumbiaFloridaGeorgiaGuamHawaiiIdahoIllinoisIndianaIowaKansasKentuckyLouisianaMaineMarylandMassachusettsMichiganMinnesotaMississippiMissouriMontanaNebraskaNevadaNew HampshireNew JerseyNew MexicoNew YorkNorth CarolinaNorth DakotaNorthern Mariana IslandsOhioOklahomaOregonPennsylvaniaPuerto RicoRhode IslandSouth CarolinaSouth DakotaTennesseeTexasUtahU.S. Virgin IslandsVermontVirginiaWashingtonWest VirginiaWisconsinWyomingArmed Forces AmericasArmed Forces EuropeArmed Forces PacificProvince*Please SelectAlbertaBritish ColumbiaManitobaNew BrunswickNewfoundland and LabradorNorthwest TerritoriesNova ScotiaNunavutOntarioPrince Edward IslandQuebecSaskatchewanYukonHow did you hear about us?Comments*By checking this box, you agree to our Privacy Policy, and we may contact you about our products and services. You can opt out of our communications at any time by visiting our Subscription Center.By checking this box, you agree to our Privacy Policy, and we may contact you about our products and services. You can opt out of our communications at any time by visiting our Subscription Center. I agree to receive communications from Analytics8.CAPTCHANameThis field is for validation purposes and should be left unchanged.