1

Arrrgh, I am not getting this.

I have a table of accounts from Dynamics GP that has 7 columns. I need to fill in the blank months for accounts that didn't have any activity for a given month.

I have created an in memory table @MONTHS that has lines like so:

Account, Description, Year, Month, Month Name, Netchange, PeriodBal


1110000, NULL, 2006, 1, NULL, 0, NULL

This should match up with the same information coming from Dynamics GP. A similar line from GP would look like this:

1110000, Petty Cash, 2006, 1, January, 15.00, 343.97

If we did not spend any petty cash in February, then there would be no line for that account in 2/2006, I want to make the @MONTHS table RIGHT JOIN with the DynamicsGP table so that empty months are filled in.

Here's the abbreviated SQL shortened for readability:

SELECT Z.GPACCOUNTNO, 
Z.DESCRIPTION, 
Z.FISCALYEAR, 
Z.FISCALPERIOD, 
Z.FISCALPERIODNAME, 
Z.NETCHANGE, 
Z.PERIODBALANCE
FROM Z
RIGHT JOIN @MONTHS M 
    ON Z.GPACCOUNTNO = M.GPACCOUNTNO
    AND Z.FISCALPERIOD = M.FISCALPERIOD
    AND Z.FISCALYEAR = M.FISCALYEAR 

The SQL just runs forever. (i.e. 5 minutes before I lose my patience)

I have verified that my @MONTHS table looks like I intend. I have tried doing a "UNION ALL" with the two tables and it gives me duplicates.

If Table Z does not have a current line for a given account/year/month, I want my @MONTHS table to add that line with a Netchange balance of 0.

Thank you for your help. The full SQL is below.


/* Create in memory table to hold account numbers */
DECLARE @i int
DECLARE @c int
DECLARE @ACCT char(129)
DECLARE @numrows int
DECLARE @numyears int
DECLARE @y int
DECLARE @m int
DECLARE @ACCT_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
account char(129)
)

/* Populate account number table */
INSERT @ACCT_TABLE
select distinct ACTNUMST from SBM01.[dbo].[GL00105]

/* Year table reads available years in the DB */
DECLARE @YEAR_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
YEAR1 smallint
)

/* Populate year table */
INSERT @YEAR_TABLE
SELECT distinct YEAR1 FROM SBM01.dbo.SY40101 ORDER BY YEAR1

/* Create our table of months to UNION to the main accounts */
DECLARE @MONTHS table (
GPACCOUNTNO char(129),
DESCRIPTION char(51),
FISCALYEAR smallint ,
FISCALPERIOD smallint,
FISCALPERIODNAME char(21),
NETCHANGE numeric(19, 5),
PERIODBALANCE numeric(19, 5)
)

/* Here comes the heavy lifting. 
We loop over the account numbers and add year and month values.
*/
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @ACCT_TABLE)
IF @numrows > 0
WHILE(@i <= (SELECT MAX(idx) FROM @ACCT_TABLE))
BEGIN

/* Get the next account number */
SET @ACCT = (SELECT account FROM @ACCT_TABLE WHERE idx = @i)
SET @c = 1
SET @numyears = (SELECT COUNT(*) FROM @YEAR_TABLE)
    WHILE(@c <= (SELECT MAX(idx) FROM @YEAR_TABLE))
    BEGIN
        SET @y = (SELECT YEAR1 FROM @YEAR_TABLE WHERE idx = @c)
        SET @m = '0'
            WHILE(@m < '13')
            BEGIN
                INSERT INTO @MONTHS (GPACCOUNTNO, DESCRIPTION, FISCALPERIOD, FISCALYEAR, FISCALPERIODNAME, NETCHANGE, PERIODBALANCE)
                VALUES (@ACCT, NULL, @m, @y, NULL, '0', NULL)
                SET @m = @m + 1
            END
            SET @c = @c + 1
        END
        SET @i = @i + 1
    END
/* We should now have a populated Database */   

SELECT Z.GPACCOUNTNO, Z.DESCRIPTION, Z.FISCALYEAR, Z.FISCALPERIOD, Z.FISCALPERIODNAME, Z.NETCHANGE, Z.PERIODBALANCE
FROM    ( SELECT    RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
                RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
                A.[YEAR1] AS FISCALYEAR,
                A.[PERIODID] AS FISCALPERIOD,
                E.[PERNAME] AS FISCALPERIODNAME,
                ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
                ( SELECT    ISNULL(SUM(D.[PERDBLNC]), 0)
                  FROM      SBM01.[dbo].[GL10110] D
                  WHERE     D.[ACTINDX] = A.[ACTINDX]
                            AND D.[YEAR1] = A.[YEAR1]
                            AND D.[PERIODID] <= A.[PERIODID]
                ) AS PERIODBALANCE
      FROM      SBM01.[dbo].[GL10110] A
                INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
                INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
                INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
                                                AND E.[PERIODID] = A.[PERIODID]
                                                AND E.[SERIES] = 0
      UNION ALL
      SELECT    RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
                RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
                A.[YEAR1] AS FISCALYEAR,
                A.[PERIODID] AS FISCALPERIOD,
                E.[PERNAME] AS FISCALPERIODNAME,
                ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
                ( SELECT    ISNULL(SUM(D.[PERDBLNC]), 0)
                  FROM      SBM01.[dbo].[GL10111] D
                  WHERE     D.[ACTINDX] = A.[ACTINDX]
                            AND D.[YEAR1] = A.[YEAR1]
                            AND D.[PERIODID] <= A.[PERIODID]
                ) AS PERIODBALANCE
      FROM      SBM01.[dbo].[GL10111] A
                INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
                INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
                INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
                                                AND E.[PERIODID] = A.[PERIODID]
                                                AND E.[SERIES] = 0
) Z
RIGHT JOIN @MONTHS M 
    ON Z.GPACCOUNTNO = M.GPACCOUNTNO
    AND Z.FISCALPERIOD = M.FISCALPERIOD
    AND Z.FISCALYEAR = M.FISCALYEAR 
