SELECT date and then putting it into group - mysql

I am trying to select dates from my DB and then group it as months and years for example:
May 2019
June 2018
etc.
DB
-the date is type date
I have this code:
SELECT datum, count(*) FROM zapasy GROUP BY datum
Which makes it on each day, but I don't want that so I searched how to make it group as months and years, not just days
SELECT datum, count(*) FROM zapasy GROUP BY MONTH(datum), YEAR(datum)
and I came up with this, however, I am getting this stupid error
#1055 - Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'zapasy_db_test.zapasy.datum' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
And I have no idea what is wrong with the code
Please, give me some advice.
Thank you

You need to have the items you're grouping by in your select.
So
SELECT MONTH(datum), YEAR(datum), count(*) from ... group by MONTH(datum), YEAR(datum)
instead of datum, otherwise a date column you're selecting, will have a day in it, which you'd get from just datum, and that has nothing to do with the count and group and would be wrong, or the grouping wouldn't work at all.

I notice that your desired output is in this format May 2019 etc. You know that DATE datatype is like this, yyyy-mm-dd so if you really, really want to extract the month-year in that format, you can try the following:
SELECT DATE_FORMAT(datum, '%b %Y') AS 'Monthyear', COUNT(*)
FROM zapasy
GROUP BY Monthyear;

Related

Subquery returns more than 1 row, how can I solve?

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

SELECT a column not in GROUP BY clause

I'm trying to write a query that would select only the rows that have events which where the only events in that year.
Eg:
Year Event
2011 A
2011 B
2012 C
2013 B
2013 D
2014 D
So, I would like to get the rows 2012 C and 2014 D in the results.
I tried doing a GROUP BY on Year, but that wouldn't let me select the Event column.
2011 and 2013 have 2 events, so these shouldn't be in the results.
Please help.
EDIT: I could write a nested query to get the only the rows having count(Year) = 1 with GROUP BY Year, but I'm unable to get the Event column selected in the outer query
SELECT Year, Event from table where Year in (SELECT Year from table GROUP BY Year Having count(*) = 1) as count;
There is no need for using a subquery or nested query. You can simply GROUP By Year field and use HAVING COUNT(Year)=1 to find the required rows. So, the applicable query will be:
SELECT Year, Event
FROM table_name
GROUP BY Year
HAVING COUNT(Year)=1
You can find the executable solution sample at:
http://sqlfiddle.com/#!9/b47044/11
Logic:
When you group by Yearit aggregates all rows with same year. So, count will be 2 for 2011.
You can check this by running:
SELECT Year, Event, COUNT(Year) as event_count
FROM table_name
GROUP BY Year
You can see this intermediate step in execution, at: http://sqlfiddle.com/#!9/b47044/10
This above solution will only work for MySQL version < 5.7. For higher versions find the solution below.
For 5.7 and greater the ONLY_FULL_GROUP_BY SQL mode is enabled by default so this will fail. Either you can update this mode( Refer answers under SELECT list is not in GROUP BY clause and contains nonaggregated column .... incompatible with sql_mode=only_full_group_by ) or alternatively you can use ANY_VALUE() function to refer to the non-aggregated column, so update query that will work in MySQL 5.7 and greater is:
SELECT Year, ANY_VALUE(Event)
FROM table_name
GROUP BY Year
HAVING COUNT(Year)=1;
You can find executable example at: https://paiza.io/projects/e/tU-7cUoy3hQUk2A7tFfVJg
Reference: https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/miscellaneous-functions.html#function_any-value
You have a minor mistake in the query, the count(*) which is used in having clause should also be in the select clause
SELECT Year, Event from table where Year in (
SELECT Year from (
SELECT Year,count(*) from table GROUP BY Year Having count(*) = 1)temp
);
Only those Year and events need to be filtered which contains single event that Year
Inner Query would give you only years which have one event
Outer query would select the events of those years
SELECT Year, Event from table where Year in
(SELECT Year from table GROUP BY Year Having count(*) = 1);
Good Question,
You don't even need a subquery to get the desired output. Concatenate all the event names into one string, then search for comma , in the string, If comma , is found, this year has more than one events, otherwise only one.
SELECT Year, GROUP_CONCAT(Event) AS Event FROM Events GROUP BY (year) having
INSTR(Event, ",") = 0;
SELECT Year, Event
FROM table
WHERE Year in (SELECT Year
FROM table
GROUP BY Year
HAVING count(*) = 1);

related to query using SQL

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.

Questions for having clause and where clause

I have a very simple question. I am using Mysql bench, and i had a data which likes below:
dateordered_new orderstatus orders
2016-06-23 23:19:23 returned 8
2016-06-01 23:19:23 completed 12
2016-06-22 23:19:23 returned 9
2016-06-04 23:19:23 completed 27
...etc...
The question is simple, I want to show the amount of orders which has been returned in each month.
And here is my query:
select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
group by month
having orderstatus='returned;
Considering the difference between where clause and having clause, my syntax should be worked. However, the system told me that "Error Code: 1054. Unknown column 'orderstatus' in 'having clause'" And it was wired.
However, when I modified my query like this:
select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
where orderstatus='returned
group by month;
And it worked.
So, it was really confusing. I think having clause should follow by the group by statement. But I cannot answer why this case happened?
Do you guys have any idea for this?
In your situation, you should use a where clause:
select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
where orderstatus='returned'
group by month
Because you want to filter rows from the table before they are aggregated.
You only use having clause when you want to filter on an aggregate value, eg
select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
group by month
having sum(orders) > 10
However, mysql is flexible and allows you to use a having on a non-aggregate value.
HAVING is used to filter out results of aggregations, like MIN/MAX/AVERAGE, while WHERE is used to filter on non-aggregate columns.
For example, you can do this:
select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
WHERE orderstatus='returned'
group by month
having sum(orders) < 100
You have to replace the condition mentioned the having clause with where clause. Because having clause filter the data on aggregated group and where clause filter the data on whole record set.
Try the below SQL:
Select month(dateorderednew) as Month, sum(orders) as return_orders
from table_a
where orderstatus='returned
group by month;
A 'WHERE' clause filters on individual row values...
where colname > 0
or
where colname = 'sometext'
A 'HAVING clause filters on a group or aggregate of a row and comes after the 'group by' statement if there is one...
group by colname
having count(*) > 0
or
group by colname
having sum(colname) < 1

Selecting rows which have a similar value for a particular column which occurs n times each month

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.