Correct data errors that prevent Management Reporter integration

This article provides a script to correct data errors that prevent Management Reporter integration.

Applies to:   Microsoft Dynamics SL 2011 Service Pack 2, Microsoft Dynamics SL 2011 Service Pack 1, Microsoft Dynamics SL 2011, Microsoft Dynamics SL 2015
Original KB number:   2931999

Summary

This article provides steps to run a Diagnostics.sql script for Management Reporter 2012 for Microsoft Dynamics SL 2011 and Dynamics SL 2015. This script can identify data errors that may prevent successful Management Reporter integration. Data errors can originate from many sources and may cause inconsistency between tables or create invalid field values.

At the bottom of this article, there are also a couple scripts used to find lowercase data that may cause issues in MR.

Resolution

Download the following script file, and then follow these steps to run the scripts against the Microsoft Dynamics SL Application database in Management Reporter. Change the output type to Text Output for easier viewing.

MR4.zip

Note

This same information is contained in the Diagnostics4.Sql file, which is included in the MR4.zip file.

Important

Always make a database backup before you update any data in Management Studio.

Step 1

  • Do you have more than one currency ID set up?

    Select 'Step1a', CASE WHEN COUNT(*)>1 then 'YES' else 'NO' end, count(*) from currncy with (nolock)
    

    Note

    • No = single currency
    • Yes = multiple currencies that are set up in Currency Maintenance and have the number listed.
  • Is multicurrency enabled?

    Select top 1 'Step1b',case isnull((select MAX(mcactivated) from cmsetup),-99) WHEN 1 then 'ENABLED' when -99 then 'NOT SETUP' else 'NOT ENABLED' end
    

Note

This script returns either Enabled or Not Set Up.

Step 2

Look for a bad currency setup record. Evaluate each situation. For help with doing this, contact Microsoft Dynamics Technical Support.

  • This should be the base currency of the application database:

    Select 'Step2a',BaseCuryId from glsetup with (nolock)
    
  • The Base currency of the Actual ledger (balance type = 'a') should be the base currency of the database.

    Select 'Step2b',BaseCuryID,LedgerID, BalanceType from ledger with (nolock)
    
  • The BaseCuryID field of all companies in a given application database should all be the same.

  • This script shows the BaseCuryID field of all application databases that are associated with the System database.

    Select 'Step2c',BaseCuryID, CpnyID, databasename from vs_company with (nolock)
    
  • The BaseCuryIDs field should exist in the currency maintenance table. Any foreign currencies should also exist in this table.

    Select 'Step2d',curyid from currncy with (nolock)
    

Step 3

