8

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;
Fayaz Ahmed
  • 953
  • 1
  • 9
  • 23

5 Answers5

5

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

saji89
  • 2,093
  • 4
  • 27
  • 49
  • 1
    Nice one, I use this `SELECT Year, GROUP_CONCAT(Event) AS Event FROM Events GROUP BY (year) having INSTR(Event, ",") = 0;` but yours seems more readable – Amir Saleem Jun 30 '19 at 06:53
  • I tried this, but this doesn't work. Not sure why. `ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.Events.Event' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by` – Fayaz Ahmed Jun 30 '19 at 06:56
  • Which version of MySQL are you using @FayazAhmed – saji89 Jun 30 '19 at 06:58
  • @FayazAhmed I assume that you're using MySQL 5.7 or greater. On checking found that this query may not be supported in newer versions. By default `ONLY_FULL_GROUP_BY` SQL mode is enabled. Ref: https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/group-by-handling.html In short, this is a good solution for MySQL < 5.7. Though I would not suggest, if you want to get this query working, you may want to check: https://stackoverflow.com/a/41887627/749232 – saji89 Jun 30 '19 at 07:08
  • Thanks. Got it to work after the following settings. `mysql> set global sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; mysql> set session sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';` – Fayaz Ahmed Jun 30 '19 at 07:14
  • @FayazAhmed There is a better solution, by using `ANY_VALUE()` function. You can find running example at: https://paiza.io/projects/e/tU-7cUoy3hQUk2A7tFfVJg I have updated my answer with this info. Do mark as accepted answer if you find it working well for you. – saji89 Jun 30 '19 at 07:20
2

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 );

Jeffy Mathew
  • 570
  • 4
  • 16
2

Only those Year and events need to be filtered which contains single event that Year

  1. Inner Query would give you only years which have one event
  2. 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);
tawab_shakeel
  • 3,701
  • 10
  • 26
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;
Amir Saleem
  • 2,912
  • 3
  • 21
  • 35
-1
SELECT Year, Event 
FROM table 
WHERE Year in (SELECT Year 
               FROM table 
               GROUP BY Year 
               HAVING count(*) = 1);
Mangesh Auti
  • 1,123
  • 1
  • 7
  • 12