Как получить D1 D7 D30 без левого соединения на одном столе - PullRequest
3 голосов
/ 03 мая 2019

Цель:

Я хотел бы знать всех, кто зарегистрировался в День 0, сколько из них вошли в систему после D1, после D7 и после D30. Я хотел бы сделать табличную функцию, где пользователи вставляют дату и получают результаты для D0, D1, D7, D30. Результаты должны выглядеть так:

Date        TotalD0 TotalD1 TotalD7 TotalD30
2019-04-01    3         3      2       1

Положение:

У меня есть одна таблица входа с адресом электронной почты и login_time. Я ушел три раза за один стол, и он работал на пустом столе. Однако при использовании реальных данных с миллионами строк они выполняются вечно. Должен быть более эффективный способ сделать это.

Что я пробовал:

CREATE FUNCTION fnTestData
(
    @StartDate AS Date
)
RETURNS TABLE
AS
RETURN
    select @startdate, 
       COUNT(distinct t1.id) As TotalD0, 
       COUNT(distinct t1a.id) As TotalD1,
       COUNT(distinct t1b.id) As TotalD7,
       COUNT(distinct t1c.id) As TotalD30
    from #test1 t1
       left join #test1 t1a on t1.id=t1a.id and t1a.login_time >= 
             DATEADD(day,1,t1.login_time)
       left join #test1 t1b on t1.id=t1b.id and t1b.login_time >= 
             DATEADD(day,7,t1.login_time)
       left join #test1 t1c on t1.id=t1c.id and t1c.login_time >= 
             DATEADD(day,30,t1.login_time)
    where t1.login_time = @startdate
    group by t1.login_time

Данные испытаний:

create table #test1 (id int, login_time date)
insert into #test1 values
(1, '2019-04-01'),
(1, '2019-04-01'),
(1, '2019-04-02'),
(1, '2019-04-19'),
(1, '2019-05-05'),
(2, '2019-04-01'),
(2, '2019-04-05'),
(2, '2019-04-10'),
(2, '2019-04-15'),
(3, '2019-04-01'),
(3, '2019-04-01'),
(3, '2019-04-02')

Ответы [ 2 ]

2 голосов
/ 03 мая 2019

Ваш запрос может быть переведен в GROUP BY:

DECLARE @StartDate Date = '2019-04-01'

SELECT COUNT(DISTINCT id) D0
     , COUNT(DISTINCT CASE WHEN login_time >= DATEADD(DAY,  1, @StartDate) THEN id END) AS D1
     , COUNT(DISTINCT CASE WHEN login_time >= DATEADD(DAY,  7, @StartDate) THEN id END) AS D7
     , COUNT(DISTINCT CASE WHEN login_time >= DATEADD(DAY, 30, @StartDate) THEN id END) AS D30
FROM #test1 AS t
WHERE login_time >= @StartDate
AND EXISTS (
    SELECT 1
    FROM #test1 AS x
    WHERE x.id = t.id
    AND x.login_time = @StartDate
)
D0    D1    D7    D30
3     3     2     1

Вам нужно создать соответствующие индексы, чтобы ускорить его.

1 голос
/ 03 мая 2019

Если вы хотите провести когортный анализ на основе дня, когда люди начинают:

select first_ld,
       count(*) as num_d0,
       sum(case when login_date >= dateadd(day, 1, firstld) then 1 else 0 end) as num_d1,
       sum(case when login_date >= dateadd(day, 7, firstld) then 1 else 0 end) as num_d7,
       sum(case when login_date >= dateadd(day, 30, firstld) then 1 else 0 end) as num_d30
from (select id, convert(date, login_time) as login_date,
             min(convert(date, login_time)) over (partition by id) as first_ld
      from #test1 t
      group by id, convert(date, login_time)
     ) t
group by first_ld
order by first_ld;
...