Look for incorrect values for the CuryID and ledgerID fields in the transaction and summary records. These statements access only the top 100 records. To see all records, remove the words top 100 from the script.

  • Accthist that has a currency ID that is not in the currency maintenance table.

    Select top 100 'Step3a',CpnyID, LedgerID, FiscYr, Acct, SUB, CuryId, * from accthist with (nolock) where CuryId not in (select CuryId from Currncy with (nolock))
    

    Fix: You may need to update the CuryID field to match the BaseCuryID field. However, that record may already exist. In this case, you receive a 6909 message. If this occurs, determine whether the record is required.

  • Accthist that has a currency ID that does not match the ledger record (or for a ledger that is not in the ledger table).

    Select top 100 'Step3b',a.CpnyID, a.LedgerID, a.FiscYr, a.Acct, a.SUB, a.CuryId, l.BaseCuryID,* from accthist a with (nolock) left join Ledger l with (nolock) on a.LedgerID=l.LedgerID where l.LedgerID is null OR l.BaseCuryID<>a.CuryId
    

    Fix: The update depends on each situation.

  • CuryAcct that has a CuryID not in the currency maintenance table.

    Select top 100 'Step3c',CpnyID, LedgerID, FiscYr, Acct, SUB,BaseCuryID, CuryId, * from curyacct with (nolock) where CuryId not in (select CuryId from Currncy with (nolock))
    

    Fix: The update will depend on each situation. You may have to delete the record later if there is no corresponding AcctHist record. Also, you may have to update the CuryID field. However, that record may already exist. In this case, you receive a 6909 message. If this occurs, determine whether the record is needed.

  • CuryAcct with a BasecuryID that does not match the ledger record (or for a ledger that is not in the ledger table).

    Select top 100 'Step3d',c.CpnyID, c.LedgerID, c.FiscYr, c.Acct, c.SUB,c.BaseCuryID, c.CuryId,l.BaseCuryID, * from curyacct c with (nolock) left join Ledger l with (nolock) on c.LedgerID=l.LedgerID where l.LedgerID is null OR c.BaseCuryID<>l.BaseCuryId
    

    Fix: The update depends on each situation.

  • GLTran with a CuryID not in the currency maintenance table.

    Select top 100 'Step3e',CpnyID, LedgerID, FiscYr, Acct, SUB,BaseCuryID, CuryId,* from gltran with (nolock) where Posted='P' and CuryId not in (select CuryId from Currncy)
    

    Fix: The update depends on each situation. You may need to update the CuryId field to a valid value.

  • GLTran with a BaseCuryID field value that does not match the ledger record (or for a ledger that is not in the ledger table).

    Select top 100 'Step3f',g.CpnyID, g.LedgerID, g.FiscYr, g.Acct, g.SUB, g.BaseCuryID, g.CuryId, * from gltran g with (nolock) left join Ledger l with (nolock) on g.LedgerID=l.LedgerID where g.Posted='P' and g.LedgerID is null OR l.BaseCuryID<>g.BaseCuryId
    

    Fix: Update will depend on each situation. You may need to update the BaseCuryID field to a valid value.

Step 4

Look for mismatched summary records.

  • Find CuryAcct records without AcctHist records.

    Select top 100 'Step4a',c.CpnyID, c.LedgerID, c.FiscYr, c.Acct, c.Sub, c.BaseCuryID, c.CuryId,* from CuryAcct c with (nolock) left join AcctHist a with (nolock) on c.CpnyID=a.CpnyID and c.Acct=a.Acct and c.Sub=a.Sub and c.LedgerID=a.LedgerID and c.FiscYr=a.FiscYr where a.CpnyID is null order by c.CpnyID, c.Acct, c.SUB, c.ledgerid, c.FiscYr
    

    Fix: Run the Fix4a.SQL script from MR2.zip on both single-currency and multi-currency databases if errors are reported.

  • Find Accthist without CuryAcct records.

    Select top 100 'Step4b',a.CpnyID, a.LedgerID, a.FiscYr, a.Acct, a.Sub, a.CuryId, * from AcctHist a with (nolock) left join Curyacct c with (nolock) on c.CpnyID=a.CpnyID and c.Acct=a.Acct and c.Sub=a.Sub and c.LedgerID=a.LedgerID and c.FiscYr=a.FiscYr where a.BalanceType='A' and c.CpnyID is null order by a.CpnyID, a.Acct, a.SUB, a.ledgerid, a.FiscYr
    

    Fix: For multicurrency databases, either initialize a curyacct record in Initialization mode in GL > Account History or post a transaction to the acct/sub/ledger/fiscyr/cpnyid/curyid. To create or update a curyacct record in GL > Account History > Currency tab, you must enter the data for each period. When you create a batch to post a transaction to the account, this should create a CuryAcct record that contains values for each period. Make sure that you use the year in which the error is reported as the year for posting. Then, reverse the batch to remove the dollars out of the account.

    For a single-currency database, open the record in GL > Account History during initialization mode if there are only one or two records. Change the beginning balance by some amount, save the record, revert it, and then save again. This creates the curyacct record. Or, you can run the script from step 6a in this section.

  • GLTrans without AcctHist

    This query will run slowly if there are many gltrans entries and if all the entries are valid. (The query actually runs faster if there is bad data.)

    Select top 100 'Step4c',g.CpnyID, g.LedgerID, g.FiscYr, g.Acct, g.Sub, g.BaseCuryID, g.CuryId, * from GLTran g with (nolock) left join AcctHist a with (nolock) on g.CpnyID=a.CpnyID and g.Acct=a.Acct and g.Sub=a.Sub and g.LedgerID=a.LedgerID and g.FiscYr=a.FiscYr inner join vs_company c with (nolock) on g.CpnyID=c.CpnyID and c.CpnyCOA in (select CpnyID from glsetup with (nolock)) -- only companies in this application DB where g.posted='P' and a.CpnyID is null order by g.CpnyID, g.LedgerID, g.FiscYr, g.Acct, g.Sub option (force order) -- added for performance in larger databases
    

    Fix: Evaluate the GLtrans field entries. If there is no AcctHist record, the financial isn't using these transactions for reports.

  • This is typically because the transactions are old. You may decide to delete them or take some other action. Evaluate these entries carefully.

