Average day values of last month as a SQL statement - php

I got a table with two columns, timestamp (like '1405184196') and value.
I've saved some measured values.
$day= time()-84600;
$result = mysql_query('SELECT timestamp, value FROM table WHERE timestamp >= "'.$day.'" ORDER BY timestamp ASC');
This is how I get all values for the last 24h.
But is it possible to get average day values for the last month with a SQL statement or do I have to select all values of the last month and calculate the average of each day via PHP?

Several issues with Anish's answer:
1) This won't work if date+time is being stored in the timestamp field.
2) It assumes the OP means last month i.e June, May etc and not the last say 30 days.
This solves those issues:
SELECT DATE(`timestamp`) as `timestamp`, AVG(value)
FROM table
WHERE `timestamp` >= CURDATE() - INTERVAL 1 MONTH
GROUP BY DATE(`timestamp)
EDIT
Since the timestamp is a unix timestamp and the OP would like a calendar month:
SELECT DATE(FROM_UNIX(`timestamp`)) as `timestamp`, AVG(value)
FROM table
WHERE MONTH(FROM_UNIX(`timestamp`)) = MONTH(NOW() - 1)
GROUP BY DATE(FROM_UNIX(`timestamp))

You can do this:-
SELECT timestamp, AVG(value)
FROM table
GROUP BY timestamp
HAVING MONTH(timestamp) = MONTH(NOW()) - 1;
This query calculates average for last month.
DEMO

Related

SELECT count(*) from where date(week number) equal to current week number

