-1

The following CodeIgniter query gives an error telling;

Expression #22 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'hw3.1.hw_homework.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

SELECT *, `studentid`, COUNT(studentid),
`be_user_profiles`.`first_name`, `be_user_profiles`.`last_name`
FROM `be_user_profiles` 
JOIN `be_users` ON `be_users`.`id`=`be_user_profiles`.`user_id` 
JOIN `hw_homework` ON `be_user_profiles`.`user_id`=`hw_homework`.`studentid` 
WHERE `be_user_profiles`.`advisor` = '20' 
AND `hw_homework`.`date` < '2018-06-15 00:00:00' 
AND `hw_homework`.`date` > '2017-08-24 00:00:00'
AND `active` = 1 
GROUP BY `be_user_profiles`.`user_id` 
ORDER BY COUNT(studentid) DESC

Filename: modules/organization/models/Mhomework.php

Line Number: 226

$this->db->select('*,studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');
$this->db->from('be_user_profiles');
$this->db->join('be_users','be_users.id=be_user_profiles.user_id');
$this->db->join('hw_homework','be_user_profiles.user_id=hw_homework.studentid');
$this->db->where('be_user_profiles.advisor',$id);
$this->db->where('hw_homework.date <',$to);
$this->db->where('hw_homework.date >',$from);
$this->db->where('active',1);
$this->db->group_by('be_user_profiles.user_id');
$this->db->order_by('COUNT(studentid)','DESC');
$query = $this->db->get();

I removed studentid or added group_by studentid etc but none of them worked.

I know that I can set global SQL mode but I think it is not a solution for me.

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

I want to fix the code not the way around.

halfer
  • 19,824
  • 17
  • 99
  • 186
shin
  • 31,901
  • 69
  • 184
  • 271
  • First read how group by works, because you are not using correctly. Then please google other questions with this error message etc. This is a faq. In the future when reading the manual & googling haven't helped and you ask a question, please read & act on [mcve]. – philipxy Nov 01 '17 at 00:24
  • See my comments on problems with the accepted answer. – philipxy Nov 01 '17 at 10:25

1 Answers1

2

In standard SQL it's very difficult to use SELECT * in a query with GROUP BY. Why? Standard SQL requires SELECTEed columns to also appear in the GROUP BY clause, with a few exceptions for columns with values that are functionally dependent on ones mentioned in the GROUP BY.

To write an aggregate query it's easiest to enumerate the columns you want in your SELECT and again in your GROUP BY. MySQL's notorious nonstandard extension to GROUP BY lets you ask for columns that aren't mentioned in the GROUP BY clause, and proceeds to return some unpredictable value for those columns.

To fix this "right" as opposed to hack around it, you need to get rid of the *. Change

 $this->db->select('*,studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');

to

$this->db->select('studentid,COUNT(studentid),be_user_profiles.first_name,be_user_profiles.last_name');

and, for best results, change

$this->db->group_by('be_user_profiles.user_id');

to

$this->db->group_by('studentid,be_user_profiles.user_id');
O. Jones
  • 103,626
  • 17
  • 118
  • 172
  • 1
    "Cannot SELECT *" is wrong and you misrepresent the problem. – philipxy Nov 01 '17 at 00:28
  • @philipxy I believe O. Jones is correctly saying `remove the select *` and the suggested group by clause is relying on `be_user_profiles.first_name, be_user_profiles.last_name` being functionally dependent on `be_user_profiles.user_id` which (if true) is allowed (although not all databases implement that relatively new part of the standard). – Paul Maxwell Nov 01 '17 at 00:48
  • @Used_By_Already Read what they wrote. I repeat, "Cannot `SELECT *`" is wrong and the answer misrepresents the problem. What is correct is, you can select columns that are grouped by or functionally dependent on those columns & you can use columns as agregate operands. In *this example* one cannot use `select *`. If they said *that* then they wouldn't be wrong about `select *`, they'd still be misleading in "You must enumerate the columns you want" (since enumeration is not the issue) and they'd still be lacking the general case. And they shouldn't have answered this chronic faq. – philipxy Nov 01 '17 at 01:11
  • @philipxy It is reasonably clear that I did read what O. Jones wrote. It appears we just differ on its accuracy as I too hold that **you cannot use SELECT * in a query with GROUP BY**. Do you have a reference for when you can do that when sql_mode=only_full_group_by? – Paul Maxwell Nov 01 '17 at 01:44
  • 1
    @Used_By_Already Clearly, if & only if `*` is only "columns that are grouped by or functionally dependent on those columns". Eg if & only if you grouped on a superset of a CK--eg PK or UNIQUE NOT NULL--since all columns are functionally dependent on such a set of columns. But rather, you should not claim "In standard SQL you cannot use SELECT * in a query with GROUP BY" unless *you* can show that it follows from the rules--which you cannot, because it does not. Moreover saying it still wouldn't *give the rules* but merely one consequence of them. PS I said to read them, not that you hadn't. – philipxy Nov 01 '17 at 01:58
  • @philipxy thank you, I now understand the point you made. – Paul Maxwell Nov 01 '17 at 02:03
  • What is "for best results" supposed to mean? What you suggest cannot make any change to the results, since studentid = be_user_profiles.user_id, and isn't good practice either. – philipxy Nov 01 '17 at 10:40