Step 5

Look for GLTrans records that have invalid dates or periods. Such records can cause the following errors in Management Reporter:

  • Error text: Year, Month, and Day parameters describe an unrepresentable DateTime.

  • Error text: Object reference is not set to an instance of an object.

  • GLTrans records that have a blank FiscYr field.

    Select top 100 'Step5a',CpnyID, LedgerID, FiscYr, Acct, Sub, perpost, perent, trandate, Posted, Rlsed, BatNbr, Module, * from GLTran with (nolock) where FiscYr='' and (Rlsed=1 or Posted='P')
    

    Fix: Consider updating the FiscYr field based on the perpost value.

  • GLTrans records that have a perpost value that is far outside a normal range.

    Select top 100 'Step5b',CpnyID, LedgerID, FiscYr, Acct, Sub, perpost, perent, trandate, Posted, Rlsed, BatNbr, Module, * from GLTran with (nolock) where (PerPost>='204812' or PerPost<='195001') and (Rlsed=1 or Posted='P')
    

    Fix: These batches will all likely have a future period to post. You can open these batches in GL > Journal Transactions during Initialization mode. Either delete them, change the period to post, or process them, as appropriate.

  • GLTrans records that have a transdate value that is far outside a normal range (frequently by having a 2079 year).

    Select top 100 'Step5c',CpnyID, LedgerID, FiscYr, Acct, Sub, perpost, perent, trandate,Posted, Rlsed, BatNbr, Module, * from GLTran with (nolock) where (trandate>='01/01/2048' or trandate<='01/01/1950') and (Rlsed=1 or Posted='P') and TranDate<>'1/1/1900'
    

    Fix: Update trandate to crtd_datetime. This script shows how.

    update gltran set trandate=crtd_datetime where (trandate>='01/01/2048' or trandate<='01/01/1950') and (Rlsed=1 or Posted='P') and TranDate<>'1/1/1900'
    
  • AcctHist records with a FiscYr field far outside a normal range.

    select top 100 'Step5d',a.CpnyID, a.LedgerID, a.FiscYr, a.Acct, a.Sub, a.CuryId, * from AcctHist a with (nolock) where a.FiscYr>'2048' or a.FiscYr<'1950' or len(a.FiscYr) < 4
    

    Fix: These are probably unwanted records. In manipulating data historically, you might have set the fiscal year to a future year to keep the records for later possible review.

Step 6

Locate instances in which amounts in the AcctHist record do not match the amounts in the CuryAcct record.

Note

Run this statement only after the issues in steps 1 to 5 have been fixed.