ORDER BY Z.[GPACCOUNTNO],
     M.[FISCALYEAR],
     M.[FISCALPERIOD]
Jason Maggard
  • 1,632
  • 1
  • 16
  • 21

2 Answers2

1

You can use a SQL case statement to join when null

CREATE TABLE #TMP
(
    id int,
    [month] datetime
)
INSERT INTO #TMP(id,[month])values(1,GETDATE())
INSERT INTO #TMP(id,[month])values(2,null)
INSERT INTO #TMP(id,[month])values(3,GETDATE())
INSERT INTO #TMP(id,[month])values(4,GETDATE())

CREATE TABLE #TMP2
(
    id int,
    [month] datetime
)
INSERT INTO #TMP2(id,[month])values(1,GETDATE())
INSERT INTO #TMP2(id,[month])values(2,GETDATE())
INSERT INTO #TMP2(id,[month])values(3,GETDATE())
INSERT INTO #TMP2(id,[month])values(4,GETDATE())

select * from #TMP
select * from #TMP2


SELECT #TMP.[id], case when #TMP.[month] is null then #TMP2.[month] else #TMP.month end
from #tmp
inner join #tmp2 on #tmp.id= #tmp2.id

drop table #tmp,#tmp2
1

Why don't you use the @Months table as the starting point (since it already gives you all the months you need) and fill-in the values from Z if they are available?

SELECT 
M.GPACCOUNTNO, 
M.DESCRIPTION, 
M.FISCALYEAR, 
M.FISCALPERIOD, 
M.FISCALPERIODNAME, 
ISNULL(Z.NETCHANGE, 0) as NETCHANGE
ISNULL(Z.PERIODBALANCE, 0) as PERIODBALANCE
FROM @MONTHS M
LEFT JOIN Z
    ON Z.GPACCOUNTNO = M.GPACCOUNTNO
    AND Z.FISCALPERIOD = M.FISCALPERIOD
    AND Z.FISCALYEAR = M.FISCALYEAR 
Vishal Bardoloi
  • 652
  • 5
  • 18
  • If you look at the full code, table Z is a huge mess of joins, etc... How does the syntax work? ` SELECT M.GPACCOUNTNO, M.DESCRIPTION, M.FISCALYEAR, M.FISCALPERIOD, M.FISCALPERIODNAME, ISNULL(Z.NETCHANGE, 0) as NETCHANGE ISNULL(Z.PERIODBALANCE, 0) as PERIODBALANCE FROM @MONTHS M LEFT JOIN ( SELECT BLAH FROM BLAH) Z ON Z.GPACCOUNTNO = M.GPACCOUNTNO AND Z.FISCALPERIOD = M.FISCALPERIOD AND Z.FISCALYEAR = M.FISCALYEAR ORDER BY Z.[GPACCOUNTNO], M.[FISCALYEAR], M.[FISCALPERIOD]` – Jason Maggard Aug 22 '12 at 14:31
  • Create Z as a temp table first, piece-by-piece, instead of creating it in one long SQL statement. Easier to read and easier for you to manipulate. You can also isolate issues with the Z table and optimize that query. Right now you can't tell where your performance bottlenecks are. – Vishal Bardoloi Aug 22 '12 at 14:36
  • If you look at the full code, table Z is a huge mess of joins, etc... How does the syntax work? `SELECT -STUFF- FROM @MONTHS M LEFT JOIN (SELECT BLAH FROM BLAH) Z ON Z.GPACCOUNTNO = M.GPACCOUNTNO AND Z.FISCALPERIOD = M.FISCALPERIOD AND Z.FISCALYEAR = M.FISCALYEAR ` Isn't working for me. – Jason Maggard Aug 22 '12 at 14:38
  • You need to be more specific about what errors you're seeing, "Isn't working for me" does not help. Is the query is returning incorrect values? That can be fixed. Is it giving you SQL errors? Check your syntax. Taking a long time to run? Create Z as a temp table first like I mentioned, instead of directly creating it as a subquery. – Vishal Bardoloi Aug 22 '12 at 14:43
  • Ahhh, I copied and pasted the above and we're missing a comma after NETCHANGE. Once I started typing it out manually I saw the error. So that is the right syntax. @Vishy B, thank you so much, that was dead on. If I could approve your answer twice, I would. – Jason Maggard Aug 22 '12 at 15:03
  • Just out of curiosity, I did it both ways, with Z as a temp table and as a subquery. It takes 1:00 as a temp table and 2:48 as a subquery. Coming from other development environments, I'm used to inline being faster, so I was surprised. Thanks for the tip! – Jason Maggard Aug 22 '12 at 15:11