определять действия за определенный период времени PHP MySQL

#php #mysql #mysql-variables

#php #mysql #mysql-переменные

Вопрос:

У меня нет никакого кода или базы данных для отображения, потому что я нахожусь на стадии планирования, и я не могу понять, как правильно это сделать.

Я хочу определить, выполнял ли пользователь определенное действие каждый день в течение недели. Если они есть, я хочу выполнить действие. Каждый раз, когда происходит перерыв в днях, мне нужно выполнить сброс.

Так, например:

 Day 1 | task performed 25 times
Day 2 | task performed 13 times
Day 3 | task performed 18 times
Day 4 | task not performed... start over at Day 1.
.....
Day 1 | task performed 3 times
Day 2 | task performed 11 times
Day 3 | task performed 14 times
Day 4 | task performed 7 times
Day 5 | task performed 3 times 
Day 6 | task performed 10 times
Day 7 | task performed 23 times
 

echo ‘Вы успешно выполнили 71 задачу последовательно в течение 7 дней’;

Я думаю, возникает реальный вопрос: каков наилучший способ добиться этого? Должен ли я попытаться сохранить 7 файлов cookie на основе даты и уничтожить все существующие файлы cookie, если самому новому значению cookie более 24 часов? Должен ли я попробовать установить и обновить дату через базу данных?

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

Обновления

Итак, я пытаюсь спланировать это, используя базу данных, и я просто сталкиваюсь с проблемами со всех сторон.

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

Если я задаю таблицу, это ЧРЕЗВЫЧАЙНО сложно, поскольку мне приходится основывать значение на последовательных датах. Поэтому я не могу выполнить простой 7-дневный поиск, я должен проверить, что каждый результат находится в течение 24 часов после предыдущего результата, установленного в базе данных, иначе как бы я мог отличить кого-то, кто выполнил задачу в день 1, 3 и 7, от того, кто сделал это 1, 2, 3, 4, 5, 6 и 7.

Очистка базы данных не менее хлопотна. Как бы я сделал очистку. Я не могу просто проверить, что данные находятся в течение 7 дней с текущей даты, потому что это не учитывает, что кто-то выполняет задачи на 5-й день, но не на шестой день … а затем на 7-й день… и в равной степени это сложно, потому что у каждого пользователя будет разная дата начала. Итак, я, возможно, запустил задачи сегодня, а другой пользователь 5 дней назад. Я могу с уверенностью предположить, что все даты старше 7 дней истекли, но это на самом деле не помогает определять перерывы в днях.

Я так запутался, как на самом деле выполнить эту задачу.

Комментарии:

1. Я могу предложить схему немного позже, после того, как я сделаю несколько вещей, и вы внесете любые другие изменения. Но определите задачи, которые пользователь выполняет в этот промежуток времени, и если они фиксированы (этот список) на дату и время начала пользователя всего этого. Это действительно упрощенная модель

2. Задача является единственной. Я работаю над созданием системы бейджей для обмена трафиком. Я пытаюсь присвоить значок пользователю, если он посещал биржу в течение 7 дней подряд. Итак, задача — «загруженная пользователем страница surf.php «. Ни больше, ни меньше.

3. Хорошо, итак, у вас нет отдельной таблицы задач с идентификаторами и тому подобным

4. Нет, на самом деле я этого не делаю. Каждый раз, когда пользователь загружает surf.php «Счетчик кредитов» увеличивается (после завершения ввода капчи). Таким образом, на самом деле нет таблицы, которая бы подавала это вообще, хотя я мог бы легко это сделать.

5. Я cookies удалил тег. Вставьте его снова, если сочтете нужным

Ответ №1:

есть несколько способов сделать это.

если вы идете по маршруту db, у вас может быть ссылка из этой скрипки SQL

Я не знаю, насколько интенсивно это будет работать с БД, но я думаю, что это подытожило бы работу, необходимую, если вы идете по этому пути. преимущество этого маршрута в том, что вам не нужно ничего удалять или сбрасывать, чтобы у вас были исторические данные, например, вы можете узнать, сколько «попыток» сделал пользователь, изменив приведенный выше запрос на having count(distinct d) < 7 (он вернет столько строк, сколько пользователь пытался выполнить задачу)

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

 {
   "day1": "2016-09-01",
   "last_task": "2016-09-03",
   "accumulated_task": "56"
}
 