select
   top 1000 'Step6a',
   a.CpnyID,
   a.Acct,
   a.Sub,
   a.LedgerID,
   a.FiscYr,
   c.numCuryAcct,
   a.BegBal,
   c.begbal,
   a.PtdBal00,
   c.ptdbal00,
   a.PtdBal01,
   c.ptdbal01,
   a.PtdBal02,
   c.ptdbal02,
   a.PtdBal03,
   c.ptdbal03,
   a.PtdBal04,
   c.ptdbal04,
   a.PtdBal05,
   c.ptdbal05,
   a.PtdBal06,
   c.ptdbal06,
   a.PtdBal07,
   c.ptdbal07,
   a.PtdBal08,
   c.ptdbal08,
   a.PtdBal09,
   c.ptdbal09,
   a.PtdBal10,
   c.ptdbal10,
   a.PtdBal11,
   c.ptdbal11,
   a.PtdBal12,
   c.ptdbal12,
   a.ytdBal00,
   c.ytdbal00,
   a.ytdBal01,
   c.ytdbal01,
   a.ytdBal02,
   c.ytdbal02,
   a.ytdBal03,
   c.ytdbal03,
   a.ytdBal04,
   c.ytdbal04,
   a.ytdBal05,
   c.ytdbal05,
   a.ytdBal06,
   c.ytdbal06,
   a.ytdBal07,
   c.ytdbal07,
   a.ytdBal08,
   c.ytdbal08,
   a.ytdBal09,
   c.ytdbal09,
   a.ytdBal10,
   c.ytdbal10,
   a.ytdBal11,
   c.ytdbal11,
   a.ytdBal12,
   c.ytdbal12
from
   AcctHist a
   inner join
      (
         select
            count(*) as numCuryAcct,
            CpnyID,
            Acct,
            Sub,
            LedgerID,
            FiscYr,
            SUM(begbal) as begbal,
            SUM(ptdbal00) as ptdbal00,
            SUM(ptdbal01) as ptdbal01,
            SUM(ptdbal02) as ptdbal02,
            SUM(ptdbal03) as ptdbal03,
            SUM(ptdbal04) as ptdbal04,
            SUM(ptdbal05) as ptdbal05,
            SUM(ptdbal06) as ptdbal06,
            SUM(ptdbal07) as ptdbal07,
            SUM(ptdbal08) as ptdbal08,
            SUM(ptdbal09) as ptdbal09,
            SUM(ptdbal10) as ptdbal10,
            SUM(ptdbal11) as ptdbal11,
            SUM(ptdbal12) as ptdbal12,
            SUM(ytdbal00) as ytdbal00,
            SUM(ytdbal01) as ytdbal01,
            SUM(ytdbal02) as ytdbal02,
            SUM(ytdbal03) as ytdbal03,
            SUM(ytdbal04) as ytdbal04,
            SUM(ytdbal05) as ytdbal05,
            SUM(ytdbal06) as ytdbal06,
            SUM(ytdbal07) as ytdbal07,
            SUM(ytdbal08) as ytdbal08,
            SUM(ytdbal09) as ytdbal09,
            SUM(ytdbal10) as ytdbal10,
            SUM(ytdbal11) as ytdbal11,
            SUM(ytdbal12) as ytdbal12
         from
            curyacct
         group by
            CpnyID,
            Acct,
            Sub,
            LedgerID,
            FiscYr
      )
      c
      on a.CpnyID = c.CpnyID
      and a.Acct = c.Acct
      and a.Sub = c.Sub
      and a.LedgerID = c.LedgerID
      and a.FiscYr = c.FiscYr
