I have a table that shows events that took place during several days in a spatial grid and I want to select the number of unique days for each cell of the grid in order to obtain the number of days where an event happend, here my table structure :
+-----+------------+------------+---------+---------+
| id | start_date | end_date | id_cell | event |
+-----+------------+------------+---------+---------+
| 1 | 2017-03-01 | 2017-03-04 | 250 | envent1 |
| 2 | 2017-03-01 | 2017-03-04 | 251 | envent1 |
| 3 | 2017-03-01 | 2017-03-04 | 307 | envent1 |
| 4 | 2017-03-01 | 2017-03-04 | 308 | envent1 |
| 5 | 2017-03-01 | 2017-03-09 | 250 | event2 |
| 9 | 2017-02-24 | 2017-03-03 | 250 | event3 |
| 13 | 2017-02-24 | 2017-03-24 | 250 | event4 |
| 17 | 2017-02-24 | 2017-03-02 | 250 | event5 |
| 21 | 2017-01-04 | 2017-01-25 | 250 | event6 |
| 25 | 2017-03-26 | 2017-03-28 | 250 | event2 |
+-----+------------+------------+---------+---------+
For example, the expected result for the cell with 250 as id is 51 days :
2017-01-04 -> 2017-01-25 = 21 days
2017-02-24 -> 2017-03-24 = 28 days
2017-03-26 -> 2017-03-28 = 2 days
The other dates are all included between 2017-02-24 and 2017-03-24 so they don't have to be counted so 21 + 28 + 2 = 51 days.
I tried to use DATEDIFF() like this :
select datediff(max(end_date) , min(start_date) ) from cell_date where id_cell = 250
The result is 83 because it counts the number of days between 2017-01-25 and 2017-03-01, the days where no event happened.
I tried some requests with DATEDIFF but I couldn't figure out how to do it. Someone can help me please ? Thanks in advance.
You can achieve this by grouping by cell_id and calculating the sum of the individual differences:
Select cell_id,[other columns],Sum(datediff(days,start_date,end_date)) as Days
From my_table
group by cell_id,[other columns]
Edit:
For your need I think you should use an intermediate table to store individual days(sure it's not the best way to do it), join them with your events and then select the distinct days in your result. Here is the code to achieve it
/*Your example Talbe*/
DECLARE #T
TABLE(ID INT,startDate DATE,EndDate DATE,id_cell INT,evnt NVARCHAR(20) )
INSERT INTO #T
VALUES
(1,'2017-03-01','2017-03-04',250,'event1'),
(2,'2017-03-01','2017-03-04',251,'event1'),
(3,'2017-03-01','2017-03-04',307,'event1'),
(4,'2017-03-01','2017-03-04',308,'event1'),
(5,'2017-03-01','2017-03-09',250,'event2'),
(9,'2017-02-24','2017-03-03',250,'event3'),
(13,'2017-02-24','2017-03-24',250,'event4'),
(17,'2017-02-24','2017-03-02',250,'event5'),
(21,'2017-01-04','2017-01-25',250,'event6'),
(25,'2017-03-26','2017-03-28',250,'event2')
/*Table to store days: ideally get the start and end dates from your table */
DECLARE #STARTDATE DATE='2017-01-04'
DECLARE #ENDDATE DATE='2017-03-28'
DECLARE #DAYS
TABLE(oneday DATE)
WHILE #StartDate <= #endDate
BEGIN
INSERT INTO #days
(
oneday
)
SELECT
#StartDate
SET #StartDate = DATEADD(dd, 1, #StartDate)
END
/*The request */
SELECT id_cell,COUNT(DISTINCT oneday) NUMBER_OF_DAYS
FROM #T t
JOIN #DAYS d ON d.oneday>=t.startDate AND d.oneday<t.EndDate
WHERE id_cell=250
GROUP BY id_cell
You could use max and min date and datediff for obtain the diff in days between the date eg: for event
select event, datediff(max(end_date) , min(star_date) )
from my_table
group by event
or yuo can sum by cell_id for the total for cell_id
select cell_id, sum(datediff(end_date , star_date) )as days
from my_table
group by cell_id
or
Looking to your sample seems you need max end_date for some event occurring starting from the same date
select id_cell, sum(datediff(max_end_date, start_date)) as days
from (
select id_cell, start_date, max(end_date) as max_end_date
from cell_date
group by id_cell, start_date ) t
group by id_cell
I have payment table info like this
ID Costumer | start_pay | Payment
1 | 2014-01-01 | 1.500
2 | 2013-12-01 | 900
that information they must pay every month, i want calculating it for range between start_pay to CURDATE
if CURDATE is 2014-03-01 (Y-m-d) the result I want like this
ID Costumer | start_pay | Payment | total_to_pay | month_count
1 | 2014-01-01 | 1.500 | 4.500 | 3
2 | 2013-12-01 | 900 | 3.600 | 4
can i do that with mysql query?
Try
SELECT *,TIMESTAMPDIFF(MONTH, DATE_SUB(start_pay,INTERVAL 1 MONTH), CURDATE()) AS
month_count,Payment * month_count AS total_to_pay FROM TABLE
Note that if the difference is less than a month it will output 0
PERIOD_DIFF is basically made for this type of calculation:
SELECT PERIOD_DIFF(DATE_FORMAT(CURDATE(),'%Y%m'), DATE_FORMAT(start_pay, '%Y%m')) from your table;
I have a mysql database with which contains data in 5 minute bins. I'd like to create hourly average of the data starting on the half hour.
By using mysql built-in group by:
select date,AVG(AE) from mytable group by date(date),HOUR(date);
would compute average value from say, 01:00 to 02:00. Instead I would like hourly averages to be computed from 00:30 to 01:30, were the value would then be the hourly average at 01:00.
This query fail when a new day starts:
select date, AVG(AE) from mytable group by date(date), HOUR( date ) + FLOOR( MINUTE( date ) / 30 );
+---------------------+------------------+
| date | AVG(AE) |
+---------------------+------------------+
| 1997-01-01 22:30:00 | 23 |
| 1997-01-01 23:30:00 | 28.3 |
| 1997-01-02 00:00:00 | 20.1333333333333 |
| 1997-01-02 00:30:00 | 29.3 |
| 1997-01-02 01:30:00 | 27.5666666666667 |
| 1997-01-02 02:30:00 | 43.4166666666667 |
which is the closest I've gotten :-)
In another post ( https://stackoverflow.com/a/6560742/1142735 ) it was suggested that GROUP BY FLOOR(MOD((mytimestamp-1800)/3600)) would create intervals starting on the half hour if timestamp was used. I am using datetime.
Thanks
Paul
Anything that uses the DATE() function will fail to correctly group the interval 23:30 - 00:30.
Use:
FLOOR((UNIX_TIMESTAMP(date) - 1800) / 3600)
I need help with a SQL statement. The goal is to count the amount of alarms of each date. My table looks something like this:
|----DATE----|---COUNTER---|---ALARM_ID---|
|2012-01-01 | 30 | 1 |
|2012-01-01 | 20 | 2 |
|2012-01-01 | 10 | 3 |
|2012-01-02 | 5 | 1 |
|2012-01-02 | 25 | 2 |
|2012-01-02 | 12 | 3 |
|2012-01-03 | 33 | 1 |
|2012-01-03 | 43 | 2 |
|2012-01-03 | 11 | 3 |
And I'm looking for a SQL statement that gives this result:
|----DATE----|---COUNTER---|
|2012-01-01 | 60 |
|2012-01-02 | 42 |
|2012-01-03 | 87 |
I've been working on this SELECT date, SUM(counter) FROM all_stats but all I get is:
|----DATE----|---COUNTER---|
|2012-01-01 | 60 |
Do I have to create a loop to go through all dates and count?
Thanks in advance, Steve-O
SELECT date, SUM(counter)
FROM all_stats
GROUP BY date
Try this instead
SELECT date, SUM(counter) FROM all_stats GROUP BY date;
"GROUP BY date" puts all the individual dates on a separate line and does the sum separately per date.
select date, sum(counter)
from all_stats
group by date
I need to obtain a count of how many actions occur on an hourly basis.
My database keeps a log by timestamp of the actions.
I understand that I could do a
SELECT table.time COUNT(table.time) from table t group by t.time
However, there are periods of time where no actions take place. For example if I have 10 actions during 8:00AM, no actions during 9:00AM and 4 actions during 10:00AM,
That query would return:
8:00 10
10:00 4
Skipping 9:00AM because it has no entries.
How can I make a query that will take into account 0-count entries.
I also need to make the same query for entries by days of the week, but I assume that by answering the first question I can easily handle the other.
Thanks in advance!
you can solve this by creating a table that will contain 24 values for hours (00:00, 01:00 etc) and perform a left (or right) join with it and your table allowing nulls so you will have all 24 rows even if your table contains 0 rows at all, then group by should work fine.
Dont forget to truncate everything but hour from your table when you perform join so result of func you call & perform join on can be equal to value of this help table.
you can use following query to do the job after populating testtime table with 24 test_time values
select test_time,sum(sign(coalesce(idFromYourTable,0))) as count from testtime
left join yourTable on test_time=hour(yourTableTime)
group by test_time
This will provide 0 as count if there are no values matching row from test table, while having count(*) will provide 24 rows with 1s instead of 0s even if your table is empty, also if there is just 1 row in your table it is impossible to distinguish the difference between 0 rows cause results will look the same for following 2 different rows
23 NULL
23 1
cause will both provide same result row count equal to 1 , while sum technique treats this rows differently
A simple way to do the same without creating any table would be as follows
SELECT
HOUR(time) 'hr', COUNT(DISTINCT id)
FROM schema.table
WHERE time BETWEEN '2016-01-23 00:00:00' AND '2016-01-24 00:00:00'
GROUP BY hr;
Hour function in mysql gives the hour from a datetime or timestamp data type. This query is grouping them based on particular hour withing the date range. Distinct is not mandatory but if you are looking for unique order or id in the time range per hour. This is the query.
You can use Valentin's solution but without the need to create a table of time slots. The idea is to generate the time slots on the fly and then JOIN them to your table as he suggests.
WITH RECURSIVE timeSlots (t) AS (
SELECT 0
UNION ALL
SELECT t + 3600 FROM timeSlots WHERE t < (23 * 3600)
)
SELECT t, TIME_FORMAT(SEC_TO_TIME(t), '%H:%i:%s') FROM timeSlots;
Gives:
+-------+----------+
| t | Time |
+-------+----------+
| 0 | 00:00:00 |
| 3600 | 01:00:00 |
| 7200 | 02:00:00 |
| 10800 | 03:00:00 |
| 14400 | 04:00:00 |
| 18000 | 05:00:00 |
| 21600 | 06:00:00 |
| 25200 | 07:00:00 |
| 28800 | 08:00:00 |
| 32400 | 09:00:00 |
| 36000 | 10:00:00 |
| 39600 | 11:00:00 |
| 43200 | 12:00:00 |
| 46800 | 13:00:00 |
| 50400 | 14:00:00 |
| 54000 | 15:00:00 |
| 57600 | 16:00:00 |
| 61200 | 17:00:00 |
| 64800 | 18:00:00 |
| 68400 | 19:00:00 |
| 72000 | 20:00:00 |
| 75600 | 21:00:00 |
| 79200 | 22:00:00 |
| 82800 | 23:00:00 |
+-------+----------+
If you want to change your time slot buckets you can just fiddle with the generator arithmetic rather than having to create another table.
An alternative is to use LIMIT:
WITH RECURSIVE timeSlots (t) AS (
SELECT 0
UNION ALL
SELECT t + 3600 FROM timeSlots LIMIT 24
)
SELECT t, TIME_FORMAT(SEC_TO_TIME(t), '%H:%i:%s') AS Time FROM timeSlots;