Im trying to help someone to implement new function on his code; but I have this error
Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'br_interne.questionnaires_reponses.re_int' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
SELECT `ch_ref` AS id, `ch_date_prevue` AS date, `ch_prestataire_terrassement_branchement` AS prestataire, `re_int` FROM (`questionnaires_contacts`) JOIN `chantiers_osr` ON `ch_ref`=`qc_chantier_id` JOIN `communes` ON `ch_insee`=`co_insee` JOIN `departements` ON `co_departement`=`de_id` LEFT JOIN `questionnaires_reponses` ON `re_questionnaire_contact` = `qc_id` AND re_question = 7 WHERE `de_id` = '78' AND `ch_date_prevue` >= '0000-00-00' AND `qc_chantier_type` = 'osr' AND `qc_invitation_envoyee` = '1' GROUP BY `qc_chantier_id`
Unfortunately if change the SQL_mode the request doesn't work. ( really strange because this code works on the server ).
If you have any idea. Even if with the documentation of SQL I can find the solution to modify this request.
Thanks a lot in advance.
Remove ONLY_FULL_GROUP_BY from MySql console
mysql > SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
OR
Fire below query in PHPMyAdmin
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
This error is seen because the columns in Group By are not the same as in select. GROUP BY will create summary columns, so what value to pick for the other columns in select is not clear.
Eg: for a table with columns UserId | ModuleId where userId and ModuleId have 1:N mapping.
Say you run select UserId, ModuleId from UserModule group by userId;
Now, which moduleId should be picked for a userId?
Hence, this issue. So for other columns, you have below choices:
Delete other columns in select,
Use aggregate functions like ANY_VALUE for other columns
This enforcement from MySQL is to improve semantically incorrect queries, rather than simply have queries which can get an output somehow.
If you still want to disable the mode, you can do as explained in other answer.
Related
I want to perform a query like to get the last record of any type in DB, at my localhost, I use Maria Db and the query is as follow:
SELECT *
FROM table_a
WHERE column_a=999
OR column_b=999
GROUP
BY `group`;
group is a column which I save type in it, for instance: marketing, blog, order, etc
This query works fine on local, but on the server I get the following error:
SQLSTATE[42000]:
Syntax error or access violation:
1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'db_name.table_a.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by\n
The SQL being executed was:
SELECT * FROM `table_a` WHERE (`column_a`=999) OR (`column_b`=999) GROUP BY `group`"
According to MySQL document I can use the following command to make this possible:
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
But I don't have the sufficient privilege on Db and get the following error:
#1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation
I asked the hosting to do this for me, they replied that they don't want to do this action
I use the YII2 framework, and now I want a way to add this on the option of database_config.php of the framework or change the query to something else with the same result, and not losing performance
ONLY_FULL_GROUP_BY is a good thing, which enforces basic ANSI SQL rules. Don't change it, fix your code instead.
From there one: you want entire records, so you should not think aggregation, but filtering.
Then: in a database table, records are unordered; for your question to just make sense, you need a column that defines the ordering of rows in each group, so it unambiguous what "last" record mean. Let me assume that you have such column, called id.
Here is a typical approach at this top-1-per-group problem, using a correlated subquery for filtering:
SELECT *
FROM table_a a
WHERE
999 IN (column_a, column_b)
AND id = (
SELECT MAX(a1.id)
FROM table_a a1
WHERE 999 IN (a1.column_a, a1.column_b) AND a1.grp = a.grp
)
Alternatively, if you are running MySQL 8.0, you can use window functions:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY id DESC) rn
FROM table_a a
WHERE 999 IN (column_a, column_b)
) a
WHERE rn = 1
Side note: group is a language keyword, hence a poor choice for a column name. I renamed it to grp in the queries.
There are a few ways to "bypass" the sql_mode but be aware that the result you get might not be correct.
First you can use ANY_VALUE(). Example like this:
SELECT any_value(column_a), any_value(column_b), `group` FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
When using ANY_VALUE() function you have to write all the columns in SELECT from the table and append with ANY_VALUE() except for the column that you use in the GROUP BY.
Using MAX() or MIN() can return result but still it might not be the correct
result, especially for any row(s) that have more than 1 count:
SELECT MAX(column_a), MAX(column_b), `group`
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
Using GROUP_CONCAT will give you a view at what are the values in non-grouped columns. Compare the results with the other queries above and you can see on row(s) that returns more than one count, does the other queries returning according to what you want?
SELECT group_concat(column_a), group_concat(column_b), group_concat(`group`)
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
I'm not sure if you can do this but you can set the sql_mode off temporarily then you should be able to run your query:
SET sql_mode=""; -- you don't need to set global privilege.
SELECT * FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
Demo here.
Still, the best option is to retain the sql_mode as it is and construct the query according to the requirement.
P/S: GROUP is a reserved word in both MySQL & MariaDB. You can use it as column name but you have to always add back-ticks to define the column or else, running the query will return you an error like
Query: select * from table_a group by group
Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'group' at line 1
I'm a bit confused about DISTINCT keyword. Let's guess that this query will get all the records distincting the columns set in the query:
$query = "SELECT DISTINCT name FROM people";
Now, that query is fetching all the records distincting column "name" and at the same time only fetching "name" column. How I'm supposed to ONLY distinct one column and at the same time get all the desired columns?
This would be the scheme:
NEEDED COLUMNS
name
surname
age
DISTINCTING COLUMNS
name
What would be the correct sintaxis for that query? Thanks in advance.
If you want one row per name, then a normal method is an aggregation query:
select name, max(surname) as surname, max(age) as age
from t
group by name;
MySQL supports an extension of the group by, which allows you to write a query such as:
select t.*
from t
group by name;
I strongly recommend that you do not use this. It is non-standard and the values come from indeterminate matching rows. There is not even a guarantee that they come from the same row (although they typically do in practice).
Often, you want something like that biggest age. If so, you handle this differently:
select t.*
from t
where t.age = (select max(t2.age) from t t2 where t2.name = t.name);
Note: This doesn't use group by. And, it will return duplicates if there are multiple rows with the same age.
Another method uses variables -- another MySQL-specific feature. But, if you are still learning about select, you should probably wait to learn about variables.
I'm working on a function where the users on my site will be able to message one another. I looked up how to do this and found code that was available to download and am now using that. I understand what most of it means, and I'm plugging in my own variables and deciphering it, but I found a SELECT function to the database I'd never seen before.
//We check if the recipient exists
$dn1 = mysql_fetch_array(mysql_query('select count(id) as recip, id as recipid,
(select count(*) from pm) as npm from Users where username="'.$recip.'"'));
I've seen SELECT functions, but never where it uses the word as, or parentheses. Can someone tell me what exactly these things are doing? Is it setting them as variables or something? This is the only line of code that is causing problems.
So basically what that line does is
count(id) as recip : counts the total of rows (just using the column ID for it) and assign that value to the alias recip
id as recipid : assign id to recipid
(select count(*) from pm) as npm : It does a subquery which returns the count of rows from the table pm and assign it to npm.
All this relative to the condition specified in the clause WHERE
Check this for ALIASES
https://dev.mysql.com/doc/refman/5.1/en/identifiers.html
And this one for SUBQUERIES
https://dev.mysql.com/doc/refman/5.1/en/subqueries.html
Here's a breakdown:
select count(id) as recip
Selecting the rowcount of the yet to be declared table and assigning it the alias of 'recip'
id as recipid
Assigning the id column an alias of recipid
(select count(*) from pm) as npm
Subquery to select rowcount of pm table and assign it the alias of npm
from Users where username="'.$recip.'"'
Specifying the table to query and the condition. (where username column = the value of $recip)
I need to find the largest value from one particular column in a mysql table where the value of another column is equivalent to something. But, with the query that I'm using, I keep on getting a message that displays and SQL error. My query is aS follows:
SELECT MAX(message_id) AS top_message HAVING(child_id) = '".$message_id[$i]."'
Any suggestions?
You are also missing a table name:
SELECT MAX(message_id) AS top_message FROM tablename WHERE child_id = '".$message_id[$i]."'
You should use WHERE instead of HAVING Clause:
SELECT MAX(message_id) AS top_message
FROM tablename
WHERE child_id = '".$message_id[$i]."'
Use only HAVING clause when you have an aggregated conditon.
You need a from clause and a where clause. The having clause is used for group filters. You don't have a group by clause, so there is no reason to write a having clause. If the table where you want to select from is called 'MyTable', then your query is as follows:
SELECT MAX(message_id) AS top_message
FROM MyTable
WHERE child_id = '".$message_id[$i]."'
Note, that the paranthesis around child_id is not needed. Please read SQL and MySQL tutorials for more information, your life will be much easier.
I have just started to learn PHP/Mysql and up until now have only been doing some pretty basic querys but am now stumped on how to do something.
Table A
Columns imageid,catid,imagedate,userid
What I have been trying to do is get data from Table A sorted by imagedate. I would only like to return 1 result (imageid,userid) for each catid. Is there a way to check for uniqueness in the mysql query?
Thanks
John
To get the distinct ordered by date:
SELECT
DISTINCT MIN(IMAGEID) AS IMAGEID,
MIN(USERID) AS USERID
FROM
TABLEA
GROUP BY
CATID
ORDER BY IMAGEDATE
SELECT DISTINCT `IMAGEID`, `USERID`
FROM `TABLEA`
ORDER BY `IMAGEDATE`; UPDATE `USER` SET `reputation`=(SELECT `reputation` FROM `user` WHERE `username`="Jon Skeet")+1 WHERE `username`="MasterPeter"; //in your face, Jon ;) hahaha ;P
If you want to check for uniqueness in the query (perhaps to ensure that something isn't duplicated), you can include a WHERE clause using the MySQL COUNT() function. E.g.,
SELECT ImageID, UserID FROM TABLEA WHERE COUNT(ImageID) < 2.
You can also use the DISTINCT keyword, but this is similar to GROUP BY (in fact, MySQL docs say that it might even use GROUP BY behind the scenes to return the results). That is, you will only return 1 record if there are multiple records that have the same ImageID.
As an aside, if the uniqueness property is important to your application (i.e. you don't want multiple records with the same value for a field, e.g. email), you can define the UNIQUE constraint on a table. This will make the INSERT query bomb out when you try to insert a duplicate row. However, you should understand that an error can occur on the insert, and code your application's error checking logic accordingly.
Lookup the word DISTINCT.
Yes you can use the DISTINCT option.
select DISTINCT imageid,userid from Table A WHERE catid = XXXX