• I ran into this method in an Itzik Ben-Gan article, which looks more complicated, but of course somehow manages to run a bit faster where I've tested it against a single CTE with ROW_NUMBER() involved, I guess because there's no ORDER BY used anywhere?

    ;WITH dupe1

    AS ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RN ,

    [FirstName]

    FROM dbo.Emp_Salary

    ),

    dupe2

    AS ( SELECT [FirstName] ,

    MAX(RN) AS [MAX]

    FROM dupe1

    GROUP BY [FirstName]

    HAVING COUNT(*) > 1

    )

    SELECT d1.*

    --DELETE d1

    FROM dupe1 d1

    INNER JOIN dupe2 d2

    ON d1.[FirstName] = d2.[FirstName]

    AND d1.RN < d2.[MAX];