where
   round(a.BegBal, 2) <> round(c.begbal, 2)
   or round(a.PtdBal00, 2) <> round(c.PtdBal00, 2)
   or round(a.PtdBal01, 2) <> round(c.PtdBal01, 2)
   or round(a.PtdBal02, 2) <> round(c.PtdBal02, 2)
   or round(a.PtdBal03, 2) <> round(c.PtdBal03, 2)
   or round(a.PtdBal04, 2) <> round(c.ptdbal04, 2)
   or round(a.PtdBal05, 2) <> round(c.PtdBal05, 2)
   or round(a.PtdBal06, 2) <> round(c.PtdBal06, 2)
   or round(a.PtdBal07, 2) <> round(c.PtdBal07, 2)
   or round(a.PtdBal08, 2) <> round(c.PtdBal08, 2)
   or round(a.PtdBal09, 2) <> round(c.PtdBal09, 2)
   or round(a.PtdBal10, 2) <> round(c.PtdBal10, 2)
   or round(a.PtdBal11, 2) <> round(c.PtdBal11, 2)
   or round(a.PtdBal12, 2) <> round(c.PtdBal12, 2)
   or round(a.ytdBal00, 2) <> round(c.ytdBal00, 2)
   or round(a.ytdBal01, 2) <> round(c.ytdBal01, 2)
   or round(a.ytdBal02, 2) <> round(c.ytdBal02, 2)
   or round(a.ytdBal03, 2) <> round(c.ytdBal03, 2)
   or round(a.ytdBal04, 2) <> round(c.ytdbal04, 2)
   or round(a.ytdBal05, 2) <> round(c.ytdBal05, 2)
   or round(a.ytdBal06, 2) <> round(c.ytdBal06, 2)
   or round(a.ytdBal07, 2) <> round(c.ytdBal07, 2)
   or round(a.ytdBal08, 2) <> round(c.ytdBal08, 2)
   or round(a.ytdBal09, 2) <> round(c.ytdBal09, 2)
   or round(a.ytdBal10, 2) <> round(c.ytdBal10, 2)
   or round(a.ytdBal11, 2) <> round(c.ytdBal11, 2)
   or round(a.ytdBal12, 2) <> round(c.ytdBal12, 2)

For a single-currency database, open the record in GL > Account History during initialization mode if there are only a few records. Change the beginning balance by some amount, save the record, revert the record, and then save it again. This updates the Curyacct record to match the Accthist record. If there are many records, run the ResetCuryAcctfromAcctHistStep6a.sql script from the MR2.zip file.

In a multicurrency database, open GL > Account History during the initialization mode if there are only a few records, and then click the Currency tab. Correct each period individually, as appropriate. If there are many records, run the MultiCurrencyStep6aFix.sql script from the MR2.zip file. Any change is made in the Base CuryID record.

After you complete Step 6, rerun the Diagnostics2.SQL script to verify that it no longer reports errors.

Additional scripts to find lowercase data that may cause issues in MR.

This script looks for multiple records where the Company.DatabaseName don't have the same case (ex: SLDemoApp and SLDEMOAPP). Run this script against the system database.

select c.DatabaseName, c.CpnyID from Company c left outer join sys.databases sd on c.DatabaseName COLLATE Latin1_General_CS_AS= sd.name COLLATE Latin1_General_CS_AS
where sd.name is null and DatabaseName in (select c1.DatabaseName from Company c1 left outer join company c2 on c1.DatabaseName = c2.DatabaseName where c1.DatabaseName=c2.DatabaseName and c1.DatabaseName COLLATE Latin1_General_CS_AS != c2.DatabaseName COLLATE Latin1_General_CS_AS)

Fix: Update the databasename to be uppercase.

This script looks for lowercase company ID and subaccount in the accthist, curyacct, and gltran tables. Run this script against the system database.

DECLARE @DbName VARCHAR(50)
DECLARE @useStatement VARCHAR(256)
DECLARE @fullStatement VARCHAR(8000)
DECLARE db_cursor CURSOR FOR
select distinct
   DatabaseName
from
   Company OPEN db_cursor FETCH NEXT
FROM
   db_cursor INTO @DbName WHILE @@FETCH_STATUS = 0
   BEGIN
set
   @DbName = LTRIM(RTRIM(@DbName))
set
   @useStatement = 'USE ' + @DbName + ''
