• There's no need to join back to the table to do the DELETE. You can delete from the table by deleting from the CTE.

    Here's the OPs original data in a readily consumable format...

    --===== Create and populate a test table on-the-fly

    SET DATEFORMAT DMY

    ;

    SELECT [Timestamp] = CONVERT(DATE ,d.[Timestamp])

    ,Customer = CONVERT(CHAR(1) ,d.Customer)

    ,Data = CONVERT(VARCHAR(10),d.Data)

    INTO #TestTable -- DROP TABLE #TestTable

    FROM (

    SELECT '3/03/2016','A','aaaaa' UNION ALL

    SELECT '1/02/2016','A','bbbbbb' UNION ALL

    SELECT '1/01/2016','A','cccccccc' UNION ALL

    SELECT '1/12/2015','A','aaaaa' UNION ALL

    SELECT '31/10/2015','B','bbbbbb' UNION ALL

    SELECT '30/09/2015','B','cccccccc' UNION ALL

    SELECT '30/08/2015','B','aaaaa' UNION ALL

    SELECT '30/07/2015','B','bbbbbb' UNION ALL

    SELECT '29/06/2015','B','cccccccc'

    ) d ([Timestamp],Customer,Data)

    ;

    Here's the DELETE through the cte. Try it. It works just fine.

    --===== Delete row in the table through the cte

    WITH cteDelete AS

    (

    SELECT Customer

    ,RowNum = ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY [TimeStamp] DESC)

    FROM #TestTable

    )

    DELETE FROM cteDelete

    WHERE RowNum > 3

    ;

    --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)