Mysql
 sql >> Base de données >  >> RDS >> Mysql

mysql sélectionne le nombre de lignes entre la période

OK, je me rends compte que je suis un peu en retard, mais je voulais quand même poster ma réponse :-)

Ce dont vous avez besoin peut être fait à l'aide d'une sous-requête, mais cela peut prendre des années à compléter sur une grande table...

En réfléchissant à la question, je suis arrivé à deux approches différentes.

L'un d'eux a déjà été traité dans les autres réponses, il fonctionne en commençant à un moment précis, en regardant l'intervalle qui commence à ce moment, puis en regardant l'intervalle de durée égale qui suit immédiatement. Cela conduit à des résultats clairs et compréhensibles et est probablement ce qui serait nécessaire (par exemple, l'utilisateur ne doit pas dépasser 100 téléchargements par jour calendaire). Cependant, cela passerait complètement à côté des situations dans lesquelles un utilisateur effectue 99 téléchargements au cours de l'heure précédant minuit et 99 autres au cours de la première heure du nouveau jour.

Donc, si le résultat requis est plutôt une "liste des dix meilleurs téléchargeurs", alors c'est l'autre approche. Les résultats ici peuvent ne pas être aussi compréhensibles à première vue, car un seul téléchargement peut compter pour plusieurs intervalles. En effet, les intervalles se chevaucheront (et devront se chevaucher).

Voici ma configuration. J'ai créé la table à partir de votre déclaration et ajouté deux index :

CREATE INDEX downloads_timestamp on downloads (dl_date);
CREATE INDEX downloads_user_id on downloads (user_id);

Les données que j'ai insérées dans le tableau :

SELECT * FROM downloads;
+----+----------+---------+---------------------+
| id | stuff_id | user_id | dl_date             |
+----+----------+---------+---------------------+
|  1 |        1 |       1 | 2011-01-24 09:00:00 |
|  2 |        1 |       1 | 2011-01-24 09:30:00 |
|  3 |        1 |       1 | 2011-01-24 09:35:00 |
|  4 |        1 |       1 | 2011-01-24 10:00:00 |
|  5 |        1 |       1 | 2011-01-24 11:00:00 |
|  6 |        1 |       1 | 2011-01-24 11:15:00 |
|  7 |        1 |       1 | 2011-01-25 09:15:00 |
|  8 |        1 |       1 | 2011-01-25 09:30:00 |
|  9 |        1 |       1 | 2011-01-25 09:45:00 |
| 10 |        1 |       2 | 2011-01-24 08:00:00 |
| 11 |        1 |       2 | 2011-01-24 12:00:00 |
| 12 |        1 |       2 | 2011-01-24 12:01:00 |
| 13 |        1 |       2 | 2011-01-24 12:02:00 |
| 14 |        1 |       2 | 2011-01-24 12:03:00 |
| 15 |        1 |       2 | 2011-01-24 12:00:00 |
| 16 |        1 |       2 | 2011-01-24 12:04:00 |
| 17 |        1 |       2 | 2011-01-24 12:05:00 |
| 18 |        1 |       2 | 2011-01-24 12:06:00 |
| 19 |        1 |       2 | 2011-01-24 12:07:00 |
| 20 |        1 |       2 | 2011-01-24 12:08:00 |
| 21 |        1 |       2 | 2011-01-24 12:09:00 |
| 22 |        1 |       2 | 2011-01-24 12:10:00 |
| 23 |        1 |       2 | 2011-01-25 14:00:00 |
| 24 |        1 |       2 | 2011-01-25 14:12:00 |
| 25 |        1 |       2 | 2011-01-25 14:25:00 |
+----+----------+---------+---------------------+
25 rows in set (0.00 sec)

Comme vous pouvez le constater, tous les téléchargements ont eu lieu hier ou aujourd'hui et ont été exécutés par deux utilisateurs différents.

Maintenant, ce que nous avons à l'esprit est le suivant :il y a (mathématiquement) un nombre infini d'intervalles de 24 heures (ou d'intervalles de toute autre durée) entre '2011-01-24 0:00' et '2011-01-25 23 :59:59'. Mais comme la précision du serveur est d'une seconde, cela revient à 86 400 intervalles :

First interval:  2011-01-24 0:00:00 -> 2011-01-25 0:00:00
Second interval: 2011-01-24 0:00:01 -> 2011-01-25 0:00:01
Third interval: 2011-01-24 0:00:02 -> 2011-01-25 0:00:02
   .
   .
   .
86400th interval: 2011-01-24 23:59:59 -> 2011-01-25 23:59:59

Nous pourrions donc utiliser une boucle pour itérer sur tous ces intervalles et calculer le nombre de téléchargements par utilisateur et par intervalle. Bien sûr, tous les intervalles n'ont pas le même intérêt pour nous, nous pouvons donc en ignorer certains en utilisant les horodatages du tableau comme "début d'intervalle".

C'est ce que fait la requête suivante. Il utilise chaque horodatage de téléchargement dans le tableau comme "début d'intervalle", ajoute la durée de l'intervalle, puis interroge le nombre de téléchargements par utilisateur pendant cet intervalle.

SET @duration = '24:00:00';
SET @limit = 5;
SELECT * FROM 
    (SELECT t1.user_id, 
            t1.dl_date startOfPeriod, 
            ADDTIME(t1.dl_date,@duration) endOfPeriod, 
           (SELECT COUNT(1) 
            FROM downloads t2 
            WHERE t1.user_id = t2.user_id 
            AND t1.dl_date <= t2.dl_date 
            AND ADDTIME(t1.dl_date,@duration) >= t2.dl_date) count
     FROM downloads t1) t3 
WHERE count > @limit;

Voici le résultat :

+---------+---------------------+---------------------+-------+
| user_id | startOfPeriod       | endOfPeriod         | count |
+---------+---------------------+---------------------+-------+
|       1 | 2011-01-24 09:00:00 | 2011-01-25 09:00:00 |     6 |
|       1 | 2011-01-24 09:30:00 | 2011-01-25 09:30:00 |     7 |
|       1 | 2011-01-24 09:35:00 | 2011-01-25 09:35:00 |     6 |
|       1 | 2011-01-24 10:00:00 | 2011-01-25 10:00:00 |     6 |
|       2 | 2011-01-24 08:00:00 | 2011-01-25 08:00:00 |    13 |
|       2 | 2011-01-24 12:00:00 | 2011-01-25 12:00:00 |    12 |
|       2 | 2011-01-24 12:01:00 | 2011-01-25 12:01:00 |    10 |
|       2 | 2011-01-24 12:02:00 | 2011-01-25 12:02:00 |     9 |
|       2 | 2011-01-24 12:03:00 | 2011-01-25 12:03:00 |     8 |
|       2 | 2011-01-24 12:00:00 | 2011-01-25 12:00:00 |    12 |
|       2 | 2011-01-24 12:04:00 | 2011-01-25 12:04:00 |     7 |
|       2 | 2011-01-24 12:05:00 | 2011-01-25 12:05:00 |     6 |
+---------+---------------------+---------------------+-------+
12 rows in set (0.00 sec)