set
   @fullStatement = '

   SELECT
      sub as ''Sub - AcctHist - ' + @DbName + ''',
      *
   FROM
      AcctHist
   WHERE
      UPPER(sub) <> sub COLLATE Latin1_General_CS_AS
      SELECT
         sub as ''Sub - GLTran - ' + @DbName + ''',
         *
      FROM
         GLTran
      WHERE
         UPPER(sub) <> sub COLLATE Latin1_General_CS_AS
         SELECT
            sub as ''Sub - CuryAcct - ' + @DbName + ''',
            *
         FROM
            CuryAcct
         WHERE
            UPPER(sub) <> sub COLLATE Latin1_General_CS_AS
            SELECT
               CpnyID as ''CpnyID - AcctHist - ' + @DbName + ''',
               *
            FROM
               AcctHist
            WHERE
               UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS
               SELECT
                  CpnyID as ''CpnyID - GLTran - ' + @DbName + ''',
                  *
               FROM
                  GLTran
               WHERE
                  UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS
                  SELECT
                     CpnyID as ''CpnyID - CuryAcct - ' + @DbName + ''',
                     *
                  FROM
                     CuryAcct
                  WHERE
                     UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS
                     SELECT
                        SUB as ''Sub - SubAcct - ' + @DbName + ''',
                        *
                     from
                        SubAcct
                     where
                        (
                           SUB collate sql_latin1_general_cp1_cs_as <> upper(SUB)
                        )
                        or
                        (
                           ConsolSub collate sql_latin1_general_cp1_cs_as <> upper(ConsolSub)
                        )
                        '
 exec (@useStatement + @fullStatement) FETCH NEXT
                     FROM
                        db_cursor INTO @DbName
   END
   CLOSE db_cursor DEALLOCATE db_cursor

Fix: If you find any lowercase subaccounts, you can run these to put them in uppercase.

update GLTran set Sub = UPPER(Sub)
update AcctHist set Sub = UPPER(Sub)
update CuryAcct set Sub = UPPER(Sub)

If you find any lowercase company IDs, you can run these to put them in uppercase.

update accthist set cpnyid = UPPER(cpnyid) WHERE UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS
update curyacct set cpnyid = UPPER(cpnyid) WHERE UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS
update gltran set cpnyid = UPPER(cpnyid) WHERE UPPER(CpnyID) <> CpnyID COLLATE Latin1_General_CS_AS

This script looks for lowercase LedgerID in the accthist, curyacct, and gltran tables. Run this script against the application database.

SELECT TOP 1 LedgerID FROM AcctHist WHERE UPPER(LedgerID) <> LedgerID COLLATE Latin1_General_CS_AS
SELECT TOP 1 LedgerID FROM GLTran WHERE UPPER(LedgerID) <> LedgerID COLLATE Latin1_General_CS_AS
SELECT TOP 1 LedgerID FROM CuryAcct WHERE UPPER(LedgerID) <> LedgerID COLLATE Latin1_General_CS_AS

Fix: If you find any lowercase LedgerID's, you can run these to put them in uppercase.

update AcctHist set LedgerID = UPPER(LedgerID) where LedgerID COLLATE Latin1_General_BIN like '%[a-z]%'
update GLTran set LedgerID = UPPER(LedgerID) where LedgerID COLLATE Latin1_General_BIN like '%[a-z]%'
update CuryAcct set LedgerID = UPPER(LedgerID) where LedgerID COLLATE Latin1_General_BIN like '%[a-z]%'

This script looks for lowercase CuryID in the accthist, curyacct, and gltran tables. Run this script against the application database.

SELECT TOP 1 CuryID FROM AcctHist WHERE UPPER(CuryID) <> CuryID COLLATE Latin1_General_CS_AS
SELECT TOP 1 CuryID FROM GLTran WHERE UPPER(CuryID) <> CuryID COLLATE Latin1_General_CS_AS
SELECT TOP 1 CuryID FROM CuryAcct WHERE UPPER(CuryID) <> CuryID COLLATE Latin1_General_CS_AS

Fix: If you find any lowercase CuryID's, you can run these to put them in uppercase.

update AcctHist set CuryId = UPPER(CuryId) where CuryId COLLATE Latin1_General_BIN like '%[a-z]%'  
update GLTran set CuryId = UPPER(CuryId) where CuryId COLLATE Latin1_General_BIN like '%[a-z]%'
update CuryAcct set CuryId = UPPER(CuryId) where CuryId COLLATE Latin1_General_BIN like '%[a-z]%'  

If no errors are reported after rerunning the Diagnostic2.SQL script, the Management Reporter Data Mart must be Integrated again using the steps in KB2964624.