Mysql
 sql >> Database >  >> RDS >> Mysql

Conta gli utenti attivi utilizzando il timestamp di accesso in MySQL

Dimostrerò un'idea del genere basata su ciò che ha più senso per me e sul modo in cui risponderei se la domanda fosse presentata come qui:

Per prima cosa, assumiamo un set di dati in quanto tale, chiameremo la tabella logins :

+---------+---------------------+
| user_id |   login_timestamp   |
+---------+---------------------+
|       1 | 2015-09-29 14:05:05 |
|       2 | 2015-09-29 14:05:08 |
|       1 | 2015-09-29 14:05:12 |
|       4 | 2015-09-22 14:05:18 |
|   ...   |          ...        |
+---------+---------------------+

Potrebbero esserci altre colonne, ma quelle non ci interessano.

Prima di tutto dovremmo determinare i confini di quella settimana, per questo possiamo usare ADDDATE() . Combinato con l'idea che la data di oggi è il giorno della settimana di oggi (DAYOFWEEK() di MySQL) ), è la data di domenica.

Ad esempio:se oggi è mercoledì 10, Wed - 3 = Sun , quindi 10 - 3 = 7 , e possiamo aspettarci che domenica sia il 7.

Possiamo ottenere WeekStart e WeekEnd timestamp in questo modo:

SELECT
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") WeekStart, 
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59") WeekEnd;

Nota:in PostgreSQL c'è un DATE_TRUNC() funzione che restituisce l'inizio di un'unità di tempo specificata, data una data, come inizio settimana, mese, ora e così via. Ma non è disponibile in MySQL.

Quindi, utilizziamo WeekStart e weekEnd per fare clic sul nostro set di dati, in questo esempio mostrerò solo come filtrare, utilizzando date codificate:

SELECT *
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'

Questo dovrebbe restituire il nostro set di dati affettato, con solo risultati rilevanti:

+---------+---------------------+
| user_id |   login_timestamp   |
+---------+---------------------+
|       2 | 2015-09-29 14:05:08 |
|       1 | 2015-09-29 14:05:12 |
+---------+---------------------+

Possiamo quindi ridurre il nostro set di risultati solo a user_id se filtra i duplicati. poi conta, in questo modo:

SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'

DISTINCT filtrerà i duplicati e il conteggio restituirà solo l'importo.

Combinato, questo diventa:

SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp 
    BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") 
        AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")

Sostituisci CURDATE() con qualsiasi timestamp per ottenere il conteggio degli accessi utente di quella settimana.

Ma ho bisogno di scomporlo in giorni, ti sento piangere. Certamente! ed ecco come:

Innanzitutto, traduciamo i nostri timestamp eccessivamente informativi solo nei dati della data. Aggiungiamo DISTINCT perché non ci dispiace che lo stesso utente acceda due volte lo stesso giorno. contiamo gli utenti, non gli accessi, giusto? (nota che facciamo un passo indietro qui):

SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d")
FROM `logins`

Questo produce:

+---------+-----------------+
| user_id | login_timestamp |
+---------+-----------------+
|       1 | 2015-09-29      |
|       2 | 2015-09-29      |
|       4 | 2015-09-22      |
|   ...   |        ...      |
+---------+-----------------+

Questa query verrà chiusa con un secondo, al fine di contare le apparizioni di ogni data:

SELECT `login_timestamp`, count(*) AS 'count'
FROM (SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp` FROM `logins`) `loginsMod`
GROUP BY `login_timestamp`

Usiamo il conteggio e un raggruppamento per ottenere l'elenco per data, che restituisce:

+-----------------+-------+
| login_timestamp | count |
+-----------------+-------+
| 2015-09-29      | 1     +
| 2015-09-22      | 2     +
+-----------------+-------+

E dopo tutto il duro lavoro, entrambi combinati:

SELECT `login_timestamp`, COUNT(*)
FROM (
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp`
FROM `logins`
WHERE login_timestamp BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")) `loginsMod`
GROUP BY `login_timestamp`;

Ti fornirà un'analisi giornaliera degli accessi giornalieri in questa settimana. Di nuovo, sostituisci CURDATE() per avere una settimana diversa.

Per quanto riguarda gli utenti stessi che hanno effettuato l'accesso, uniamo le stesse cose in un ordine diverso:

SELECT `user_id`
FROM (
    SELECT `user_id`, COUNT(*) AS `login_count`
    FROM (
        SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
        FROM `logins`) `logins`
    GROUP BY `user_id`) `logincounts`
WHERE `login_count` > 6

Ho due query interne, la prima è logins :

SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`

Fornirà l'elenco degli utenti e i giorni in cui hanno effettuato l'accesso, senza duplicati.

Quindi abbiamo logincounts :

SELECT `user_id`, COUNT(*) AS `login_count`
FROM `logins` -- See previous subquery.
GROUP BY `user_id`) `logincounts`

Restituirà lo stesso elenco, con il conteggio di quanti accessi ha avuto ogni utente.

E infine:SELEZIONA user_id DA logincounts -- Vedi sottoquery precedente.WHERE login_count> 6

Filtrando quelli che non hanno effettuato l'accesso 7 volte e rilasciando la colonna della data.

È passato un po' di tempo, ma penso che sia pieno di idee e penso che possa sicuramente aiutare a rispondere in modo interessante a un colloquio di lavoro. :)