Add Zero(0) to columns based on Min and Max value of the record.

  • Here min Calendar year is 2010 and max Calendar year is 2013
    How to add Zero to employes who does not have that year

    Input sample:
    SalesamountCalendarYearEmployee
    6370002010282
    34400002011282
    44150002012282
    32940002013282
    18980002011291
    49850002012291
    36310002013291
    4780002012296
    12090002013296
    780002012297


    Output required :

    SalesamountCalendarYearEmployee
    6370002010282
    34400002011282
    44150002012282
    32940002013282
    02010291
    18980002011291
    49850002012291
    36310002013291
    02010296
    02011296
    4780002012296
    12090002013296
    02010297
    02011297
    780002012297
    02013297

  • Do a left join from a table, or virtual, dynamic table, which contains all of the years you wish to display.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Thanks !

    Tried creating left join , but did not work as expected.

    Second tried with tally table with running number in it and found the missing record, but it did not match with  my requirement.

    More of my table have some missing records need to identify them and say as Zero (0).

     

  • I understand your requirement, but unless you post the SQL you have tried, it's difficult to help you any further.

    The absence of evidence is not evidence of absence
    - Martin Rees
    The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
    - Phil Parkin

  • Maybe not the best query, but here's a test. Query embedded in the --ACT section.

    CREATE OR ALTER PROCEDURE tsqltests.[test calendarsales]
    AS
    BEGIN
    ---------------
    -- Assemble
    ---------------
    DECLARE
    @expected INT
    , @actual INT;
    EXEC tsqlt.faketable @TableName = 'CalendarSales', @SchemaName = 'dbo';
    INSERT dbo.CalendarSales
    (SalesAmount
    , CalendarYear
    , Employee)
    VALUES
    (637000, 2010, 282)
    , (3440000, 2011, 282)
    , (4415000, 2012, 282)
    , (3294000, 2013, 282)
    , (1898000, 2011, 291)
    , (4985000, 2012, 291)
    , (3631000, 2013, 291)
    , (478000, 2012, 296)
    , (1209000, 2013, 296)
    , (78000, 2012, 297);
    CREATE TABLE #Expected
    ( SalesAmount INT
    , CalendarYear int
    , Employee INT);
    INSERT #Expected
    (SalesAmount, CalendarYear, Employee)
    VALUES
    (637000, 2010, 282)
    , (3440000, 2011, 282)
    , (4415000, 2012, 282)
    , (3294000, 2013, 282)
    , (0, 2010, 291)
    , (1898000, 2011, 291)
    , (4985000, 2012, 291)
    , (3631000, 2013, 291)
    , (0, 2010, 296)
    , (0, 2011, 296)
    , (478000, 2012, 296)
    , (1209000, 2013, 296)
    , (0, 2010, 297)
    , (0, 2011, 297)
    , (78000, 2012, 297)
    , (0, 2013, 297);
    SELECT TOP 0 SalesAmount, CalendarYear, Employee INTO #Actual FROM
    #Expected;

    ---------------
    -- Act
    ---------------
    WITH cteYear (minyear, maxyear)
    AS
    (SELECT MIN(calendarYEar ) AS minyear
    , MAX(cs.CalendarYear) AS maxyear
    FROM dbo.CalendarSales AS cs
    )
    , cteTally(n)
    AS
    (SELECT n = ROW_NUMBER() OVER (ORDER BY (SELECT null))
    FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) a(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) b(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) c(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) d(n)
    )
    , cteYears (yearnum)
    AS (
    SELECT n
    FROM cteTally
    WHERE n >= (SELECT minyear FROM cteYear)
    AND n <= (SELECT maxyear FROM cteYear)
    )
    , cteEmpYearList (Employee, CalendarYear)
    AS
    (
    SELECT DISTINCT cs.Employee
    , y.yearnum
    FROM dbo.CalendarSales AS cs
    CROSS JOIN cteYears y
    )
    INSERT #Actual
    SELECT
    COALESCE(cs2.SalesAmount, 0) AS SalesAmount
    , cey.CalendarYear
    , cey.Employee
    FROM cteEmpYearList cey
    LEFT OUTER JOIN dbo.CalendarSales AS cs2
    ON cey.Employee = cs2.Employee
    AND cs2.CalendarYear = cey.CalendarYear
    --WHERE cs2.CalendarYear IS NOT null
    ORDER BY cey.Employee, cey.CalendarYear;
    ---------------
    -- Assert
    ---------------
    EXEC tSQLt.AssertEqualsTable
    @Expected = N'#expected'
    , @Actual = N'#actual'
    , @Message = N'The query doesn''t work';
    END;
    GO

    EXEC tsqlt.run 'tsqltests.[test calendarsales]';
  • Thanks Steve ,

    Here is the code i have tried. Knew that it can be done in better way.


    create table #CalendarSales (salesamount decimal(20,4),Calendaryear int,Employee int)
    create table #CalendarSales_final (salesamount decimal(20,4),Calendaryear int,Employee int)

    INSERT #CalendarSales
    (SalesAmount
    , CalendarYear
    , Employee)
    VALUES
    (637000, 2010, 282)
    , (3440000, 2011, 282)
    , (4415000, 2012, 282)
    , (3294000, 2013, 282)
    , (1898000, 2011, 291)
    , (4985000, 2012, 291)
    , (3631000, 2013, 291)
    , (478000, 2012, 296)
    , (1209000, 2013, 296)
    , (78000, 2012, 297);

    Select Distinct Identity(Int,1,1) Rid,Employee into #temp from #CalendarSales

    Select Distinct Calendaryear into #dates from #CalendarSales
    Declare @i int,@j int=1,@Emp int
    Select @i =Rid from #temp

    While @j<=@i
    Begin
    Select @emp=Employee from #temp where Rid=@j
    insert into #CalendarSales_final
    Select ISNULL(c.salesamount,0)salesamount, d.*,@emp from #CalendarSales c Right join #Dates as d on c.Calendaryear=d.Calendaryear and Employee in (Select t. Employee from #temp as t where Rid=@j)
    Set @j=@j+1
    end

    Select * from #CalendarSales_final

    Drop table #temp
    drop table #CalendarSales
    drop table #CalendarSales_final
    Drop table #dates

     

  • Steve Jones - SSC Editor wrote:

    Maybe not the best query, but here's a test. Query embedded in the --ACT section.

    CREATE OR ALTER PROCEDURE tsqltests.[test calendarsales]
    AS
    BEGIN
    ---------------
    -- Assemble
    ---------------
    DECLARE
    @expected INT
    , @actual INT;
    EXEC tsqlt.faketable @TableName = 'CalendarSales', @SchemaName = 'dbo';
    INSERT dbo.CalendarSales
    (SalesAmount
    , CalendarYear
    , Employee)
    VALUES
    (637000, 2010, 282)
    , (3440000, 2011, 282)
    , (4415000, 2012, 282)
    , (3294000, 2013, 282)
    , (1898000, 2011, 291)
    , (4985000, 2012, 291)
    , (3631000, 2013, 291)
    , (478000, 2012, 296)
    , (1209000, 2013, 296)
    , (78000, 2012, 297);
    CREATE TABLE #Expected
    ( SalesAmount INT
    , CalendarYear int
    , Employee INT);
    INSERT #Expected
    (SalesAmount, CalendarYear, Employee)
    VALUES
    (637000, 2010, 282)
    , (3440000, 2011, 282)
    , (4415000, 2012, 282)
    , (3294000, 2013, 282)
    , (0, 2010, 291)
    , (1898000, 2011, 291)
    , (4985000, 2012, 291)
    , (3631000, 2013, 291)
    , (0, 2010, 296)
    , (0, 2011, 296)
    , (478000, 2012, 296)
    , (1209000, 2013, 296)
    , (0, 2010, 297)
    , (0, 2011, 297)
    , (78000, 2012, 297)
    , (0, 2013, 297);
    SELECT TOP 0 SalesAmount, CalendarYear, Employee INTO #Actual FROM
    #Expected;

    ---------------
    -- Act
    ---------------
    WITH cteYear (minyear, maxyear)
    AS
    (SELECT MIN(calendarYEar ) AS minyear
    , MAX(cs.CalendarYear) AS maxyear
    FROM dbo.CalendarSales AS cs
    )
    , cteTally(n)
    AS
    (SELECT n = ROW_NUMBER() OVER (ORDER BY (SELECT null))
    FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) a(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) b(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) c(n)
    CROSS JOIN (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) d(n)
    )
    , cteYears (yearnum)
    AS (
    SELECT n
    FROM cteTally
    WHERE n >= (SELECT minyear FROM cteYear)
    AND n <= (SELECT maxyear FROM cteYear)
    )
    , cteEmpYearList (Employee, CalendarYear)
    AS
    (
    SELECT DISTINCT cs.Employee
    , y.yearnum
    FROM dbo.CalendarSales AS cs
    CROSS JOIN cteYears y
    )
    INSERT #Actual
    SELECT
    COALESCE(cs2.SalesAmount, 0) AS SalesAmount
    , cey.CalendarYear
    , cey.Employee
    FROM cteEmpYearList cey
    LEFT OUTER JOIN dbo.CalendarSales AS cs2
    ON cey.Employee = cs2.Employee
    AND cs2.CalendarYear = cey.CalendarYear
    --WHERE cs2.CalendarYear IS NOT null
    ORDER BY cey.Employee, cey.CalendarYear;
    ---------------
    -- Assert
    ---------------
    EXEC tSQLt.AssertEqualsTable
    @Expected = N'#expected'
    , @Actual = N'#actual'
    , @Message = N'The query doesn''t work';
    END;
    GO

    EXEC tsqlt.run 'tsqltests.[test calendarsales]';

    The problem with this code is that it will produce the full output of the tally CTE before filtering it, in this case 10000 rows.

    😎

    Here is an example on how to limit the tally CTE output to the exact number of rows needed

    USE TEEST;
    GO
    SET NOCOUNT ON;

    --Input sample:
    ;WITH SAMPLE_DATA(Salesamount,CalendarYear,Employee) AS
    (
    SELECT 637000,2010,282 UNION ALL
    SELECT 3440000,2011,282 UNION ALL
    SELECT 4415000,2012,282 UNION ALL
    SELECT 3294000,2013,282 UNION ALL
    SELECT 1898000,2011,291 UNION ALL
    SELECT 4985000,2012,291 UNION ALL
    SELECT 3631000,2013,291 UNION ALL
    SELECT 478000,2012,296 UNION ALL
    SELECT 1209000,2013,296 UNION ALL
    SELECT 78000,2012,297
    )
    ,T(N) AS (SELECT X.N FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) X(N))
    ,YEARSTAT(STY,NY) AS
    (
    SELECT
    MIN(SD.CalendarYear) AS STY
    ,1 + (MAX(SD.CalendarYear) - MIN(SD.CalendarYear)) AS NY
    FROM SAMPLE_DATA SD
    )
    ,CALENDAR(YR) AS
    (
    SELECT
    TOP((SELECT YS.NY FROM YEARSTAT YS))
    YS.STY + (ROW_NUMBER() OVER (ORDER BY @@VERSION) - 1)
    FROM T T1,T T2
    CROSS APPLY YEARSTAT YS
    )
    ,EMP_LIST AS
    (
    SELECT DISTINCT
    SD.Employee EMP
    FROM SAMPLE_DATA SD
    )
    ,EMP_YEAR_LIST(EMP,YR) AS
    (
    SELECT
    EL.EMP
    ,CR.YR
    FROM CALENDAR CR
    CROSS APPLY EMP_LIST EL
    )
    SELECT
    ISNULL(SD.Salesamount,0) AS Salesamount
    ,EYL.YR AS CalendarYear
    ,EYL.EMP AS Employee
    FROM EMP_YEAR_LIST EYL
    LEFT OUTER JOIN SAMPLE_DATA SD
    ON EYL.EMP = SD.Employee
    AND EYL.YR = SD.CalendarYear
    ORDER BY EYL.EMP ASC
    ,EYL.YR ASC
    ;

     

Viewing 7 posts - 1 through 6 (of 6 total)

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