Is it possible to make a simple query to count how many records I have in a determined period of time like a year, month, or day, having a TIMESTAMP field, like:
SELECT COUNT(id)
FROM stats
WHERE record_date.YEAR = 2009
GROUP BY record_date.YEAR
Or even:
SELECT COUNT(id)
FROM stats
GROUP BY record_date.YEAR, record_date.MONTH
To have a monthly statistic.
Thanks!
GROUP BY YEAR(record_date), MONTH(record_date)
Check out the date and time functions in MySQL.
GROUP BY DATE_FORMAT(record_date, '%Y%m')
Note (primarily, to potential downvoters). Presently, this may not be as efficient as other suggestions. Still, I leave it as an alternative, and a one, too, that can serve in seeing how faster other solutions are. (For you can't really tell fast from slow until you see the difference.) Also, as time goes on, changes could be made to MySQL's engine with regard to optimisation so as to make this solution, at some (perhaps, not so distant) point in future, to become quite comparable in efficiency with most others.
try this one
SELECT COUNT(id)
FROM stats
GROUP BY EXTRACT(YEAR_MONTH FROM record_date)
EXTRACT(unit FROM date) function is better as less grouping is used and the function return a number value.
Comparison condition when grouping will be faster than DATE_FORMAT function (which return a string value). Try using function|field that return non-string value for SQL comparison condition (WHERE, HAVING, ORDER BY, GROUP BY).
I tried using the 'WHERE' statement above, I thought its correct since nobody corrected it but I was wrong; after some searches I found out that this is the right formula for the WHERE statement so the code becomes like this:
SELECT COUNT(id)
FROM stats
WHERE YEAR(record_date) = 2009
GROUP BY MONTH(record_date)
If your search is over several years, and you still want to group monthly, I suggest:
version #1:
SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY DATE_FORMAT(record_date, '%Y%m')
version #2 (more efficient):
SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY YEAR(record_date)*100 + MONTH(record_date)
I compared these versions on a big table with 1,357,918 rows (innodb),
and the 2nd version appears to have better results.
version1 (average of 10 executes): 1.404 seconds
version2 (average of 10 executes): 0.780 seconds
(SQL_NO_CACHE key added to prevent MySQL from CACHING to queries.)
If you want to filter records for a particular year (e.g. 2000) then optimize the WHERE clause like this:
SELECT MONTH(date_column), COUNT(*)
FROM date_table
WHERE date_column >= '2000-01-01' AND date_column < '2001-01-01'
GROUP BY MONTH(date_column)
-- average 0.016 sec.
Instead of:
WHERE YEAR(date_column) = 2000
-- average 0.132 sec.
The results were generated against a table containing 300k rows and index on date column.
As for the GROUP BY clause, I tested the three variants against the above mentioned table; here are the results:
SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY YEAR(date_column), MONTH(date_column)
-- codelogic
-- average 0.250 sec.
SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY DATE_FORMAT(date_column, '%Y%m')
-- Andriy M
-- average 0.468 sec.
SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY EXTRACT(YEAR_MONTH FROM date_column)
-- fu-chi
-- average 0.203 sec.
The last one is the winner.
You can do this simply Mysql DATE_FORMAT() function in GROUP BY. You may want to add an extra column for added clarity in some cases such as where records span several years then same month occurs in different years.Here so many option you can customize this. Please read this befor starting. Hope it should be very helpful for you. Here is sample query for your understanding
SELECT
COUNT(id),
DATE_FORMAT(record_date, '%Y-%m-%d') AS DAY,
DATE_FORMAT(record_date, '%Y-%m') AS MONTH,
DATE_FORMAT(record_date, '%Y') AS YEAR
FROM
stats
WHERE
YEAR = 2009
GROUP BY
DATE_FORMAT(record_date, '%Y-%m-%d ');
If you want to group by date in MySQL then use the code below:
SELECT COUNT(id)
FROM stats
GROUP BY DAYOFMONTH(record_date)
Hope this saves some time for the ones who are going to find this thread.
Complete and simple solution with similarly performing yet shorter and more flexible alternative currently active:
SELECT COUNT(*) FROM stats
-- GROUP BY YEAR(record_date), MONTH(record_date), DAYOFMONTH(record_date)
GROUP BY DATE_FORMAT(record_date, '%Y-%m-%d')
If you want to get a monthly statistics with row counts per month of each year ordered by latest month, then try this:
SELECT count(id),
YEAR(record_date),
MONTH(record_date)
FROM `table`
GROUP BY YEAR(record_date),
MONTH(record_date)
ORDER BY YEAR(record_date) DESC,
MONTH(record_date) DESC
The following query worked for me in Oracle Database 12c Release 12.1.0.1.0
SELECT COUNT(*)
FROM stats
GROUP BY
extract(MONTH FROM TIMESTAMP),
extract(MONTH FROM TIMESTAMP),
extract(YEAR FROM TIMESTAMP);
I prefer to optimize the one year group selection like so:
SELECT COUNT(*)
FROM stats
WHERE record_date >= :year
AND record_date < :year + INTERVAL 1 YEAR;
This way you can just bind the year in once, e.g. '2009', with a named parameter and don't need to worry about adding '-01-01' or passing in '2010' separately.
Also, as presumably we are just counting rows and id is never NULL, I prefer COUNT(*) to COUNT(id).
try it
GROUP BY YEAR(record_date), MONTH(record_date)
I wanted to get similar data per day, after experimenting a bit, this is the fastest I could find for my scenario
SELECT COUNT(id)
FROM stats
GROUP BY record_date DIV 1000000;
If you want to have it per month, add additional zeroes (00)
I would not recommend this from "make the code readable" perspective, it might also break in different versions. But in our case this took less then half the time compared to some other more clearer queries that I tested.
This is a MySQL answer (as MySQL is tagged in the question) and well documented in the manual https://dev.mysql.com/doc/refman/8.0/en/date-and-time-type-conversion.html
.... group by to_char(date, 'YYYY') --> 1989
.... group by to_char(date,'MM') -->05
.... group by to_char(date,'DD') --->23
.... group by to_char(date,'MON') --->MAY
.... group by to_char(date,'YY') --->89
Here's one more approach. This uses [MySQL's LAST_DAY() function][1] to map each timestamp to its month. It also is capable of filtering by year with an efficient range-scan if there's an index on record_date.
SELECT LAST_DAY(record_date) month_ending, COUNT(*) record_count
FROM stats
WHERE record_date >= '2000-01-01'
AND record_date < '2000-01-01' + INTERVAL 1 YEAR
GROUP BY LAST_DAY(record_date)
If you want your results by day, use DATE(record_date) instead.
If you want your results by calendar quarter, use YEAR(record_date), QUARTER(record_date).
Here's a writeup. https://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
[1]: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_last-day
Or you can use group by clause like this,
//to get data by month and year do this ->
SELECT FORMAT(TIMESTAMP_COLUMN, 'MMMM yy') AS Month, COUNT(ID) FROM TABLE_NAME GROUP BY FORMAT(TIMESTAMP_COLUMN, 'MMMM yy')
if you want to fetch records by date then in group by change format to
'dd-mm-yy' or 'dd-MMMM-yyy'
Related
In oracle sql, how to get the count of newly added customers only for the month of april and may and make sure they werent there in the previous months
SELECT CUSTOMER ID , COUNT(*)
FROM TABLE
WHERE DATE BETWEEN '1-APR-2018' AND '31-MAY-2018' AND ...
If we give max (date) and min(date), we can compare the greater date to check if this customer is new , correct?
expected output is month count
april ---
may ---
should show the exact count how many new customers joined in these two months
One approach is to use aggregation:
select customer_id, min(date) as min_date
from t
group by customer_id
having min(date) >= date '2018-04-01 and
min(date) < date '2018-06-01';
This gets the list of customers (which your query seems to be doing). To get the count, just use count(*) and make this a subquery.
I working on a little web project and I was wondering what SQL I would need to use find the month with the least amount of bookings.
I have a Booking table:
I have a Package table:
I have a HolidayMaker table:
I think this might have something to do with nested SELECT statements, however I am not entirely sure.
Thanks, James.
:-)
Use MONTHNAME and GROUP BY a COUNT.
SELECT MONTHNAME(Bo_Datebooked), COUNT(Booking_ID)
FROM Booking
GROUP BY MONTHNAME(Bo_Datebooked)
ORDER BY COUNT(Booking_ID) ASC
The following query returns the booking amount for each month:
SELECT DATE_FORMAT(Bo_DateBooked, '%Y-%m') AS BookingMonth,
SUM(Package_Price) AS MonthlyAmount
FROM Booking
JOIN Package
ON Booking.Package_ID = Package.Package_ID
GROUP BY DATE_FORMAT(Bo_DateBooked, '%Y-%m');
Using a nested SELECT, you can get the minimum.
In case you are interested in seeing results 'only' for months, not taking in account years: (I.e. All reservations from any January, no matter what year):
SELECT MONTHNAME(Bo_Datebooked) as month, COUNT(1) as num_reservations
FROM Booking
GROUP BY month
ORDER BY num_reservations ASC
/* additionality add...
/* LIMIT 1 */
/* ...to see only the lower result */
In case you're concerned in differenciate months from each year (I.e: reseravations from January 2016, reservations from January 2012...):
SELECT CONCAT(MONTHNAME(Bo_Datebooked), YEAR(Bo_Datebooked)) as date, COUNT(1) as num_reservations
FROM Booking
GROUP BY date
ORDER BY num_reservations ASC
/* additionality add...
/* LIMIT 1 */
/* ...to see only the lower result */
Warning: any of this won't show you months with 0 reservations!!!
This is just an aggregation with limit:
select date_format(bo_datebooked, '%Y-%m') as yyyymm, count(*)
from booking b
group by date_format(bo_datebooked, '%Y-%m')
order by count(*) desc
limit 1;
You can use this sql. I test this in my ms sql server. If it's not working just find similar syntax for mysql server. ok ?
SELECT CONVERT(CHAR(3), DATENAME(MONTH, Bo_Datebooked)), COUNT(Booking_Id) FROM Booking
GROUP BY CONVERT(CHAR(3), DATENAME(MONTH, Bo_Datebooked))
ORDER BY COUNT(Booking_Id) ASC
Hope this will help you
I have a mysql table with date, name and rating of a person. I need to build a query to show the best person of each month. The query above gives me maximum rating of the month but wrong name/id of person.
SELECT DATE_FORMAT(date,'%m.%Y') as date2, MAX(rating), name FROM test GROUP BY date2
Here's sqlfiddle with sample table: http://sqlfiddle.com/#!2/4dd54b/9
I read several greatest-n-per-group topics, but those queries didn't work, I suppose it's because of grouping by DATE_FORMAT. So here I ask.
The easiest way is to use the substring_index()/group_concat() trick:
SELECT DATE_FORMAT(date, '%m.%Y') as date2, MAX(rating),
substring_index(group_concat(name order by rating desc), ',', 1) as name
FROM test
GROUP BY date2;
A faster solution might look like this - although removal of the DATE_FORMAT function altogether will speed things up even further...
SELECT x.*
FROM test x
JOIN
( SELECT DATE_FORMAT(date,'%Y-%m') dt
, MAX(rating) max_rating
FROM test
GROUP
BY DATE_FORMAT(date,'%Y-%m')
) y
ON y.dt = DATE_FORMAT(x.date,'%Y-%m')
AND y.max_rating = x.rating;
I have a MySQL database populated with power consumption over 20 years.
I want to query the average of the power consumption over every month, from a given month.
For example with this database,
date power_consumption
2014/03/30 30
2014/04/30 40
2014/05/30 50
2014/06/30 20
The result would be, from 2014/04
month average_so_far_from_april_2014
2014/04 40.0
2014/05 45.0
2014/06 36.667
If I cannot achieve this in one query, what query should I go for to retrieve the most useful data for this task? (My naive approach is to query the whole table out and calculate the average in my application.)
Join the table of sub query against the consumption table which gets the unique months against the table of consumption, with a join condition that the year / month is less than or equal to the one from the sub query and use the AVG aggregate function on the power consumption from the table grouped by the year / month
Something like this:-
SELECT consumption_month,
AVG(b.power_consumption)
FROM
(
SELECT DISTINCT DATE_FORMAT(`date`, '%Y%m') AS consumption_month FROM consumption_table a
) a
INNER JOIN consumption_table b
ON consumption_month >= DATE_FORMAT(b.`date`, '%Y%m')
WHERE b.`date` >= '2014/04/01'
GROUP BY consumption_month
SQL fiddle:-
http://www.sqlfiddle.com/#!2/16588/2
If you only had one record per month you could simplify it more by just doing a join of the table against itself without the need for the sub query.
GROUP BY is for this kind of problems. The average is calculated for each distinct value of the expression the the GROUP BY clause.
SELECT DATE_FORMAT(date, '%Y/%m'), AVG(power_consumption)
FROM table_name
WHERE date > ...
GROUP BY DATE_FORMAT(date, '%y/%m')
ORDER BY DATE_FORMAT(date, '%y/%m')
You get the average for each month, DATE_FORMAT(date, '%y/%m') is year and month in format YYYY/MM
I'm looking for a function to return the most predominant non numeric value from a table.
My database table records readings from a weatherstation. Many of these are numeric, but wind direction is recorded as one of 16 text values - N,NNE,NE,ENE,E... etc in a varchar field. Records are added every 15 minutes so 95 rows represent a day's weather.
I'm trying to compute the predominant wind direction for the day. Manually you would add together the number of Ns, NNEs, NEs etc and see which there are most of.
Has MySQL got a neat way of doing this?
Thanks
It's difficult to answer your question without seeing your schema, but this should help you.
Assuming the wind directions are stored in the same column as the numeric values you want to ignore, you can use REGEXP to ignore the numeric values, like this:
select generic_string, count(*)
from your_table
where day = '2014-01-01'
and generic_string not regexp '^[0-9]*$'
group by generic_string
order by count(*) desc
limit 1
If wind direction is the only thing stored in the column then it's a little simpler:
select wind_direction, count(*)
from your_table
where day = '2014-01-01'
group by wind_direction
order by count(*) desc
limit 1
You can do this for multiple days using sub-queries. For example (assuming you don't have any data in the future) this query will give you the most common wind direction for each day in the current month:
select this_month.day,
(
select winddir
from weatherdatanum
where thedate >= this_month.day
and thedate < this_month.day + interval 1 day
group by winddir
order by count(*) desc
limit 1
) as daily_leader
from
(
select distinct date(thedate) as day
from weatherdatanum
where thedate >= concat(left(current_date(),7),'-01') - interval 1 month
) this_month
The following query should return you a list of wind directions along with counts sorted by most occurrences:
SELECT wind_dir, COUNT(wind_dir) AS count FROM `mytable` GROUP BY wind_dir ORDER DESC
Hope that helps