SQL Query to get results on a 24 hour graph - php

I have the following structure to store clicks from a website on a Mysql database:
select * from contenido_clicks;
+-------------+-------------+------------+
| idContenido | fecha_click | servicetag |
+-------------+-------------+------------+
| 5 | 1392829606 | HJCS302 |
| 8 | 1392832379 | HJCS302 |
| 5 | 1392832433 | HJCS302 |
| 5 | 1392832435 | HJCS302 |
| 5 | 1392832437 | HJCS302 |
And so on...
Here I have lots on entries from different days and hours, and I need to get all of them and place on a 24 hours graph, to show the hours in the day that people makes more clicks. I can get the clicks per hour with:
SELECT cc.fecha_click div 3600 as Horas, COUNT(cc.idContenido) as Clicks
FROM contenido_clicks cc
GROUP BY fecha_click div 3600 ASC
But I dont know how to merge them in a 24 hour table.
Any ideas?

Create a Horas domain table with 24 rows and left join your contenido_clicks table with it
create table Horas
(
Hora integer not null
)
Insert into Horas (Hora) vlaues (0)
Insert into Horas (Hora) vlaues (1)
.
.
.
Insert into Horas (Hora) vlaues (23)
select *
from Horas h
left join (
SELECT cc.fecha_click div 3600 as Horas, COUNT(cc.idContenido) as Clicks
FROM contenido_clicks cc
GROUP BY fecha_click div 3600
) as hh on hh.Hora = h.Hora
order by h.Hora

I think you want to do some thing like this
SELECT *
FROM contenido_clicks
WHERE DATE_ADD(NOW(), INTERVAL 24 HOUR) > fecha_click
I think this will solve your problem

Thanks to the solution provided by jean, I write the following query:
SELECT h.hora, COUNT(cc.idContenido) as Clicks
FROM horas h
LEFT JOIN contenido_clicks cc ON h.hora = DATE_FORMAT(FROM_UNIXTIME(cc.fecha_click), '%H')
GROUP BY h.hora;
And get the following result:
+------+--------+
| hora | Clicks |
+------+--------+
| 0 | 0 |
| 1 | 0 |
| 2 | 0 |
| 3 | 0 |
| 4 | 0 |
| 5 | 0 |
| 6 | 0 |
| 7 | 0 |
| 8 | 0 |
| 9 | 5 |
| 10 | 3 |
| 11 | 7 |
| 12 | 4 |
| 13 | 3 |
| 14 | 0 |
| 15 | 5 |
| 16 | 1 |
| 17 | 5 |
| 18 | 8 |
| 19 | 0 |
| 20 | 0 |
| 21 | 1 |
| 22 | 0 |
| 23 | 0 |
+------+--------+
24 rows in set (0.00 sec)
Which are the correct results.

Related

Calculating running balance with limit

I am working on a small accounting app. The following function is used to get transaction of a supplier. I want get the balance after each transaction in this loop. Can some one provide me a best method.
public function transaction_by_id_paginated($supplier_id,$start_from,$limit) {
$sql="
SELECT *
FROM transactions
WHERE tr_sup_id = $supplier_id
ORDER
BY tr_date DESC
LIMIT $start_from, $limit
";
$suppliers = DB::fetch($sql);
return $suppliers;
}
With this function i want get a calculated balance value. I am not storing balance in DB.
Fields in transactions tables are
tr_id (Primary) int(11)
tr_sup_id int(11)
bill_id int(11)
tr_date date
tr_type varchar(250)
tr_bill int(250)
tr_payment int(250)
tr_payment_note varchar(250)
i want balance which is equal to balance = balance + tr_payment - tr_bill
Consider the following:
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT i, #j:=#j+i FROM ints, (SELECT #j:=0) vars ORDER BY i;
+---+----------+
| i | #j:=#j+i |
+---+----------+
| 0 | 0 |
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
+---+----------+
10 rows in set (0.00 sec)
SELECT i, #j:=#j+i FROM ints, (SELECT #j:=0) vars ORDER BY i LIMIT 3,6;
+---+----------+
| i | #j:=#j+i |
+---+----------+
| 3 | 3 |
| 4 | 7 |
| 5 | 12 |
| 6 | 18 |
| 7 | 25 |
| 8 | 33 |
+---+----------+
6 rows in set (0.00 sec)

