• I've been doing some testing of the other solutions in the article and comments (still have some to go, including another from Peso that might beat the rest).

    Peso's version in the body of the article is probably the most clever/elegant to my eyes so far, but is beaten on performance by a couple versions in the comments.

    His own #6 solution is significantly faster percentage-wise, and dova's query is faster still, by a narrow margin.

    dova's isn't quite to spec, though, since his query only works by getting the MIN and MAX dt from DailyVisits and using that. It can be modified to accept variables for start and end, but that prevents its most efficient query plan, and it then becomes very, very slow.

    Just to make it more accessible, here are Peso's solutions from the body of the article and the comments (just the #6), with some formatting applied:to remove all the white space and sprawl in the former case, and to provide any formatting at all in the latter case:

    I also have the variables set to the range used in Steve's test data, not the test harness they used to test their solutions, as an FYI. Further, do note that these solutions require the GetDates function they define in the article (just a cascading CTE tally to generate all the dates in the range).

    DECLARE
    @from AS DATE = '20110101',
    @to AS DATE = '20161231';

    WITH cteSource(dt, NumVisits, Added, Removed)
    AS
    (
    SELECT  dt,
        SUM(NumVisits) AS NumVisits,
        SUM(Added) AS Added,
        SUM(Removed) AS Removed
    FROM  (
        SELECT DATEADD(DAY, f.DayDelta, w.dt) AS dt,
          w.Visitor,
          f.NumVisits,
          f.Added,
          f.Removed
        FROM dbo.DailyVisits AS w
          CROSS JOIN
          (
          VALUES (0, 1, 1, -1),
             (1, 0, -1, 1)
          ) AS f(DayDelta, NumVisits, Added, Removed)
        WHERE w.dt BETWEEN DATEADD(DAY, -1, @From) AND @To
        ) AS d
    WHERE  dt BETWEEN @From AND @To
    GROUP BY dt,
        Visitor
    )

    SELECT dt,
       SUM(NumVisits) AS NumVisits,
       SUM(Added) AS Added,
       SUM(Removed) AS Removed,
       SUM(Remained) AS Remained
    FROM  (
       SELECT  dt,
           SUM(NumVisits) AS NumVisits,
           SUM(CASE WHEN Added = 1 THEN 1 ELSE 0 END) AS Added,
           SUM(CASE WHEN Removed = 1 THEN 1 ELSE 0 END) AS Removed,
           SUM(CASE WHEN 1 IN (Added, Removed) THEN 0 ELSE 1 END) AS Remained
       FROM  cteSource
       GROUP BY dt
       UNION ALL
       SELECT dt,
          0 AS NumVisits,
          0 AS Added,
          0 AS Removed,
          0 AS Remained
       FROM  dbo.GetDates(@From, @To)
       ) AS d
    GROUP BY dt;

    And the #6:

    DECLARE
    @from AS DATE = '20110101',
    @to AS DATE = '20161231';

    WITH cte AS
    (
    SELECT    f.dt,
       f.NumVisits,
       f.Visitor,
       f.Added,
       f.Removed,
       f.Remained
    FROM  dbo.GetDates(@From, @To) AS gd
       OUTER APPLY
       (
       SELECT
       q.dt,
       q.Visitor,
       SUM(q.NumVisits) AS NumVisits,
       CASE WHEN SUM(q.Added) > 0 THEN 1 ELSE 0 END AS Added,
       CASE WHEN SUM(q.Removed) > 0 THEN 1 ELSE 0 END AS Removed,
       CASE WHEN COUNT(*) = 2 THEN 1 ELSE 0 END AS Remained
       FROM
       (
       SELECT gd.dt,
         d.Visitor,
         1 - d.theDiff AS NumVisits,
         1 - 2 * d.theDiff AS Added,
         2 * d.theDiff - 1 AS Removed
       FROM (
         SELECT dv.Visitor,
           CASE WHEN dv.dt = gd.dt THEN 0 ELSE 1 END AS theDiff
         FROM    dbo.DailyVisits AS dv
         WHERE dv.dt BETWEEN DATEADD(DAY, -1, gd.dt) AND gd.dt
         ) AS d
       ) AS q
       GROUP BY q.dt,
          q.Visitor
       ) AS f
    )

    SELECT dt,
       SUM(NumVisits) AS NumVisits,
       SUM(Added) AS Added,
       SUM(Removed) AS Removed,
       SUM(Remained) AS Remained
    FROM  cte
    GROUP BY dt;

    Cheers!