I have this table below. I want to count and select the values within a month range.
Here's my query
select count(*) as c, monthname(file_date) as mn
from baguio_patrolcase
where monthname(file_date) between 'January' and 'July'
group by monthname(file_date)
order by file_date
What I want to achive is that it will also count and select the values from February an June. How will I do this?
When you convert the date to a month name, you are comparing strings. Here are two options to do what you want:
where month(file_date) between 2 and 6
where file_date >= '2015-02-01' and file_date < '2015-07-01'
The second is better, because it allows the engine to use an index on file_date (if available).
Also, between keeps the end values (it is inclusive). So, if you want February through June, then use those months, rather than 1 and 7.
What I have understood, you can use in clause:
select count(*) as c, monthname(file_date) as mn
from baguio_patrolcase
where monthname(file_date) in('January', 'July')
group by monthname(file_date)
order by file_date
Add the name of all the required months in the in clause.
You can see the SQLFiddle Demo here.
Related
Question: Show the category of competitions that have always been hosted in the same country during May 2010. What is wrong with my query?
select Category
from competition
where Date >= '2010-01-01' and Date <= '2010-12-31'
group by Country, Category
having count(*) = (select count(*)
from competition
where Date >= '2010-01-01' and Date <= '2010-12-31'
group by Category)
You don't need two queries. Just use one query that checks that the count of countries is 1.
select category, count(DISTINCT country) AS country_count
from competition
where Date BETWEEN '2010-05-01' and '2010-05-31'
group by Category
HAVING country_count = 1
I also corrected the dates to be just May, not the whole year 2010.
Remove the GROUP BY if you that is making you return more than 1 row (in your HAVING CLAUSE. If you give me an example dataset and what you want I can help you more
I'd try something like this to start with:
SELECT COUNTRY
, CATEGORY
, COUNT(COUNTRY)
FROM COMPETITION
WHERE DATE BETWEEN '2010-04-30' AND '2010-06-01'
ORDER BY CATEGORY DESC, COUNT(COUNTRY) DESC
;
Your original query's date limits are just for the year of 2010 but you specified you only wanted May 2010. If the Date column is a date or datetime time you'll need to cast the string to the appropriate datatype.
Your question asked "always hosted by one country" - do you know that a competition is only going to be hosted by one country during that particular month? If you do, you're pretty much done. If you don't, however, then you need to clarify what your criteria really are
i have an orders table, and i need to fetch the orders record by month. but i have terms if there is no data in a month it should still show the data but forcing to zero like this:
what i have done is using my query:
select sum(total) as total_orders, DATE_FORMAT(created_at, "%M") as date
from orders
where is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
group by DATE_FORMAT(created_at, "%m")
but the result is only fetched the existed data:
can anyone here help me to create the exactly query?
Thank you so much
Whenever you're trying to use a value that doesn't exist in the table, one option is to use a reference; whether it's from a table or a query-generated value.
I'm guessing that in terms of date data, the column created_at in table orders may have a complete list all the 12 months in a year regardless of which year.
Let's assume that the table data for orders spans from 2019 to present date. With that you can simply create a 12 months reference table for a LEFT JOIN operation. So:
SELECT MONTHNAME(created_at) mnt FROM orders GROUP BY MONTHNAME(created_at);
You can append that into your query like:
SELECT IFNULL(SUM(total),0) as total_orders, mnt
from (SELECT MONTHNAME(created_at) mnt FROM orders GROUP BY MONTHNAME(created_at)) mn
LEFT JOIN orders o
ON mn.mnt=MONTHNAME(created_at)
AND is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
GROUP BY mnt;
Apart from adding the 12 months sub-query and a LEFT JOIN, there are 3 other changes from your original query:
IFNULL() is added to the SUM() operation in SELECT to return 0 if the value is non-existent.
All the WHERE conditions has been switched to ON since remaining it as WHERE will make the LEFT JOIN becoming a normal JOIN.
GROUP BY is using the sub-query generated month (mnt) value instead.
Taking consideration of table orders might not have the full 12 months, you can generate it from query. There are a lot of ways of doing it but here I'm only going to show the UNION method that works with most MySQL version.
SELECT MONTHNAME(CONCAT_WS('-',YEAR(NOW()),mnt,'01')) dt
FROM
(SELECT 1 AS mnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION
SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12) mn
If you're using MariaDB version that supports SEQUENCE ENGINE, the same query above is much shorter:
SELECT MONTHNAME(CONCAT_WS('-',YEAR(NOW()),mnt,'01'))
FROM (SELECT seq AS mnt FROM seq_1_to_12) mn
I'm using MariaDB 10.5 in this demo fiddle however it seems like the month name ordering is based on the name value rather than the month itself so it looks un-ordered. It's in the correct order if it's in MySQL 8.0 fiddle though.
Thanks all for the answers & comments i really appreciate it.
i solved it by create table helper for static months then use union and aliasing, since i need the months in indonesia, i create case-when function too.
so, the query is like this:
SELECT total_orders,
(CASE date WHEN 01 THEN 'Januari'
WHEN 02 THEN 'Februari'
WHEN 03 THEN 'Maret'
WHEN 04 THEN 'April'
WHEN 05 THEN 'Mei'
WHEN 06 THEN 'Juni'
WHEN 07 THEN 'Juli'
WHEN 08 THEN 'Agustus'
WHEN 09 THEN 'September'
WHEN 10 THEN 'Oktober'
WHEN 11 THEN 'November'
WHEN 12 THEN 'Desember'
ELSE date END ) AS date
FROM (SELECT SUM(total) AS total_orders,
DATE_FORMAT(created_at, "%m") AS date
FROM orders
WHERE is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
GROUP BY DATE_FORMAT(created_at, "%m")
UNION
SELECT 0 AS total_orders,
code AS date
FROM quantum_default_months ) as Q
GROUP BY date
I still don't know if this query is fully correct or not, but I get my exact result.
cmiiw.
thanks all
I have a database with multiple columns from which I have created this view where I have multiple rows similar to the ones shown below. The data is available for each day of the month from 2009 to 2010 and for all the month for the 5 names given. I have to get the 'Name' for which the occurrence of category 'Super' is more than 5 times each month and list them out separately for each month. The view contains data for all months together.
Name Dates Category
--------------------------------
PAT 2009-01-01 Super
YAT 2009-01-01 No
ROT 2009-01-01 No
SUP 2009-01-01 Super
ANT 2009-01-01 Super
I tried getting a count of the Name in MySQL using
SELECT `NAME`,`DATES`
FROM (
SELECT `NAME`, `CATEGORY`,MONTH(`DATES`)
FROM VIEW
GROUP BY `NAME`, `CATEGORY`,MONTH(`DATES`)
HAVING COUNT(`CATEGORY`)>5
) a
GROUP BY `NAME`
HAVING count(`CATEGORY`)>5;
But it does not return any rows.
You're trying to group your rows into months. The best way to do this is to start with an expression that will take any date and convert it to the first day of the month in which it occurs. That expression is.
DATE(DATE_FORMAT(dates, '%Y-%m-01'))
Next, you use this expression in a query with a GROUP BY clause.
SELECT NAME, CATEGORY,
DATE(DATE_FORMAT(DATES, '%Y-%m-01')) DATES
FROM VIEW
GROUP BY NAME, CATEGORY, DATE(DATE_FORMAT(DATES, '%Y-%m-01'))
HAVING COUNT(*) > 5
This will yield all the name / category / month combinations occurring more than five times.
I think that's what you want. But maybe you want all the monthly items listed in any month where the Super category appears more than five times for some name. To do that first we write a subquery to get a list of those dates:
SELECT DATE(DATE_FORMAT(DATES, '%Y-%m-01')) DATES
FROM VIEW
WHERE CATEGORY = 'Super'
GROUP BY NAME, DATE(DATE_FORMAT(DATES, '%Y-%m-01'))
HAVING COUNT(*) > 5
Then we write a main query to get all the data
SELECT DISTINCT
NAME, CATEGORY,
DATE(DATE_FORMAT(DATES, '%Y-%m-01')) DATES
FROM VIEW
WHERE DATE(DATE_FORMAT(DATES, '%Y-%m-01')) IN
(
SELECT DATE(DATE_FORMAT(DATES, '%Y-%m-01')) DATES
FROM VIEW
WHERE CATEGORY = 'Super'
GROUP BY NAME, DATE(DATE_FORMAT(DATES, '%Y-%m-01'))
HAVING COUNT(*) > 5
)
The trick to getting this sort of thing to work is choosing the right date-arithmetic expression to use in your GROUP BY clause. The functions like DAY(), MONTH(), and YEAR() are surprisingly difficult to use correctly, so I think you may find DATE(DATE_FORMAT(dates, '%Y-%m-01')) more reliable.
I have a column of type date. I want to group rows per month for a particular year.
I did the following:
SELECT SUM(price), DATE_FORMAT(production_date, '%Y%m')
FROM TABLE
WHERE YEAR(production_date) = ?
GROUP BY 2
Is there a better/more efficient way to do this?
Instead of specifying the year using the YEAR function
SELECT SUM(price), DATE_FORMAT(production_date, '%Y%m')
FROM TABLE
WHERE YEAR(production_date) = 2014
GROUP BY 2
specify it like this
SELECT SUM(price), DATE_FORMAT(production_date, '%Y%m')
FROM TABLE
WHERE production_date BETWEEN '2014-01-01' AND '2014-12-31'
GROUP BY 2
The 2nd query enables the db to use an index on production_date
you are almost there :)
SELECT SUM(price), MONTH(production_date)
FROM TABLE
WHERE YEAR(production_date) = ?
GROUP BY 2
I have a SQL/Java code issue. The basic overlay is as follows: a MySQL database with a table. In this table there are multiple columns. One column consists of names. An associated column is months. In the third column there is counts. So a sample table would be
john - january - 5
john - january - 6
mary - january - 5
Alex - February- 5
John - February - 6
John - February - 4
Mary - February - 3
John - march - 4
The table continues to month May.
So John appears in five months, Mary in 3, and Alex in one. Currently, my SQL query somewhat looks like this.
select name, sum(count)/4
from table where (category ='something'
AND month not like 'May') group by name;
Basically, what this query is supposed to do is just display each name with the average counts per month. Hence, the sum will be divided by four (because I exclude May, so it must divide Jan-April/4). However, the issue is that some names only appear in one month (or two or three).
This means for that name, the sum of the counts would only be divided by that specific number, to get the average counts over the months. How would I go about this? I feel as if this will require some if statement in a where clause. Kind of like where if the count of the distinct (because months may repeat) is a certain number, then divide the sum(count) by that number for each name?
Also, I think it may not be a where if clause issue. I've read some forums where possibly some use of case could be utilized?
If you need average per month, you can GROUP BY name and month and use AVG function:
SELECT `name`, `month`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`, `month`;
If you need average for all period, just GROUP BY name and AVG count:
SELECT `name`, avg(`count`)
FROM table
WHERE `category` ='something' AND `month` NOT LIKE 'May'
GROUP BY `name`;
And another option, if you don't like AVG:
SELECT `name`, sum(`count`)/(SELECT count(*) FROM `table` AS `t2` WHERE `category` ='something' AND `month` NOT LIKE 'May' and `t1`.`name` = `t2`.`name`)
FROM `table` AS `t1`
WHERE `category` ='something' AND `month` NOT LIKE 'May')
GROUP BY name;
But I would stay with AVG.
Actually, i prefer to use != instead of NOT LIKE it's improves readability
Just for completness sake here is a WORKING FIDDLE. using the AVG function is the way to go as it will do the average per person per month. look at John in January.. his result is 5.5 when the count (in january) is 5 and 6.. average = 5.5.
SELECT
person,
month,
avg(counter)
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month;
If you want to see the data in one like as it sounds like that from your post then you can do this. ANOTHER FIDDLE
SELECT
person,
group_concat(month),
group_concat(average_count)
FROM(
SELECT
person,
month,
avg(counter) as average_count
FROM testing
where
(
category ='something'
AND month <> 'May'
)
GROUP BY person, month
) as t
group by person;
Try this :
SELECT name, SUM(count) / COUNT(DISTINCT month)
FROM table
WHERE month != 'May'
AND category = 'something'
GROUP BY name