Find the number of rooms availble from the below table structure

I have the following table structure:
roominfo table
+---------+----------------+---------------+
| Room_id | room_type_name | maximum_rooms |
+---------+----------------+---------------+
| 1 | A | 16 |
| 2 | B | 14 |
| 3 | C | 7 |
| 4 | D | 2 |
| 5 | E | 2 |
+---------+----------------+---------------+
bookedtable stores all the rooms booked within that date:
+------------+--------------+---------------+----------------+---------+
| room_bk_id | checkin_date | checkout_date | maxroomsbooked | room_id |
+------------+--------------+---------------+----------------+---------+
| 1 | 2014-01-28 | 2014-01-29 | 8 | 1 |
| 2 | 2014-01-29 | 2014-01-30 | 2 | 4 |
| 3 | 2014-01-28 | 2014-01-29 | 4 | 1 |
+------------+--------------+---------------+----------------+---------+
bookingprogress table to avoid the race condition (it blocks upto the expire time) I set the maximum expire time as 15 minutes from current time
+------------+----------------+-----------------+----------------+---------+---------------+---------------------+
| room_pg_id | checkinpg_date | checkoutpg_date | maxroomsbooked | room_id | sessionid | ExpireTime |
+------------+----------------+-----------------+----------------+---------+---------------+---------------------+
| 1 | 2014-01-28 | 2014-01-29 | 2 | 1 | AdsddsA23asd | 2014-01-28 00:15:00 |
| 2 | 2014-01-29 | 2014-01-30 | 2 | 5 | AdsQWerasdwe | 2014-01-28 00:18:00 |
| 3 | 2014-01-28 | 2014-01-29 | 1 | 2 | BdrtQWerasdwe | 2014-01-28 00:20:00 |
+------------+----------------+-----------------+----------------+---------+---------------+---------------------+
The workflow is:
User checks for the available rooms by providing checkin date, checkout date and no of rooms.
I need to find and display the rooms are available which are not blocked or booked for that particular period.
The executed query was (might be small mistakes -- Here I gave overview of what I have done --So modified my query according to that)
SELECT tbook.*,
SUM(tbook.maxroomsbooked + tprogress.maxroomsbooked) AS bookedrooms
FROM bookedtable AS tbook
JOIN bookingprogress AS tprogress USING (Room_id)
JOIN roominfo AS troomtype USING (Room_id)
WHERE tbook.checkout_date > '2014-01-28'
AND tprogress.checkoutpg_date > '2014-01-28'
AND tprogress.ExpireTime < '2014-01-27 00:10:00'
AND tprogress.room_id = 1
GROUP BY Room_id
From the above tables I tried to get the rooms which are available for booking. But I didn't get the expected result.
See it on sqlfiddle.
Could you please provide me with the solution?
One way would be to use NOT EXISTS subqueries. For example, if a user is interested in booking '2014-02-01' to '2014-02-07':
SELECT *
FROM roominfo r
WHERE NOT EXISTS (
SELECT *
FROM bookedtable b
WHERE b.room_id = r.room_id
AND NOT (
b.checkin_date < '2014-02-07'
AND b.checkout_date > '2014-02-01'
)
LIMIT 1
)
AND NOT EXISTS (
SELECT *
FROM bookingprogress p
WHERE p.room_id = r.room_id
AND p.ExpireTime > CURRENT_TIME
AND NOT (
p.checkinpg_date < '2014-02-07'
AND p.checkoutpg_date > '2014-02-01'
)
LIMIT 1
)

SQL request for several tables and operations in MySQL

