Je stocke des hits. Ma table ressemble à ceci:
ID | time | Country
--------------------------------
1 | 01:00:00 | France
2 | 01:00:00 | France
3 | 01:00:00 | Brazil
4 | 01:00:00 | USA
5 | 02:00:00 | USA
Voici ma requête:
SELECT COUNT(*) as total_hits, HOUR(time) as hour, Country
FROM hits
WHERE time >= CURDATE()
GROUP BY HOUR(time)
Il compte le nombre de hits que j'ai reçus et les regroupe par heures:
time | total_hits
---------------------------
01:00:00 | 4
02:00:00 | 1
Je veux un résultat groupé par colonne time
et un autre groupé par colonne countries
. C'est ce dont j'ai besoin:
1) Regroupé par heures comme ceci (comme ci-dessus)
time | total_hits
---------------------------
01:00:00 | 4
02:00:00 | 1
2) ET regroupés par pays comme celui-ci
country | total_hits
---------------------------
France | 2
USA | 2
Brazil | 1
Je pourrais faire:
SELECT
COUNT(*)
, HOUR(time)
, COUNT(IF( Country = 'France', Country, null)) AS France
, COUNT(IF( Country = 'USA', Country, null)) AS USA
, COUNT(IF( Country = 'Brazil', Country, null)) AS Brazil
FROM hits
WHERE time >= CURDATE()
GROUP BY HOUR(time)
Ou bien avec CASE
ou SUM(Country = 'France') AS France
.
Mais dans la colonne des pays, il y a plus de seulement 3 pays. Si je le faisais avec tous les pays, ma requête serait très longue.
Je pourrais faire ça:
SELECT COUNT(*), Country, HOUR(time)
FROM hits
WHERE time >= CURDATE()
GROUP BY Country, HOUR(time)
Mais la sortie sera quelque chose comme ceci:
time | country | total_hits
---------------------------------------
01:00:00 | France | 2
01:00:00 | USA | 1
01:00:00 | Brazil | 1
02:00:00 | USA | 1
Cependant, j'ai besoin d'une sortie comme mentionné ci-dessus.
Donc, fondamentalement, j'ai besoin de ces requêtes dans une seule requête:
1) Grouper par HEURE (comme ci-dessus)
SELECT COUNT(*) as total_hits, HOUR(time) as hour, Country
FROM hits
WHERE time >= CURDATE()
GROUP BY HOUR(time)
2) ET regrouper par pays
SELECT COUNT(*) as total_hits
FROM hits
WHERE time >= CURDATE()
GROUP BY Country
La performance est importante. La base de données contient des millions d'entrées. Peut-être que MySQL n'est pas le meilleur moyen de résoudre ce problème?
Je ne pense pas pouvoir vous aider avec le formatage, mais la requête dont vous avez besoin est celle-ci:
SELECT
IFNULL(Hour,CONCAT('Total for ',IFNULL(Country,'All Countries'))) Statistic,
COUNT(1) TotalHits
FROM
(
SELECT Country,(time - INTERVAL MOD(UNIX_TIMESTAMP(time),3600) SECOND) Hour
FROM hits WHERE time >= (DATE(NOW()) + INTERVAL 0 SECOND)
) AA
GROUP BY Country,Hour WITH ROLLUP;
USE test
DROP TABLE IF EXISTS hits;
CREATE TABLE hits
(
id int not null auto_increment,
time datetime,
country varchar(20),
PRIMARY KEY (id)
);
INSERT INTO hits (time,Country) VALUES
('2014-06-19 01:00:00','France'),
('2014-06-19 01:00:00','Brazil'),
('2014-06-19 01:00:00','USA'),
('2014-06-19 02:00:00','USA');
mysql> USE test
Database changed
mysql> DROP TABLE IF EXISTS hits;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE TABLE hits
-> (
-> id int not null auto_increment,
-> time datetime,
-> country varchar(20),
-> PRIMARY KEY (id)
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO hits (time,Country) VALUES
-> ('2014-06-19 01:00:00','France'),
-> ('2014-06-19 01:00:00','Brazil'),
-> ('2014-06-19 01:00:00','USA'),
-> ('2014-06-19 02:00:00','USA');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM hits;
+----+---------------------+---------+
| id | time | country |
+----+---------------------+---------+
| 1 | 2014-06-19 01:00:00 | France |
| 2 | 2014-06-19 01:00:00 | Brazil |
| 3 | 2014-06-19 01:00:00 | USA |
| 4 | 2014-06-19 02:00:00 | USA |
+----+---------------------+---------+
4 rows in set (0.00 sec)
mysql>
mysql> SELECT
-> IFNULL(Hour,CONCAT('Total for ',IFNULL(Country,'All Countries'))) Statistic,
-> COUNT(1) TotalHits
-> FROM
-> (
-> SELECT Country,(time - INTERVAL MOD(UNIX_TIMESTAMP(time),3600) SECOND) Hour
-> FROM hits WHERE time >= (DATE(NOW()) + INTERVAL 0 SECOND)
-> ) AA
-> GROUP BY Country,Hour WITH ROLLUP;
+-------------------------+-----------+
| Statistic | TotalHits |
+-------------------------+-----------+
| 2014-06-19 01:00:00 | 1 |
| Total for Brazil | 1 |
| 2014-06-19 01:00:00 | 1 |
| Total for France | 1 |
| 2014-06-19 01:00:00 | 1 |
| 2014-06-19 02:00:00 | 1 |
| Total for USA | 2 |
| Total for All Countries | 4 |
+-------------------------+-----------+
8 rows in set (0.00 sec)
mysql>
CAVEAT: Veuillez vous assurer d'avoir un index de temps sur la table
ALTER TABLE hits ADD INDEX time_index (time);
Une requête supplémentaire pourrait être
SELECT
IFNULL(Country,CONCAT('Total for ',IFNULL(Hour,DATE(NOW())))) Statistic,
COUNT(1) TotalHits
FROM
(
SELECT Country,(time - INTERVAL MOD(UNIX_TIMESTAMP(time),3600) SECOND) Hour
FROM hits WHERE time >= (DATE(NOW()) + INTERVAL 0 SECOND)
) AA
GROUP BY Hour,Country WITH ROLLUP;
dont la sortie serait
+-------------------------------+-----------+
| Statistic | TotalHits |
+-------------------------------+-----------+
| Brazil | 1 |
| France | 1 |
| USA | 1 |
| Total for 2014-06-19 01:00:00 | 3 |
| USA | 1 |
| Total for 2014-06-19 02:00:00 | 1 |
| Total for 2014-06-19 | 4 |
+-------------------------------+-----------+
7 rows in set (0.00 sec)
Peut-être que les deux requêtes combinées avec UNION fonctionneront pour vous
SELECT
IFNULL(Country,CONCAT('Total for ',IFNULL(Hour,DATE(NOW())))) Statistic,
COUNT(1) TotalHits
FROM
(
SELECT Country,(time - INTERVAL MOD(UNIX_TIMESTAMP(time),3600) SECOND) Hour
FROM hits WHERE time >= (DATE(NOW()) + INTERVAL 0 SECOND)
) AA
GROUP BY Hour,Country
UNION
SELECT
IFNULL(Hour,CONCAT('Total for ',IFNULL(Country,'All Countries'))) Statistic,
COUNT(1) TotalHits
FROM
(
SELECT Country,(time - INTERVAL MOD(UNIX_TIMESTAMP(time),3600) SECOND) Hour
FROM hits WHERE time >= (DATE(NOW()) + INTERVAL 0 SECOND)
) AA
GROUP BY Country,Hour WITH ROLLUP;
J'ai supprimé le WITH ROLLUP
du premier pour que le total sorte une fois