что я подразумеваю под самостоятельным сохранением данных, так это то, что вам необходимо обновлять их каждый раз, когда применяются изменения, например, если текущая дата равна 2016-09-05 и last_task равна 2016-09-03 , тогда вам нужно ее сбросить. преимущество этого маршрута, конечно, в отсутствии накладных расходов на БД, но в большом количестве «ручного труда».

Ответ №2:

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

предположим, вы храните данные в этом формате в базе данных:

 Description | task_id | created 
Task perfor. | 2      | 2016-10-17
Task perfor. | 2      | 2016-10-17
Task perfor. | 2      | 2016-10-18
Task perfor. | 2      | 2016-10-18
 

Вы можете удалить данные, просто выполнив запрос:

 delete from table where created = date
 

Один запрос может очистить ваши данные, это совсем не беспорядочно. Даже огромные базы данных обрабатываются подобным образом.

Комментарии:

1. Проблема в том, что я не могу понять, как это сделать. lol Я продолжаю пытаться настроить план базы данных, и каждый раз возникают проблемы. Я не могу просто установить дату, потому что нет способа определить обновление даты по последнему обновлению даты. Поэтому мне пришлось бы хранить 7 дат. Тогда мне пришлось бы проверить последнюю дату на текущую дату. Если прошло более 24 часов, я должен сбросить все 7 дней ….. и это становится очень грязным и интенсивным использованием базы данных.

2. Это не будет беспорядочно, просто создайте имя столбца created в своей таблице и принимайте решения по запросам на основе этого столбца. Каждая строка будет DataTime сохранена при каждой вставке, и вы можете выполнять запросы на основе этого.

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

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

5. Я собираюсь обновить вопрос, чтобы сделать некоторые из моих проблем более понятными.

Ответ №3:

Для нашего теста предполагается, что идентификатор страницы = 9 … это просматривается, считая значок (7 дней подряд для пользователя, видящего эту страницу). Этот факт был удален из комментариев op (7 дней и значок). Что касается страницы № 9, мы только что сделали это здесь, в этом ответе.

Таким образом, если пользователь просматривает страницу 7 дней подряд, мы хотим, чтобы пользователь был включен в выходные данные. Обратите внимание, номер страницы равен 9.

Загрузка схемы и данных

 create schema db40076704;
use db40076704;

create table pageViews
(   id int auto_increment primary key,
    userId int not null,
    viewDT datetime not null,
    pageId int not null
    -- include decent index choices here
    -- include Foreign Key constraints here
);
truncate pageViews;
insert pageViews (userId,viewDT,pageId) values
(101,'2016-09-05 21:00:00',9),
(101,'2016-09-06 11:00:00',9),
(101,'2016-09-06 15:55:00',9),
(101,'2016-09-06 15:57:00',9),
(101,'2016-09-07 21:00:00',9),
(101,'2016-09-08 21:00:00',999999),
(101,'2016-09-09 21:00:00',9),
(101,'2016-09-10 21:00:00',9),
(101,'2016-09-11 21:00:00',9),

(150,'2016-09-01 21:00:00',9),
(150,'2016-09-06 11:00:00',9),
(150,'2016-09-06 15:55:00',9),
(150,'2016-09-06 15:57:00',9),
(150,'2016-09-07 21:00:00',9),
(150,'2016-09-08 10:44:00',9),
(150,'2016-09-09 21:00:00',9),
(150,'2016-09-10 21:00:00',9),
(150,'2016-09-11 23:00:00',9),
(150,'2016-09-12 23:00:00',9),

(200,'2016-09-08 10:44:00',9),
(200,'2016-09-10 21:00:00',9),
(200,'2016-09-12 21:00:00',9),
(200,'2016-09-14 23:00:00',9),
(200,'2016-09-16 23:00:00',9),
(200,'2016-09-18 23:00:00',9),
(200,'2016-09-20 23:00:00',9);
 

Внутренний запрос, показывающий детали для отладки

 select userId, 
date(viewDT), 
    (@rn := if(@curUser = userId 
            AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn, 
                if(@curUser := GREATEST(userId,-1), @rn 1, @rn 1) 
            ) 
    ) rn, 
@prevDate:=DATE(viewDT) as dummy1 
from pageViews 
join (select @curUser:=-1,@prevDate:='',@rn:=0) params 
where pageId=9 
order by userId,viewDt;
 -------- -------------- ------ ------------ 
| userId | date(viewDT) | rn   | dummy1     |
 -------- -------------- ------ ------------ 