I have the following 3 tables: unit, stage, stats.
unit stage
+----+--------+ +----+-------+---------------------+
| id | status | | id |unit_id| date |
+----+--------+ +----+-------+---------------------+
| 1 | 2 | | 1 | 2 | 2013-11-22 00:00:00 |
| 2 | 3 | | 2 | 2 | 2013-11-26 12:00:00 |
| 3 | 3 | | 3 | 3 | 2013-10-11 00:00:00 |
| 4 | 0 | | 4 | 1 | 2013-12-29 00:00:00 |
+----+--------+ +----+-------+---------------------+
stats
+----+----------+---------------------+-------+
| id | stage_id | date | clicks|
+----+----------+---------------------+-------+
| 1 | 1 | 2013-11-22 00:00:00 | 10 |
| 2 | 1 | 2013-11-23 00:00:00 | 20 |
| 3 | 1 | 2013-11-24 00:00:00 | 25 |
| 4 | 2 | 2013-11-26 00:00:00 | 15 |
| 5 | 2 | 2013-11-27 12:00:00 | 21 |
| 6 | 3 | 2013-12-29 00:00:00 | 8 |
+----+----------+---------------------+-------+
I need a request, that will produce the following response:
+---------+---------------------+-----------------------+
| unit.id | stage.min.date | sum(stats.max.clicks) |
+---------+---------------------+-----------------------+
| 2 | 2013-11-22 00:00:00 | 46 |
| 3 | 2013-12-29 00:00:00 | 8 |
+---------+---------------------+-----------------------+
by the following rules:
1) unit.id - show only units with unit.status=3
2) stage.min.date - minimal stage.date for corresponding unit_id
3) sum(stats.max.clicks) - sum of stats.clicks with max dvalues for each stage_id associated with corresponding unit_id. In my example 46 = 25(stage_id=1) + 21(stage_id=2)
The problem is in min.date and sum of clicks - I have no idea how to get it in one query. Definitely it`s not a problem to do it using php code and several requests.
Schema in SQL Fiddle
Thanks in advance.
I just ask myself, why I do this? Your example resonse has an error, and does not match your fiddle... but:
SELECT
cc.unit_id, MIN(cc.date) as stage_min_date , SUM(dd.clicks) as stats_max_clicks
FROM
stage cc
LEFT JOIN (
SELECT
bb.stage_id, bb.clicks
FROM
stats bb LEFT JOIN (
SELECT id, stage_id, MAX(date) AS max_date
FROM stats
GROUP BY stage_id
) aa
ON
aa.max_date = bb.date
WHERE
aa.max_date IS NOT NULL
) dd
ON cc.id = dd.stage_id
LEFT JOIN unit ee
ON ee.id = cc.unit_id
WHERE ee.status = 3
GROUP BY cc.unit_id
...

Query optimization for tournament scoring tables in MySQL

I have two tables in a tournament-related database and I need to know the most optimized SQL query to generate the correct overall results. The results must show the total points scored, minus any penalties, and scores that are tied should be broken based on the person who reached that score first.
In the database tables, I have an event log where each score is added as teams proceed through the tournament, and I have another table which shows which team is part of which tournament.
Table "xTournamentTeam" (connects a team to a tournament)
=======================
+-----+------------+--------+--------------+
| nID | Team Name | TeamID | TournamentID |
+-----+------------+--------+--------------+
| 1 | Team A | 12 | 25 |
| 2 | Team B | 13 | 25 |
| 3 | Team C | 14 | 25 |
| 4 | Team D | 15 | 25 |
| 3 | Team A | 12 | 32 |
| 4 | Team B | 13 | 32 |
+-----+------------+--------+--------------+
Table "nEventLog" (records scoring during a tournament)
=================
+-----+---------------+---------+----------+----------------+-----------------------+
| nID | nTournamentID | nTeamID | nPoints | nPointsPenalty | nEventTime |
+-----+---------------+---------+----------+----------------|-----------------------+
| 1 | 25 | 15 | 100 | 0 | 1/24/2013 6:05:14 AM |
| 2 | 25 | 14 | 100 | 0 | 1/24/2013 6:29:55 AM |
| 3 | 25 | 14 | 100 | 25 | 1/24/2013 7:09:34 AM |
| 4 | 25 | 12 | 100 | 0 | 1/24/2013 7:12:28 AM |
| 5 | 25 | 12 | 100 | 0 | 1/24/2013 8:42:59 AM |
| 6 | 25 | 12 | 100 | 50 | 1/24/2013 8:43:36 AM |
| 7 | 25 | 14 | 100 | 0 | 1/24/2013 9:15:24 AM |
| 8 | 25 | 15 | 100 | 0 | 1/24/2013 9:15:27 AM |
| 9 | 32 | 12 | 100 | 0 | 1/28/2013 8:33:49 AM |
| 10 | 32 | 13 | 100 | 25 | 1/28/2013 2:15:12 PM |
| 11 | 32 | 12 | 100 | 10 | 1/28/2013 7:12:25 AM |
| 12 | 32 | 13 | 100 | 0 | 1/29/2013 7:18:06 AM |
+-----+---------------+---------+----------+----------------+-----------------------+
In the case of the above data, the query I need should generate the following results for Tournament #25:
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| nRank | Team Name | TeamID | TournamentID | nTotalPoints | nTotalPointsPenalty | nLatestEventTime |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| 1 | Team A | 12 | 25 | 300 | 50 | 1/24/2013 8:43:36 AM |
| 2 | Team C | 14 | 25 | 300 | 25 | 1/24/2013 9:15:24 AM |
| 3 | Team D | 15 | 25 | 200 | 0 | 1/24/2013 9:15:27 AM |
| 4 | Team B | 13 | 25 | 0 | 0 | |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
For load purposes, I'm trying to avoid sub-queries at all costs since the final query should be as optimized as possible. The "nRank" column can be generated programatically... MySQL shouldn't have to return it, but I'm shoing it for reference.
The query I have that is the closest is this one, but it doesn't return "Team B" because they don't have any records in the "nEventLog" table for nTournamentID #25:
SELECT xTournamentTeam.nTeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.nTeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.nTournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.nTeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.nTournamentID = 33
AND nEventLog.nTournamentID = 33
GROUP BY
xTournamentTeam.nID
, xTournamentTeam.nTournamentID
ORDER BY
nTotalPoints DESC
, nLatestEventTime DESC
I'm certainly no expert in MySQL queries, and I've been working on this for two days without much success, so any help would be greatly appreciated.
I change your logic a little bit, I think it's working:
SELECT
xTournamentTeam.TeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.TeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.TournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.TournamentID = nEventLog.nTournamentID AND xTournamentTeam.TeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.TournamentID = 25
GROUP BY
xTournamentTeam.TeamID
, xTournamentTeam.TournamentID
, xTournamentTeam.TeamName
ORDER BY
nTotalPoints DESC
If you need, you can format nulls to represent 0 or something else.

MySQL - get sum() of group

I have this table similar to MySQL - get sum() grouped max() of group
id | person | score | date | g | b | m |
-----------------------------------------------------------
1 | 32 | 444 | 2011-05 | 0 | 1 | o |
2 | 65 | 528 | 2011-05 | 1 | 0 | 1 |
3 | 77 | 455 | 2011-05 | 0 | 0 | 1 |
4 | 32 | 266 | 2011-05 | 1 | 1 | 0 |
5 | 77 | 100 | 2011-05 | 0 | 0 | 1 |
6 | 77 | 457 | 2011-05 | 1 | 0 | 0 |
7 | 77 | 457 | 2011-05 | 1 | 0 | 1 |
8 | 65 | 999 | 2011-05 | 0 | 0 | 1 |
9 | 32 | 222 | 2011-05 | 0 | 1 | 1 |
The result should be:
person | score | date | g | b | m |
-----------------------------------------------------
32 | 932 | 2012-05 | 1 | 3 | 1 |
66 | 1527 | 2012-05 | 1 | 0 | 2 |
77 | 1469 | 2012-05 | 2 | 0 | 3 |
But I couldn't achieve what I want to. I am trying to get for each person sum of its scores, g, m and b fields in each month. I'm very newbie about subqueries.
Thank you!
You can't just group by month, since the same month can appear in more than one year, so group by year as well, e.g.:
SELECT person, YEAR(`date`), MONTH(`date`),
SUM(score), SUM(b), SUM(g), SUM(m)
FROM MyTable
GROUP BY person, YEAR(`date`), MONTH(`date`)
If your date column is actually not a date type but a varchar or similar, and it contains yyyy-dd as shown, than you can just do:
SELECT person, `date`,
SUM(score), SUM(b), SUM(g), SUM(m)
FROM MyTable
GROUP BY person, `date`

Categories