Рассчитать повторяющегося пользователя на 12 месяцев с SQL - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь понять, есть ли лучший способ добиться того, что я делаю сейчас.Например, мне нужно знать общее количество пользователей, которые вошли в систему за последние 12 месяцев.Таким образом, каждый пользователь, который входил в систему не менее одного раза в месяц, в течение двенадцати месяцев подряд, будет учитываться при подсчете.

Я делаю это прямо сейчас: я запрашиваю свою таблицу и получаю все идентификаторы пользователейи отметки времени, когда они были активны и вернуть их в мой код C #.Затем, с помощью набора циклов и LINQ, я вычисляю значение (слишком много кода, чтобы разобраться с этим вопросом, и, поскольку я пытаюсь избавиться от этого в c #, я не верю, что в этом есть необходимость).

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

Для ответа я надеюсь либо получить пример, либо ссылку на аналогичный вопрос SO, либостатья, в которой говорится о достижении этого.

Пример MyUsersTable:

UserId | Timestamp
1      | '2018-12-23 00:00:00.000'
1      | '2018-11-23 00:00:00.000'
1      | '2018-10-23 00:00:00.000'

РЕДАКТИРОВАТЬ: Я думал об использовании SUM(CASE WHEN month = 1 and month = 2 and month = 3), но это также не очень хорошее решение.

Ожидаемый результат:

Общее количество пользователей, которые были активны хотя бы раз в месяц за последние 12 месяцев.

Ответы [ 3 ]

0 голосов
/ 31 января 2019

Я бы посчитал, сколько месяцев пользователь вошел в систему:

SELECT   userid
FROM     mytable
WHERE    YEAR(timestamp) = 2018
GROUP BY userid
HAVING   COUNT(DISTINCT MONTH(timestamp)) = 12
0 голосов
/ 31 января 2019

Чтобы получить идентификаторы пользователей, которые входили в систему в течение определенного количества последовательных месяцев, вы можете использовать:

/* These are your input values */
DECLARE @searchDate date = '2018-12-15' ;
DECLARE @monthsToSearch int = 12 ;

 /* First day of search month */    
DECLARE @EndDate   date = DATEADD(month, DATEDIFF(month, 0, @searchDate), 0) ;
 /* First day of month to search from */
DECLARE @StartDate date = DATEADD(month, -@monthsToSearch, @EndDate) ;

SELECT userID --, @StartDate AS startDate, @EndDate AS endDate
FROM (
    SELECT userID,  ( (YEAR(userLoginDT)*100)+MONTH(userLoginDT) ) AS datePoint /* YYYYMM */
    FROM t1
    WHERE userLoginDT >= @StartDate
        AND userLoginDT < @EndDate
) s1
GROUP BY userID
HAVING count(distinct(datePoint)) = @monthsToSearch
;

См. db <> fiddle здесь для моих примеров.

Первые две объявленные переменные являются вашими входными переменными.Вы указываете дату, за которую запускаете отчет, а затем указываете, на сколько месяцев вы хотите вернуться.Таким образом, вы можете искать любое количество месяцев.После этого это в значительной степени манипулирование датами и математика.

@EndDate по существу берет вашу объявленную дату и вычисляет первый день месяца, в котором вы в настоящее время ищете. Вы будете искать любые даты до этой даты.

@StartDate отсчитывает отваш @EndDate для расчета количества месяцев, которые вы хотите найти.

(YEAR(userLoginDT)*100)+MONTH(userLoginDT) в вашем под-выборе создает целочисленную переменную, которую вы можете GROUP BY, чтобы получить различное количество месяцев, в течение которых вы ищете.Эта часть может быть ускорена с помощью таблицы календаря.

Затем вы просто используете HAVING, чтобы выбрать, сколько разных записей вы хотите для @monthsToSearch.


ПРИМЕЧАНИЕ: Как многие здесь могут подтвердить, я большой поклонник работы с таблицами календаря при работе с расчетами дат и большими объемами поисковых данных.Нечто подобное, скорее всего, немного ускорит запрос.

0 голосов
/ 31 января 2019

Если вам нужны пользователи, которые заходили каждый месяц в 2018 году:

select ut.userid
from MyUsersTable ut
where timestamp >= '2018-01-01' and timestamp < '2019-01-01'
group by ut.userid
having count(distinct month(timestamp)) = 12;
...