|    101 | 2016-09-05   | 1    | 2016-09-05 |
|    101 | 2016-09-06   | 1    | 2016-09-06 |
|    101 | 2016-09-06   | 1    | 2016-09-06 |
|    101 | 2016-09-06   | 1    | 2016-09-06 |
|    101 | 2016-09-07   | 1    | 2016-09-07 |
|    101 | 2016-09-09   | 2    | 2016-09-09 |
|    101 | 2016-09-10   | 2    | 2016-09-10 |
|    101 | 2016-09-11   | 2    | 2016-09-11 |
|    150 | 2016-09-01   | 3    | 2016-09-01 |
|    150 | 2016-09-06   | 4    | 2016-09-06 |
|    150 | 2016-09-06   | 4    | 2016-09-06 |
|    150 | 2016-09-06   | 4    | 2016-09-06 |
|    150 | 2016-09-07   | 4    | 2016-09-07 |
|    150 | 2016-09-08   | 4    | 2016-09-08 |
|    150 | 2016-09-09   | 4    | 2016-09-09 |
|    150 | 2016-09-10   | 4    | 2016-09-10 |
|    150 | 2016-09-11   | 4    | 2016-09-11 |
|    150 | 2016-09-12   | 4    | 2016-09-12 |
|    200 | 2016-09-08   | 5    | 2016-09-08 |
|    200 | 2016-09-10   | 6    | 2016-09-10 |
|    200 | 2016-09-12   | 7    | 2016-09-12 |
|    200 | 2016-09-14   | 8    | 2016-09-14 |
|    200 | 2016-09-16   | 9    | 2016-09-16 |
|    200 | 2016-09-18   | 10   | 2016-09-18 |
|    200 | 2016-09-20   | 11   | 2016-09-20 |
 -------- -------------- ------ ------------ 
25 rows in set (0.00 sec)
 

Окончательный ответ с использованием приведенного выше

 SELECT userId,rn,count(*) days_In_A_Row 
from 
(   SELECT userId, 
    DATE(viewDT), 
        (@rn := if(@curUser = userId 
                AND (@prevDate=DATE(viewDT) OR @prevDate=DATE_SUB(DATE(viewDT),INTERVAL 1 DAY)), @rn, 
                    if(@curUser := GREATEST(userId,-1), @rn 1, @rn 1) 
                ) 
        ) rn, 
    @prevDate:=DATE(viewDT) as dummy1 
    FROM pageViews 
    JOIN (SELECT @curUser:=-1,@prevDate:='',@rn:=0) params 
    WHERE pageId=9 
    ORDER BY userId,viewDt 
) xDerived 
GROUP BY userId,rn 
HAVING days_In_A_Row>6; 

 -------- ------ --------------- 
| userId | rn   | days_In_A_Row |
 -------- ------ --------------- 
|    150 | 4    |             9 |
 -------- ------ --------------- 
 

Таким образом, пользователь 150 просматривал страницу 9 не менее 7 дней подряд (фактически 9 дней подряд). Этот пользователь получает значок в вашей системе.

Немного информации о переменной mysql (@ variables). Чтобы безопасно использовать переменные, нужно позаботиться о том, чтобы не предполагать, что какой-либо выходной столбец для выбора будет запущен раньше другого. Это факт, четко изложенный на странице руководства, озаглавленной «Определяемые пользователем переменные:

В следующем утверждении вы можете подумать, что MySQL сначала оценит @a, а затем выполнит присваивание вторым:

SELECT @a, @a:=@a 1, ...;

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

Тем не менее, мы знаем, что использование таких функций, как GREATEST(), LEAST() и COALESCE(), будет принудительно иметь более высокий приоритет.

Также бессмысленность в коде НАИБОЛЬШЕГО (N,-1) всегда будет возвращать N. Но нам нужно было принудительно установить приоритет этого столбца, вычисляемого перед

 @prevDate:=DATE(viewDT) as dummy1 
 

линия. Также см. Обязательное чтение книги Барона Шварца «Расширенные методы пользовательских переменных MySQL«.

Комментарии:

1. Это был бы правильный ответ, если бы я строго придерживался базы данных. Однако, поскольку я был открыт для способов сделать это…. Я не могу думать, что будет более быстрый метод, чем предложенный метод json. 0 подключений к базе данных. Очень легкие файлы на fs. Я могу обрабатывать пару миллионов ~ 1k файлов намного проще, чем десятки записей для миллионов пользователей в базе данных 🙂

2. Я думал, вы просили решение для БД, моя вина. Конечно, используйте свои собственные методы без БД и посмотрите, как вам это нравится