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()) );
Related
I am interested in collecting data from the last month in the database with MySQLi.
But using INTERVAL 1 MONTH each month overlaps the other, so is there a way to tell the function to check my current month, start from the first day, and collect all data from said month?
Something like:
SELECT count(DISTINCT ip) AS visitor_ip FROM visitor_list
WHERE visited_date > ( INTERVAL CURRENT_MONTH_BEGINNING)
You can just use the current year and month, and 01 as the day:
SELECT count(DISTINCT ip) AS visitor_ip
FROM visitor_list
WHERE visited_date > CONCAT(DATE_FORMAT(NOW(),'%Y%m'), '01')
This has the advantage that any index on visited_date will still be used correctly.
First you need to generate current month starting date from PHP like this:
$monthStartDate = date('Y-m').'-01';
Then your query will become:
$sql = "SELECT count(DISTINCT ip) AS visitor_ip FROM visitor_list WHERE visited_date > DATE_SUB(now(), interval (datediff(now(), '".$monthStartDate."')) day)";
I want to get count of previous day records from database.
I am using following method
$date = date('Y-m-d H:i:s', strtotime('-1 day'));
$users = 'SELECT Count(*) FROM users where date="'.$date.'"';
This is show count 0 as date format in database is (Y-m-d H:i:s).
Thanks.
Could just do
select count(*) from users where to_days(date) = (to_days(now()) - 1);
This is useful if your date column is a datetime - we're just converting to a day number and checking how many records have yesterdays day number.
Hope it will help you
SELECT COUNT(*) FROM users WHERE date = (CURDATE() - INTERVAL 1 DAY)
You might want to consider asking MYSQL itself about it, so that PHP doesn't have to compute it (and it is likely to be faster) :
SELECT Count(*) FROM users WHERE date = DATE_SUB(NOW(), INTERVAL 1 DAY)
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
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;
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