YTD running balance including missing months

  • Hi All,
    I am trying to get the  YTD Account Balances for a financial statement. There are accounts which does not have balance for all the months . I need the results for all the 12 months irrespective of having balance in a particular month or not. With the help of various forum posts I have reached until the below query. This is giving me YTD balance until the month the account has balance. 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567
    20175NULL
    20176NULL
    20177NULL
    20178NULL
    20179NULL
    201710NULL
    201711NULL
    201712NULL

    I need the results as 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567.00
    2017516567.00
    2017616567.00
    2017716567.00
    2017816567.00
    2017916567.00
    20171016567.00
    20171116567.00
    20171216567.00

     
    SELECT
    years.y, months.m, 
    fk_pandL.NetAmount 
    FROM (
    SELECT distinct year(begindate) as y from ESGOFiscalYear 

    ) years
    CROSS JOIN (
    SELECT 1 AS m UNION ALL
    SELECT 2 AS m UNION ALL
    SELECT 3 AS m UNION ALL
    SELECT 4 AS m UNION ALL
    SELECT 5 AS m UNION ALL
    SELECT 6 AS m UNION ALL
    SELECT 7 AS m UNION ALL
    SELECT 8 AS m UNION ALL
    SELECT 9 AS m UNION ALL
    SELECT 10 AS m UNION ALL
    SELECT 11 AS m UNION ALL
    SELECT 12 AS m
    ) months
    left join
    (SELECT DISTINCT year(fy.BeginDate) AS YEAR, fp.Description AS FiscalPeriod,
    CASE WHEN SUBSTRING(fp.Description, 6, 3) = 'JAN'
    THEN 'January'
    WHEN SUBSTRING(fp.Description, 6, 3) 
    = 'FEB'
    THEN 'February'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'MAR'
    THEN 'March'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'APR'
    THEN 'April'
    WHEN SUBSTRING(fp.Description, 6, 3) 
    = 'MAY' THEN 'May'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'JUN'
    THEN 'June'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'JUL'
    THEN 'July'
    WHEN SUBSTRING(fp.Description, 6, 3) 
    = 'AUG'
    THEN 'August'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'SEP'
    THEN 'September'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'OCT'
    THEN 'October'
    WHEN SUBSTRING(fp.Description, 6, 3) 
    = 'NOV'
    THEN 'November'
    WHEN SUBSTRING(fp.Description, 6, 3) = 'DEC'
    THEN 'December' END AS Period,
    row_number() over (order by fp.enddate) as monthno,
     'YTD' AS VIEWv,
    gp.fCompanyCode AS CompanyCode, 
    bu.fTableField1Code AS BusinessUnitCategory,
    gl.code AS AccountCode,
    '' AS Intercompanycode, gl.name AS AccountDescription, 
    (sum(gp.debitvalue) OVER (Partition BY gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY fp.enddate ) - 
    sum(gp.CreditValue) OVER (Partition BY gl.code, gp.fcompanycode, bu.fTableField1Code, Year(fp.enddate)
    ORDER BY fp.enddate )) AS NetAmount
    FROM  ESGLAccountPeriodics gp LEFT JOIN ESGOFiscalPeriod fp ON fp.gid = gp.fFiscalPeriodGID LEFT JOIN
    ESGOFiscalYear fy ON fy.gid = gp.fFiscalYearGID LEFT JOIN
    esglaccount gl ON gl.gid = gp.fAccountGID LEFT JOIN
     ESGOZBusinessUnit bu ON bu.Code = gp.fBusinessUnitCode
    WHERE   gl.ChartOfAccounts = 0 AND gl.FlagField2 = 1 and gl.code='7001xxxx' and year(fy.BeginDate) = '2017' and gp.fCompanyCode ='10x' and datepart(m,fp.enddate) <=12
    GROUP BY gl.code, fp.Description, fp.EndDate,fy.EndDate, gp.DebitValue, gp.CreditValue, gp.fCompanyCode, bu.fTableField1Code, gl.name, fy.BeginDate, gp.gid, gp.fAccountGID) fk_pandL on 
    fk_pandL.year = years.y and fk_pandL.monthno =months.m
    where years.y='2017'

    Any help is highly appreciated.

    Thanks.

  • As you have not provided DDL, I cannot post the exact solution. But here is an idea for creating running totals for 'missing' months by left joining from a calendar table.

    DROP TABLE IF EXISTS #Calendar;

    CREATE TABLE #Calendar
    (
      Yr SMALLINT,
      Mth SMALLINT
    );

    INSERT #Calendar
    (
      Yr,
      Mth
    )
    VALUES
    (2017, 1),
    (2017, 2),
    (2017, 3),
    (2017, 4),
    (2017, 5),
    (2017, 6),
    (2017, 7),
    (2017, 8),
    (2017, 9),
    (2017, 10),
    (2017, 11),
    (2017, 12);

    DROP TABLE IF EXISTS #SomeData;
    CREATE TABLE #SomeData
    (
      Yr SMALLINT,
      Mth TINYINT,
      NetAmount DECIMAL(19, 6)
    );

    INSERT #SomeData
    (
      Yr,
      Mth,
      NetAmount
    )
    VALUES
    (2017, 1, 4315.77),
    (2017, 2, 8213.89),
    (2017, 3, 12529.66),
    (2017, 4, 16567.);

    SELECT c.Yr,
       c.Mth,
       RunningSum = SUM(sd.NetAmount) OVER (ORDER BY c.Yr, c.Mth ROWS UNBOUNDED PRECEDING)
    FROM #Calendar c
      LEFT JOIN #SomeData sd
       ON c.Yr = sd.Yr
        AND c.Mth = sd.Mth
    ORDER BY c.Yr,
       c.Mth;

    If you haven't even tried to resolve your issue, please don't expect the hard-working volunteers here to waste their time providing links to answers which you could easily have found yourself.

  • Thankyou so much  and taking your time to  help .  

    The query you have posted have given me an idea how to make the changes in the existing query.

  • ddly_ann - Monday, May 28, 2018 7:47 AM

    Hi All,
    I am trying to get the  YTD Account Balances for a financial statement. There are accounts which does not have balance for all the months . I need the results for all the 12 months irrespective of having balance in a particular month or not. With the help of various forum posts I have reached until the below query. This is giving me YTD balance until the month the account has balance. 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567
    20175NULL
    20176NULL
    20177NULL
    20178NULL
    20179NULL
    201710NULL
    201711NULL
    201712NULL

    I need the results as 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567.00
    2017516567.00
    2017616567.00
    2017716567.00
    2017816567.00
    2017916567.00
    20171016567.00
    20171116567.00
    20171216567.00


    Any help is highly appreciated.

    Thanks.

    Just wondering whether it's actually appropriate to carry the last value you see in the data into months for which there is no data.   If there not being data for a given month for a given account, does that mean that the balance for that month might actually be zero?  And from that, carrying over that balance might be incorrect.   Another potential consideration is whether the balance might need to be cumulative, as what if the balance number represents an amount purchased on credit terms, and thus the balance will always be cumulative?   And from appearances, the numbers you already posted look like they may already be cumulative, and thus if there's no data, and this is in the past, there might oughta be zero's, as surely somewhere in those numbers, any payments made would be reflected?

    Steve (aka sgmunson) 🙂 🙂 🙂
    Rent Servers for Income (picks and shovels strategy)

  • ddly_ann - Monday, May 28, 2018 7:47 AM

    A useful idiom is a report period calendar. It gives a name to a range of dates. The worst way would be to use temporal math; it tells the world you do not think in sets or understand declarative programming yet. Here is a skeleton:

    CREATE TABLE Report_Periods
    (report_name CHAR(10) NOT NULL PRIMARY KEY,
    report_start_date DATE NOT NULL,
    report_end_date DATE NOT NULL,
    CONSTRAINT date_ordering
    CHECK (report_start_date <= report_end_date),
    ordinal_period INTEGER NOT NULL UNIQUE
    CHECK(ordinal_period > 0)
    etc);

    These report periods can overlap; a fiscal quarter will be contained in the range of its fiscal year. I like the MySQL convention of using double zeroes for months and years, That is 'yyyy-mm-00' for a month within a year and 'yyyy-00-00' for the whole year. The advantage is that it will sort with the ISO-8601 data format required by Standard SQL. Remember that when you design report name column.

    We now have some more basic problems with your design. The NULL in SQL actually has some meaning. Did this monthly report itself exist, rather than the amount of the monthly report. . Think about it. If I'm in the middle the year, then I can't get reports from the end of the year. However, if I am at the end of the year, and I'm missing data (all those departments never turned in their net amount reports, but I know that the amounts actually exist – – the missing value, or unreported value problem), then I have a really different situation between obviously physically not existing and not reported.

    If you are projecting future revenue, then we have a different model.

    In short, we need more specs.

    Please post DDL and follow ANSI/ISO standards when asking for help. 

  • jcelko212 32090 - Tuesday, May 29, 2018 12:24 PM

    ddly_ann - Monday, May 28, 2018 7:47 AM

    A useful idiom is a report period calendar. It gives a name to a range of dates. The worst way would be to use temporal math; it tells the world you do not think in sets or understand declarative programming yet. Here is a skeleton:

    CREATE TABLE Report_Periods
    (report_name CHAR(10) NOT NULL PRIMARY KEY,
    report_start_date DATE NOT NULL,
    report_end_date DATE NOT NULL,
    CONSTRAINT date_ordering
    CHECK (report_start_date <= report_end_date),
    ordinal_period INTEGER NOT NULL UNIQUE
    CHECK(ordinal_period > 0)
    etc);

    These report periods can overlap; a fiscal quarter will be contained in the range of its fiscal year. I like the MySQL convention of using double zeroes for months and years, That is 'yyyy-mm-00' for a month within a year and 'yyyy-00-00' for the whole year. The advantage is that it will sort with the ISO-8601 data format required by Standard SQL. Remember that when you design report name column.

    We now have some more basic problems with your design. The NULL in SQL actually has some meaning. Did this monthly report itself exist, rather than the amount of the monthly report. . Think about it. If I'm in the middle the year, then I can't get reports from the end of the year. However, if I am at the end of the year, and I'm missing data (all those departments never turned in their net amount reports, but I know that the amounts actually exist – – the missing value, or unreported value problem), then I have a really different situation between obviously physically not existing and not reported.

    If you are projecting future revenue, then we have a different model.

    In short, we need more specs.

    Mr. Celko, for being a SQL Standards purist you seem to have a love fest for MySQL.  You do realize that this site is For Microsoft SQL Server and not Oracle MySQL, correct?  Stop hyping MySQL and actually provide some T-SQL help here.

  • sgmunson - Tuesday, May 29, 2018 10:25 AM

    ddly_ann - Monday, May 28, 2018 7:47 AM

    Hi All,
    I am trying to get the  YTD Account Balances for a financial statement. There are accounts which does not have balance for all the months . I need the results for all the 12 months irrespective of having balance in a particular month or not. With the help of various forum posts I have reached until the below query. This is giving me YTD balance until the month the account has balance. 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567
    20175NULL
    20176NULL
    20177NULL
    20178NULL
    20179NULL
    201710NULL
    201711NULL
    201712NULL

    I need the results as 

    ymNetAmount
    201714315.77
    201728213.89
    2017312529.66
    2017416567.00
    2017516567.00
    2017616567.00
    2017716567.00
    2017816567.00
    2017916567.00
    20171016567.00
    20171116567.00
    20171216567.00


    Any help is highly appreciated.

    Thanks.

    Just wondering whether it's actually appropriate to carry the last value you see in the data into months for which there is no data.   If there not being data for a given month for a given account, does that mean that the balance for that month might actually be zero?  And from that, carrying over that balance might be incorrect.   Another potential consideration is whether the balance might need to be cumulative, as what if the balance number represents an amount purchased on credit terms, and thus the balance will always be cumulative?   And from appearances, the numbers you already posted look like they may already be cumulative, and thus if there's no data, and this is in the past, there might oughta be zero's, as surely somewhere in those numbers, any payments made would be reflected?

    BWAAA-HAAA!!!  I'm right there with you!  "We shall post no dime before its time". 😀

    Heh... and with those year and month columns used for display, I can't wait to see what happens "on the wrap" to a new year, either. 😀

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Lynn Pettis - Tuesday, May 29, 2018 3:37 PM

    jcelko212 32090 - Tuesday, May 29, 2018 12:24 PM

    ddly_ann - Monday, May 28, 2018 7:47 AM

    A useful idiom is a report period calendar. It gives a name to a range of dates. The worst way would be to use temporal math; it tells the world you do not think in sets or understand declarative programming yet. Here is a skeleton:

    CREATE TABLE Report_Periods
    (report_name CHAR(10) NOT NULL PRIMARY KEY,
    report_start_date DATE NOT NULL,
    report_end_date DATE NOT NULL,
    CONSTRAINT date_ordering
    CHECK (report_start_date <= report_end_date),
    ordinal_period INTEGER NOT NULL UNIQUE
    CHECK(ordinal_period > 0)
    etc);

    These report periods can overlap; a fiscal quarter will be contained in the range of its fiscal year. I like the MySQL convention of using double zeroes for months and years, That is 'yyyy-mm-00' for a month within a year and 'yyyy-00-00' for the whole year. The advantage is that it will sort with the ISO-8601 data format required by Standard SQL. Remember that when you design report name column.

    We now have some more basic problems with your design. The NULL in SQL actually has some meaning. Did this monthly report itself exist, rather than the amount of the monthly report. . Think about it. If I'm in the middle the year, then I can't get reports from the end of the year. However, if I am at the end of the year, and I'm missing data (all those departments never turned in their net amount reports, but I know that the amounts actually exist – – the missing value, or unreported value problem), then I have a really different situation between obviously physically not existing and not reported.

    If you are projecting future revenue, then we have a different model.

    In short, we need more specs.

    Mr. Celko, for being a SQL Standards purist you seem to have a love fest for MySQL.  You do realize that this site is For Microsoft SQL Server and not Oracle MySQL, correct?  Stop hyping MySQL and actually provide some T-SQL help here.

    Heh... and besides, it violates the very standards that Joe busts everyone chops about.  "00" is not a valid representation for either day or month in the ISO 8601 standard on the subject of such temporal notations.  It would be better to use blanks but that would also perpetuate the mistake of storing temporal display data in character based columns instead of using the proper data type.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Hi All,
    Thankyou all for the valuable points. Finally I could come up with the desired result with changes in the query.

    QUERY
    -

    SELECT  yr.y as Year,buc.buc,glc.ac,glc.descr,co.code, '' as Intercompanycode, 'YTD' as Viewv,
    case c.m when 1 then 'January'
    when 2 then 'February'
    when 3 then 'March'
    when 4 then 'April'
    when 5 then 'May'
    when 6 then 'June'
    when 7 then 'July'
    when 8 then 'August'
    when 9 then 'September'
    when 10 then 'October'
    when 11 then 'November'
    when 12 then 'Decemeber'
    end as Period,
    (sum(isnull(dt.NetAmount,0)) OVER ( partition by buc.buc,glc.ac,co.code,yr.y ORDER BY c.m, yr.y ROWS UNBOUNDED PRECEDING )) RunningSum
    FROM
    ( select distinct year(fy.enddate) as y from ESGOFiscalYear fy )yr cross join
    (select distinct gl.code as ac,gl.name as descr from esglaccount gl where gl.ChartOfAccounts = 0 and gl.SummaryAccount =0 and gl.FlagField2=1) glc cross join
    (select distinct bu.fTableField1Code buc from ESGOZBusinessUnit bu ) buc cross join
    (select distinct c.code from esgocompany c ) co
    cross join (
      SELECT 1 AS m UNION ALL
    SELECT 2 AS m UNION ALL
    SELECT 3 AS m UNION ALL
    SELECT 4 AS m UNION ALL
    SELECT 5 AS m UNION ALL
    SELECT 6 AS m UNION ALL
    SELECT 7 AS m UNION ALL
    SELECT 8 AS m UNION ALL
    SELECT 9 AS m UNION ALL
    SELECT 10 AS m UNION ALL
    SELECT 11 AS m UNION ALL
    SELECT 12 AS m) c
    LEFT JOIN

     (SELECT DISTINCT year(fy.BeginDate) AS YEAR, fp.Description AS FiscalPeriod, 'YTD' AS VIEWv, gp.fCompanyCode AS CompanyCode,
    bu.fTableField1Code AS BusinessUnitCategory, gl.code AS AccountCode, '' AS Intercompanycode, gl.name AS AccountDescription,datepart(m,fp.enddate) as monthno,
    isnull(sum(gp.debitvalue) OVER ( partition by datepart(m,fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m,fp.enddate) ) -
    sum(gp.CreditValue) OVER ( partition by datepart(m,fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m,fp.enddate)),0 ) AS NetAmount
             FROM ESGLAccountPeriodics gp LEFT JOIN
             ESGOFiscalPeriod fp ON fp.gid = gp.fFiscalPeriodGID LEFT JOIN
             ESGOFiscalYear fy ON fy.gid = gp.fFiscalYearGID LEFT JOIN
             esglaccount gl ON gl.gid = gp.fAccountGID LEFT JOIN
             ESGOZBusinessUnit bu ON bu.Code = gp.fBusinessUnitCode
    WHERE  
    gl.ChartOfAccounts = 0
    AND gl.FlagField2 = 1 and
    datepart(m,fp.enddate) <=12
    and bu.fTableField1Code is not null
    and year(fy.begindate)>='2017'
    GROUP BY gl.code,
        fp.Description,
        fp.EndDate,
        gp.DebitValue,
        gp.CreditValue,
        gp.fCompanyCode,
        bu.fTableField1Code,
        gl.name,
       fy.BeginDate,
       gp.gid,
       gp.fAccountGID) dt
      ON dt.monthno =c.m
      AND dt.year =yr.y and dt.AccountCode=glc.ac and dt.BusinessUnitCategory = buc.buc and dt.CompanyCode = co.Code
      where buc.buc is not null and yr.y>='2017'
      group by buc.buc,co.code,yr.y,c.m,dt.NetAmount,glc.ac,glc.descr
      order by 1,3,2,5,c.m
        

  • When looking up the month names, you could also use the CHOOSE function

    Replace this large CASE statement
    case c.m when 1 then 'January'
    when 2 then 'February'
    when 3 then 'March'
    when 4 then 'April'
    when 5 then 'May'
    when 6 then 'June'
    when 7 then 'July'
    when 8 then 'August'
    when 9 then 'September'
    when 10 then 'October'
    when 11 then 'November'
    when 12 then 'Decemeber'
    end as Period,

    with ...
    CHOOSE(c.m, 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December') as [Period]

  • You could also add the decoded monthname to the CROSS JOIN:
    CROSS JOIN
      (
       SELECT m = 1,
         mth = 'January'
       UNION ALL
       SELECT m = 2,
         mth = 'February'
       UNION ALL
       SELECT m = 3,
         mth = 'March'
       UNION ALL
       SELECT m = 4,
         mth = 'April'
       UNION ALL
       SELECT m = 5,
         mth = 'May'
       UNION ALL
       SELECT m = 6,
         mth = 'June'
       UNION ALL
       SELECT m = 7,
         mth = 'July'
       UNION ALL
       SELECT m = 8,
         mth = 'August'
       UNION ALL
       SELECT m = 9,
         mth = 'September'
       UNION ALL
       SELECT m = 10,
         mth = 'October'
       UNION ALL
       SELECT m = 11,
         mth = 'November'
       UNION ALL
       SELECT m = 12,
         mth = 'Decemeber'
      ) c

    and then change the SELECT bit to have
      Period = c.mth,

    If you haven't even tried to resolve your issue, please don't expect the hard-working volunteers here to waste their time providing links to answers which you could easily have found yourself.

  • ddly_ann - Wednesday, May 30, 2018 1:04 AM

    Hi All,
    Thankyou all for the valuable points. Finally I could come up with the desired result with changes in the query.

    QUERY
    -

    SELECT  yr.y as Year,buc.buc,glc.ac,glc.descr,co.code, '' as Intercompanycode, 'YTD' as Viewv,
    case c.m when 1 then 'January'
    when 2 then 'February'
    when 3 then 'March'
    when 4 then 'April'
    when 5 then 'May'
    when 6 then 'June'
    when 7 then 'July'
    when 8 then 'August'
    when 9 then 'September'
    when 10 then 'October'
    when 11 then 'November'
    when 12 then 'Decemeber'
    end as Period,
    (sum(isnull(dt.NetAmount,0)) OVER ( partition by buc.buc,glc.ac,co.code,yr.y ORDER BY c.m, yr.y ROWS UNBOUNDED PRECEDING )) RunningSum
    FROM
    ( select distinct year(fy.enddate) as y from ESGOFiscalYear fy )yr cross join
    (select distinct gl.code as ac,gl.name as descr from esglaccount gl where gl.ChartOfAccounts = 0 and gl.SummaryAccount =0 and gl.FlagField2=1) glc cross join
    (select distinct bu.fTableField1Code buc from ESGOZBusinessUnit bu ) buc cross join
    (select distinct c.code from esgocompany c ) co
    cross join (
      SELECT 1 AS m UNION ALL
    SELECT 2 AS m UNION ALL
    SELECT 3 AS m UNION ALL
    SELECT 4 AS m UNION ALL
    SELECT 5 AS m UNION ALL
    SELECT 6 AS m UNION ALL
    SELECT 7 AS m UNION ALL
    SELECT 8 AS m UNION ALL
    SELECT 9 AS m UNION ALL
    SELECT 10 AS m UNION ALL
    SELECT 11 AS m UNION ALL
    SELECT 12 AS m) c
    LEFT JOIN

     (SELECT DISTINCT year(fy.BeginDate) AS YEAR, fp.Description AS FiscalPeriod, 'YTD' AS VIEWv, gp.fCompanyCode AS CompanyCode,
    bu.fTableField1Code AS BusinessUnitCategory, gl.code AS AccountCode, '' AS Intercompanycode, gl.name AS AccountDescription,datepart(m,fp.enddate) as monthno,
    isnull(sum(gp.debitvalue) OVER ( partition by datepart(m,fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m,fp.enddate) ) -
    sum(gp.CreditValue) OVER ( partition by datepart(m,fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m,fp.enddate)),0 ) AS NetAmount
             FROM ESGLAccountPeriodics gp LEFT JOIN
             ESGOFiscalPeriod fp ON fp.gid = gp.fFiscalPeriodGID LEFT JOIN
             ESGOFiscalYear fy ON fy.gid = gp.fFiscalYearGID LEFT JOIN
             esglaccount gl ON gl.gid = gp.fAccountGID LEFT JOIN
             ESGOZBusinessUnit bu ON bu.Code = gp.fBusinessUnitCode
    WHERE  
    gl.ChartOfAccounts = 0
    AND gl.FlagField2 = 1 and
    datepart(m,fp.enddate) <=12
    and bu.fTableField1Code is not null
    and year(fy.begindate)>='2017'
    GROUP BY gl.code,
        fp.Description,
        fp.EndDate,
        gp.DebitValue,
        gp.CreditValue,
        gp.fCompanyCode,
        bu.fTableField1Code,
        gl.name,
       fy.BeginDate,
       gp.gid,
       gp.fAccountGID) dt
      ON dt.monthno =c.m
      AND dt.year =yr.y and dt.AccountCode=glc.ac and dt.BusinessUnitCategory = buc.buc and dt.CompanyCode = co.Code
      where buc.buc is not null and yr.y>='2017'
      group by buc.buc,co.code,yr.y,c.m,dt.NetAmount,glc.ac,glc.descr
      order by 1,3,2,5,c.m
        

    Your query is rather hard to read, so I've formatted it quite a bit to try and make it more readable, and also applied a simplification, as you don't need to use a CASE statement to figure out the month name.   Of course, it would be on heck of a lot better if you would stop using year and month separately.   That's why date and datetime data types were invented.
    SELECT
        yr.y as Year,
        buc.buc,
        glc.ac,
        glc.descr,
        co.code,
        '' as Intercompanycode,
        'YTD' as Viewv,
        DATENAME(month, DATEFROMPARTS(yr.y, c.m, 1)) as Period,
        SUM(ISNULL(dt.NetAmount, 0)) OVER (PARTITION BY buc.buc, glc.ac, co.code, yr.y ORDER BY c.m, yr.y ROWS UNBOUNDED PRECEDING) AS RunningSum
    FROM (
        select distinct year(fy.enddate) as y
        from ESGOFiscalYear AS fy
        ) AS yr
        CROSS JOIN (
            select distinct
                gl.code as ac,
                gl.name as descr
            from esglaccount AS gl
            where gl.ChartOfAccounts = 0
                and gl.SummaryAccount = 0
                and gl.FlagField2 = 1
            ) AS glc
        CROSS JOIN (
            select distinct bu.fTableField1Code buc
            from ESGOZBusinessUnit AS bu
            ) AS buc
        CROSS JOIN (
            select distinct c.code
            from esgocompany AS c
            ) AS co
        CROSS JOIN (
            SELECT 1 AS m UNION ALL
            SELECT 2 AS m UNION ALL
            SELECT 3 AS m UNION ALL
            SELECT 4 AS m UNION ALL
            SELECT 5 AS m UNION ALL
            SELECT 6 AS m UNION ALL
            SELECT 7 AS m UNION ALL
            SELECT 8 AS m UNION ALL
            SELECT 9 AS m UNION ALL
            SELECT 10 AS m UNION ALL
            SELECT 11 AS m UNION ALL
            SELECT 12 AS m
            ) AS c
        LEFT JOIN (
            SELECT DISTINCT
                year(fy.BeginDate) AS YEAR,
                fp.Description AS FiscalPeriod,
                'YTD' AS VIEWv,
                gp.fCompanyCode AS CompanyCode,
                bu.fTableField1Code AS BusinessUnitCategory,
                gl.code AS AccountCode,
                '' AS Intercompanycode,
                gl.name AS AccountDescription,
                datepart(m,fp.enddate) as monthno,
                isnull(    sum(gp.debitvalue)    OVER (PARTITION BY datepart(m, fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m, fp.enddate)),
                        sum(gp.CreditValue)    OVER (PARTITION BY datepart(m, fp.enddate), gl.code, gp.fcompanycode, bu.ftablefield1code, Year(fp.enddate) ORDER BY datepart(m,fp.enddate)), 0) AS NetAmount
       FROM ESGLAccountPeriodics AS gp
                LEFT OUTER JOIN ESGOFiscalPeriod AS fp
                    ON fp.gid = gp.fFiscalPeriodGID
                LEFT OUTER JOIN ESGOFiscalYear AS fy
                    ON fy.gid = gp.fFiscalYearGID
                LEFT OUTER JOIN esglaccount AS gl
                    ON gl.gid = gp.fAccountGID
                LEFT OUTER JOIN ESGOZBusinessUnit AS bu
                    ON bu.Code = gp.fBusinessUnitCode
            WHERE gl.ChartOfAccounts = 0
                AND gl.FlagField2 = 1
                AND datepart(m, fp.enddate) <= 12
                AND bu.fTableField1Code IS NOT NULL
                and year(fy.begindate) >= '2017'
            GROUP BY gl.code,
                fp.Description,
                fp.EndDate,
                gp.DebitValue,
                gp.CreditValue,
                gp.fCompanyCode,
                bu.fTableField1Code,
                gl.name,
                fy.BeginDate,
                gp.gid,
                gp.fAccountGID
            ) AS dt
                ON dt.monthno = c.m
                AND dt.year = yr.y
                AND dt.AccountCode = glc.ac
                AND dt.BusinessUnitCategory = buc.buc
                AND dt.CompanyCode = co.Code
    WHERE buc.buc is not null
        AND yr.y >= '2017'
    GROUP BY buc.buc,
        co.code,
        yr.y,
        c.m,
        dt.NetAmount,
        glc.ac,
        glc.descr
    ORDER BY 1, 3, 2, 5, c.m;

    Steve (aka sgmunson) 🙂 🙂 🙂
    Rent Servers for Income (picks and shovels strategy)

  • Phil Parkin - Wednesday, May 30, 2018 5:21 AM

    You could also add the decoded monthname to the CROSS JOIN:
    CROSS JOIN
      (
       SELECT m = 1,
         mth = 'January'
       UNION ALL
       SELECT m = 2,
         mth = 'February'
       UNION ALL
       SELECT m = 3,
         mth = 'March'
       UNION ALL
       SELECT m = 4,
         mth = 'April'
       UNION ALL
       SELECT m = 5,
         mth = 'May'
       UNION ALL
       SELECT m = 6,
         mth = 'June'
       UNION ALL
       SELECT m = 7,
         mth = 'July'
       UNION ALL
       SELECT m = 8,
         mth = 'August'
       UNION ALL
       SELECT m = 9,
         mth = 'September'
       UNION ALL
       SELECT m = 10,
         mth = 'October'
       UNION ALL
       SELECT m = 11,
         mth = 'November'
       UNION ALL
       SELECT m = 12,
         mth = 'Decemeber'
      ) c

    and then change the SELECT bit to have
      Period = c.mth,

    Why are you doing display formatting in the database layer? Isn't that a violation of the basic principle of any tiered architecture? Why are you using the old Sybase UNION ALL syntax to build a table? How can a month exist without being in a year?

    Please post DDL and follow ANSI/ISO standards when asking for help. 

  • Lynn Pettis - Tuesday, May 29, 2018 3:37 PM

    jcelko212 32090 - Tuesday, May 29, 2018 12:24 PM

    ddly_ann - Monday, May 28, 2018 7:47 AM

    Mr. Celko, for being a SQL Standards purist you seem to have a love fest for MySQL.  You do realize that this site is For Microsoft SQL Server and not Oracle MySQL, correct?  Stop hyping MySQL and actually provide some T-SQL help here.

    I suppose in the interest of full disclosure, I did work for the MySQL people and produced some website material. It was all about basic data modeling, etc. Having said this, the reason I keep mentioning their convention for temporal intervals is (1) it is being considered for ANSI ISO standards, thanks largely to the popularity of MySQL (2) it is language independent (3) it sorts properly with the rest of the ISO 8601 display format. In short, they are a good choice at the current time for conforming to international standards.

    You probably don't remember this, but it one point thanks to the French (anytime something goes wrong in a standard, look for the French to have done something) NATO had a standard that used Roman numerals for months. No, really!

    Since Microsoft has not implemented the ANSI/ISO standard interval data types in its temporal model, we have to do a "repair job" instead. If you have a better suggestion. I'd love to hear and put it in my books.

    Please post DDL and follow ANSI/ISO standards when asking for help. 

  • jcelko212 32090 - Thursday, May 31, 2018 11:03 AM

    Phil Parkin - Wednesday, May 30, 2018 5:21 AM

    You could also add the decoded monthname to the CROSS JOIN:
    CROSS JOIN
      (
       SELECT m = 1,
         mth = 'January'
       UNION ALL
       SELECT m = 2,
         mth = 'February'
       UNION ALL
       SELECT m = 3,
         mth = 'March'
       UNION ALL
       SELECT m = 4,
         mth = 'April'
       UNION ALL
       SELECT m = 5,
         mth = 'May'
       UNION ALL
       SELECT m = 6,
         mth = 'June'
       UNION ALL
       SELECT m = 7,
         mth = 'July'
       UNION ALL
       SELECT m = 8,
         mth = 'August'
       UNION ALL
       SELECT m = 9,
         mth = 'September'
       UNION ALL
       SELECT m = 10,
         mth = 'October'
       UNION ALL
       SELECT m = 11,
         mth = 'November'
       UNION ALL
       SELECT m = 12,
         mth = 'Decemeber'
      ) c

    and then change the SELECT bit to have
      Period = c.mth,

    Why are you doing display formatting in the database layer? Isn't that a violation of the basic principle of any tiered architecture? Why are you using the old Sybase UNION ALL syntax to build a table? How can a month exist without being in a year?

    Absolutely! I know I call up my HR department every year to ask when Christmas is. After all, "December 25" is meaningless without a year!

Viewing 15 posts - 1 through 15 (of 37 total)

You must be logged in to reply to this topic. Login to reply