I am using this to query from my table:
$res = $link -> query("SELECT count(*) FROM sales WHERE status='OK'") or die($mysqli->error);
$num_rows = mysqli_fetch_row($res)[0];
$numberOfSales = $num_rows;
In table sales I also have a column named date datetime.
I want it to only returns the number of rows where date is the same as the current week number. So if the date column cell has value 2020-08-03 16:25:26, that converted to week number is 32. I have been looking at strftime("%V",, but not sure how to proceed. Any tips?
Consider and index-friendly expression such as:
select count(*)
from sales
where
status='OK'
and datetime >= current_date - interval weekday(current_date) day
Expression current_date - interval weekday(current_date) day dynamically computes the date that corresponds to the first day of the current week (starting on Monday).
If you may have dates in the future, then you can add an upper limit:
where
status='OK'
and datetime >= current_date - interval weekday(current_date) day
and datetime < current_date + interval (7 - weekday(current_date)) day

get the nearest date mysql

I have the following dates in my table. How do I find a closest date from either today (if today's date is there) or if today's date is not there then the nearest past date?
2012-10-01 aa123
2012-10-02 aa43
2012-10-03 aa478
2012-10-04 aa40
2012-10-05 aa54
2012-10-06 de34
2012-10-07 a5434
2012-10-08 r4t
2012-10-09 x34
2012-10-10 q23
2012-10-11 b53
So if today is '2012-10-07' is then the record will be a5434. But if 2012-10-07 is missing then the record will be de34 which belongs to 2012-10-06 since that would be the closest past day from today.
I am not sure where to start on this one, so I haven't tried anything yet. Need a sql solution to this.
It's simple, just get one of the last date <= the current date:
$now = date("Y-m-d");
$sql = "SELECT * FROM date_table where date_field <= '$now' ORDER BY date_field DESC LIMIT 1 OFFSET 1";
Add an ORDER BY statement to the query. The following will order the rows by their date, with the latest at the top and oldest at the bottom.
SELECT `id`, `date` FROM `table` ORDER BY `date` DESC LIMIT 1;

SQL Query Concerning Dates

I have the following relation in my schema:
Entries:
entryId(PK) auto_inc
date date
In order to count the total entries in the relation I use a query in my php like this:
$sql = mysql_query("SELECT COUNT(*) as Frequency FROM Entries WHERE date = '$date'");
My question is how can I count the number of entries for the CURRENT month..
You want a between query based on your date column.
WHERE date BETWEEN startdate AND enddate.
Between is equivalent to date >= startdate AND date <= enddate. It would of course be also possible to just use >= AND < explicitly which would simplify it a bit because you don't need to find the last day of the month, but just the first day of the following month using only DATE_ADD(..., INTERVAL 1 MONTH).
However startdate and enddate in this case would be derived from CURDATE().
You can use CURDATE(), MONTH(), DATE_ADD and STR_TO_DATE to derive the dates you need (1st day of current month, last day of current month). This article solves a similar problem and all the techniques needed are shown in examples that you should be able to adapt:
http://www.gizmola.com/blog/archives/107-Calculate-a-persons-age-in-a-MySQL-query.html
The first day of the current month is obvious YEAR-MONTH(CURDATE())-01. The last day you can calculate by using DATE_ADD to add 1 Month to the first day of the current month, then DATE_ADD -1 Days.
update-
Ok, I went and formulated the full query. Don't think str_to_date is really needed to get the index efficiency but didn't actually check.
SELECT count(*)
FROM entries
WHERE `date` BETWEEN
CONCAT(YEAR(CURDATE()), '-', MONTH(CURDATE()), '-', '01')
AND
DATE_ADD(DATE_ADD(CONCAT(YEAR(CURDATE()), '-', MONTH(CURDATE()), '-', '01'), INTERVAL 1 MONTH), INTERVAL -1 DAY);
Try this
SELECT COUNT(1) AS `Frequency`
FROM `Entries`
WHERE EXTRACT(YEAR_MONTH FROM `date`) = EXTRACT(YEAR_MONTH FROM CURDATE())
See EXTRACT() and CURDATE()
Edit: Changed NOW() to CURDATE() as it is more appropriate here
Try
$sql = mysql_query("SELECT COUNT(*) as Frequency FROM Entries WHERE MONTH(date) = MONTH(NOW()) );

how do I get month from date in mysql

I want to be able to fetch results from mysql with a statement like this:
SELECT *
FROM table
WHERE amount > 1000
But I want to fetch the result constrained to a certain a month and year (based on input from user)... I was trying like this:
SELECT *
FROM table
WHERE amount > 1000
AND dateStart = MONTH('$m')
...$m being a month but it gave error.
In that table, it actually have two dates: startDate and endDate but I am focusing on startDate. The input values would be month and year. How do I phrase the SQL statement that gets the results based on that month of that year?
You were close - got the comparison backwards (assuming startDate is a DATETIME or TIMESTAMP data type):
SELECT *
FROM table
WHERE amount > 1000
AND MONTH(dateStart) = {$m}
Caveats:
Mind that you are using mysql_escape_string or you risk SQL injection attacks.
Function calls on columns means that an index, if one exists, can not be used
Alternatives:
Because using functions on columns can't use indexes, a better approach would be to use BETWEEN and the STR_TO_DATE functions:
WHERE startdate BETWEEN STR_TO_DATE([start_date], [format])
AND STR_TO_DATE([end_date], [format])
See the documentation for formatting syntax.
Reference:
MONTH
YEAR
BETWEEN
STR_TO_DATE
Use the month() function.
select month(now());
Try this:
SELECT *
FROM table
WHERE amount > 1000 AND MONTH(dateStart) = MONTH('$m') AND YEAR(dateStart) = YEAR('$m')
E.g.
$date = sprintf("'%04d-%02d-01'", $year, $month);
$query = "
SELECT
x,y,dateStart
FROM
tablename
WHERE
AND amount > 1000
AND dateStart >= $date
AND dateStart < $date+Interval 1 month
";
mysql_query($query, ...
This will create a query like e.g.
WHERE
AND amount > 1000
AND dateStart >= '2010-01-01'
AND dateStart < '2010-01-01'+Interval 1 month
+ Interval 1 month is an alternative to date_add().
SELECT Date('2010-01-01'+Interval 1 month)-> 2010-02-01
SELECT Date('2010-12-01'+Interval 1 month)-> 2011-01-01
This way you always get the first day of the following month. The records you want must have a dateStart before that date but after/equal to the first day of the month (and year) you've passed to sprintf().
'2010-01-01'+Interval 1 month doesn't change between rows. MySQL will calculate the term only once and can utilize indices for the search.
Try this
SELECT *
FROM table
WHERE amount > 1000
AND MONTH(datestart)
GROUP BY EXTRACT(YEAR_MONTH FROM datestart)
Try this if(date field is text then convert this string to date):
SELECT * FROM `table_name` WHERE MONTH(STR_TO_DATE(date,'%d/%m/%Y'))='11'
//This will give month number MONTH(STR_TO_DATE(date,'%d/%m/%Y'))
//If its return 11 then its November
// Change date format with your date string format %d/%m/%Y
Works in: MySQL 5.7, MySQL 5.6, MySQL 5.5, MySQL 5.1, MySQL 5.0, MySQL 4.1, MySQL 4.0, MySQL 3.23
Day:
SELECT EXTRACT(DAY FROM "2017-06-15");
Month:
SELECT EXTRACT(MONTH FROM "2017-06-15");
Year:
SELECT EXTRACT(YEAR FROM "2017-06-15");

How to minimize the load in queries that need grouping with different invervals?

I'm looking for a best practice advice how to speed up queries and at the same time to minimize the overhead needed to invoke date/mktime functions. To trivialize the problem I'm dealing with the following table layout:
CREATE TABLE my_table(
id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
important_data INTEGER,
date INTEGER);
The user can choose to show 1) all entries between two dates:
SELECT * FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Output:
10-21-2009 12:12:12, 10002
10-21-2009 14:12:12, 15002
10-22-2009 14:05:01, 20030
10-23-2009 15:23:35, 300
....
I don't think there is much to improve in this case.
2) Summarize/group the output by day, week, month, year:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data
FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Example output by month:
10-2009, 100002
11-2009, 200030
12-2009, 3000
01-2010, 0 /* <- very important to show empty dates, with no entries in the table! */
....
To accomplish option 2) I'm currently running a very costly for-loop with mktime/date like the following:
for(...){ /* example for group by day */
$span_from = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i, date("Y", $time_min));
$span_to = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i+1, date("Y", $time_min));
$query = "..";
$output = date("m-d-y", ..);
}
What are my ideas so far? Add additional/ redundant columns (INTEGER) for day (20091212), month (200912), week (200942) and year (2009). This way I can get rid of all the unnecessary queries in the for loop. However I'm still facing the problem to very fastly calculate all dates that doesn't have any equivalent in database. One way to simply move the problem could be to let MySQL do the job and simply use one big query (calculate all the dates/use MySQL date functions) with a left join (the data). Would it be wise to let MySQL take the extra load? Anyway I'm reluctant to use all these mktime/date in the for loop. Since I have complete control over the table layout and code even suggestions with major changes are welcome!
Update
Thanks to Greg I came up with the following SQL query. However it still bugs me to use 50 lines of sql statements - build up with php - that maybe could be done faster and more elegantly otherwise:
SELECT * FROM (
SELECT DATE_ADD('2009-01-30', INTERVAL 0 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 1 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 2 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 3 DAY) AS day UNION ALL
......
SELECT DATE_ADD('2009-01-30', INTERVAL 50 DAY) AS day ) AS dates
LEFT JOIN (
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date, SUM(data) AS data
FROM test
GROUP BY date
) AS results
ON DATE_FORMAT(dates.day, '%Y-%m-%d') = results.date;
You definitely shouldn't be doing a query inside a loop.
You can group like this:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data, DATE_FORMAT('%Y-%m', date) AS month
FROM my_table
WHERE date BETWEEN ? AND ? -- This should be the min and max of the whole range
GROUP BY DATE_FORMAT('%Y-%m', date)
ORDER BY date DESC;
Then pull these into an array keyed by date and loop over your data range as you are doing (that loop should be pretty light on CPU).
Another idea is not to use string inside the query. Transform the string parameter to datetime, on mysql.
STR_TO_DATE(str,format)
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html

Categories