sql >> Database >  >> RDS >> Mysql

Tel actieve gebruikers met behulp van inlogtijdstempel in MySQL

Ik ga zo'n idee demonstreren op basis van wat voor mij het meest logisch is en de manier waarop ik zou antwoorden als de vraag hetzelfde zou worden gesteld als hier:

Laten we eerst een dataset als zodanig aannemen, we zullen de tabel logins . noemen :

+---------+---------------------+
| 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 |
|   ...   |          ...        |
+---------+---------------------+

Er kunnen andere kolommen zijn, maar die vinden wij niet erg.

Allereerst moeten we de grenzen van die week bepalen, daarvoor kunnen we ADDDATE() gebruiken . Gecombineerd met het idee dat de datum van vandaag - de weekdag van vandaag (MySQL's DAYOFWEEK() ), is de datum van zondag.

Bijvoorbeeld:als het vandaag woensdag de 10e is, Wed - 3 = Sun , dus 10 - 3 = 7 , en we kunnen verwachten dat zondag de 7e is.

We kunnen WeekStart . krijgen en WeekEnd tijdstempels op deze manier:

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;

Opmerking:in PostgreSQL is er een DATE_TRUNC() functie die het begin van een opgegeven tijdseenheid retourneert, gegeven een datum, zoals start van de week, maand, uur, enzovoort. Maar dat is niet beschikbaar in MySQL.

Laten we vervolgens WeekStart en weekEnd gebruiken om onze dataset te selecteren. In dit voorbeeld laat ik alleen zien hoe je kunt filteren, met behulp van hard gecodeerde datums:

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

Dit zou onze dataset gesegmenteerd moeten retourneren, met alleen relevante resultaten:

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

We kunnen dan onze resultatenset terugbrengen tot alleen de user_id s, en filter duplicaten uit. tel dan, op deze manier:

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 zal duplicaten uitfilteren en count geeft alleen het bedrag terug.

Gecombineerd wordt dit:

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")

Vervang CURDATE() met een tijdstempel om het aantal gebruikersaanmeldingen van die week te krijgen.

Maar ik moet dit opdelen in dagen, ik hoor je huilen. Natuurlijk! en zo:

Laten we eerst onze over-informatieve tijdstempels vertalen naar alleen de datumgegevens. We voegen DISTINCT . toe omdat we het niet erg vinden dat dezelfde gebruiker twee keer op dezelfde dag inlogt. we tellen gebruikers, niet logins, toch? (merk op dat we hier een stap terug doen):

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

Dit levert:

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

Deze vraag zullen we afsluiten met een tweede, om de verschijningen van elke datum te tellen:

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`

We gebruiken telling en een groepering om de lijst op datum te krijgen, die als resultaat geeft:

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

En na al het harde werken, beide gecombineerd:

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`;

Geeft u een dagelijkse uitsplitsing van logins per dag in deze week. Nogmaals, vervang CURDATE() om een ​​andere week te krijgen.

Wat betreft de gebruikers zelf die zich hebben aangemeld, laten we dezelfde dingen in een andere volgorde combineren:

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

Ik heb twee innerlijke vragen, de eerste is logins :

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

Biedt de lijst met gebruikers en de dagen waarop ze zich hebben aangemeld, zonder duplicaten.

Dan hebben we logincounts :

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

Zal dezelfde lijst retourneren, met een telling van het aantal logins dat elke gebruiker had.

En tot slot:SELECT user_id VAN logincounts -- Zie vorige subquery.WHERE login_count> 6

Het filteren van degenen die niet 7 keer hebben ingelogd en de datumkolom laten vallen.

Dit werd een beetje lang, maar ik denk dat het bol staat van de ideeën en ik denk dat het zeker kan helpen om op een interessante manier te antwoorden in een werkinterview. :)



  1. Zoek en verwijder dubbele rijen met twee kolommen

  2. Een object (meer dan 10 eigenschappen) invoegen in mysql via mybatis op basis van annotatie zonder alle eigenschappen op te sommen

  3. Een postgres-back-upbestand herstellen via de opdrachtregel?

  4. Een groot sql-bestand importeren naar MySql via de opdrachtregel