Msql getting incompatible with sql_mode=only_full_group_by - mysql

i am using mysql version 5.7.13 in linux
When i running the stored procedure i am getting the following error
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause
and contains nonaggregated column 'medigurus.pp.physicianid' which is not
functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
My Procedure is
DELIMITER $$ DROP PROCEDURE IF EXISTS medigurus.getPatientDoctors$$ CREATE
DEFINER=root#localhost PROCEDURE getPatientDoctors(IN patientid INT(10))
BEGIN SELECT pp.physicianid, d.physiciantypeid, p.firstname, p.lastname,
p.dob, p.mobile, p.officephone, p.address1, p.address2, p.city, p.stateid,
p.cid, p.zip,p.speciality, p.about, p.imgid FROM patientphysicians pp INNER
JOIN physician p ON pp.physicianid = p.physicianid INNER JOIN
getpatientdoctorsview AS d ON d.patientid=pp.patientid WHERE pp.patientid
= patientid GROUP BY p.physicianid; END$$ DELIMITER ;
and view is
DELIMITER $$
DROP VIEW IF EXISTS `medigurus`.`getpatientdoctorsview`$$
CREATE ALGORITHM=UNDEFINED
DEFINER=`root`#`localhost` SQL SECURITY DEFINER VIEW `getpatientdoctorsview` AS
select `pp`.`physicianid` AS `physicianid`,`pp`.`patientid` AS
`patientid`,group_concat(`pp`.`physiciantypeid` separator ',') AS
`physiciantypeid`
from `patientphysicians` `pp` group by `pp`.`patientid`$$
DELIMITER ;
How can i fix the error..

A quick solution is to apply an aggregate function to medigurus.pp.physicianid, like this:
select ... min(medigurus.pp.physicianid) as physicianid, ...
The reason for the error message is that medigurus.pp.physicianid is ambiguous as there could be several values per group, and the SQL engine would need to pick one. Without this setting (restriction), it would just take the first one it encounters, but that behaviour is not in line with the SQL standards.
However, by indicating which one of these values you want to return (e.g. via min), you resolve the issue.
Disabling the "only full group by" option
Alternatively, although not advised, you can return to the old behaviour of MySql, by clearing this option:
SET sql_mode = ''
Concerning the procedure and view
As you provided the actual SQL you have in an update of your question, I add here my observation on that:
The view's select groups the result by patientid in order to aggregate the types of the associated physicians. However, you also select the physicianid: this makes little sense, as in general you might have several different physicians associated with one patient, so its value is not singular. You should just omit that field -- or if you really need one physician per patient, you should ask yourself the question: which one, if there is more than one? Here I will suggest to omit it:
select patientid AS patientid,
group_concat(physiciantypeid separator ',') AS physiciantypeid
from patientphysicians
group by patientid
Secondly, the procedure's SQL is also in need of correction. You seem to want to list the details of all the physicians associated with one particular patient. For that purpose it makes no sense to join the view, as the view only returns one record for a patient, and aggregates the physician types into a comma separated list. This is not useful for the SQL you have in the procedure, where you want a separate record for each physician. So remove the view from it, and just return the physician type for each physician.
Apart from that, you should group by the same physicianid as the one you have in the select list. Don't select the physicianid from pp in the select clause and group by the physicianid from p.
Here is the suggested update:
SELECT p.physicianid,
p.physiciantypeid,
p.firstname,
p.lastname,
p.dob,
p.mobile,
p.officephone,
p.address1,
p.address2,
p.city,
p.stateid,
p.cid,
p.zip,
p.speciality,
p.about,
p.imgid
FROM patientphysicians pp
INNER JOIN physician p
ON pp.physicianid = p.physicianid
WHERE pp.patientid = patientid /* the argument */
GROUP BY p.physicianid
Note that it really helps to understand code better when you apply proper indentation.

Related

not self explicable 1064 error trying to use MEMBER OF in a mysql query

I have a query where I select some rows of a table based on their ID.
SELECT id,hotel_name FROM hotel WHERE id IN (1,2) and this works fine.
It returns two rows from hotel, id 1 and id 2 as expected. IDs in the where clause are hardcoded but data are coming from another table where they are stored in a json column as ["1","2"]. On a normal table i'd have done I'd have done (WHERE id in (SELECT ...) so I tried to replace the IN operator whith MEMBER OF that should behave like IN for JSON columns.
SELECT id,hotel_name FROM hotel
WHERE id MEMBER OF (
SELECT details FROM auth_events
WHERE auth_events.id_user=1 AND auth_events.id_auth_catalog=10
);
but I get
Syntax error in the query next to 'SELECT details FROM auth_events WHERE auth_events.id_user=1 AND auth_events.id_a'
but I don't understand exactly what is raising it. The inner query SELECT details FROM auth_events WHERE auth_events.id_user=1 AND auth_events.id_auth_catalog=10 is returning correctly the ["1","2"] array.
Can anyone help me understand what am I doing wrong? Also note that my mysql version is 8.0.26 and MEMBER OF is available since 8.0.13 so this shouldn't be the point
The operand of MEMBER OF must be scalar JSON array, not a rowset.
Use
SELECT id,hotel_name
FROM hotel
JOIN auth_events ON auth_events.id_user=1
AND auth_events.id_auth_catalog=10
AND hotel.id MEMBER OF (auth_events.details);
PS. The MEMBER OF() operator was added in MySQL 8.0.17, not in 8.0.13.

How to fix "ambiguous" where clause in procedure

I am getting an error:
1052 - Column 'orderId' in where clause is ambiguous
when trying to do CALL GetOrderById(2000)
BEGIN
SELECT
hsorders.*,
hslineitem.partNum, hslineitem.price
FROM
hsorders
JOIN hslineitem ON hslineitem.orderId = hsorders.orderId
WHERE
orderId = orderId;
END
I need to pass an Id and join data from two tables that have the same `orderId``.
What am I doing wrong?
You are getting the error because orderid is in both tables. Hence, the SQL engine does not know which orderid the where clause refers to.
Let me hypothesize that you have a parameter or variable called orderid.
That name conflicts with columns of the same name in the table. That is why I use prefixes. For instance, if orderid is being passed in as a parameter, I would name it in_orderid. If it were a local variable, I might use v_orderid.
Then the code would look like this:
BEGIN
SELECT o.*, li.partNum, li.price
FROM hsorders o JOIN
hslineitem li
ON li.orderId = o.orderId
WHERE o.orderId = v_orderId;
END;
Notice that I also added table aliases so the query is easier to write and to read.
You need to use alias:
BEGIN
SELECT
hsorders.*,
hslineitem.partNum, hslineitem.price
FROM hsorders
JOIN hslineitem ON hslineitem.orderId = hsorders.orderId
WHERE
hsorders.orderId = p_orderId; -- I suggest to rename parameter to avoid
-- name collision
END
ambiguous means use table name or alias name before FIELD
Like hsorders.orderId in where clause.
Use alias while joining tables. It will be helpful to distinguish the columns if they are in both the tables.
When to use alias
BEGIN
SELECT
HO.*,
HL.partNum, HL.price
FROM
hsorders HO
JOIN hslineitem HL
ON HO.orderId = HL.orderId
END
you have already used ON clause to give HO.orderId = HL.orderId
so you do not have to use where clause again

MySQL Different results from same query/data

I have two servers running MySQL. Both are on windows. One, is my local machime (Windows 7, MySQL 5.6.25, 32bit) and the other is my production webserver (Windows 2012, MySQL 5.7.11-log, 64bit (that's what show variables showed me).
The data is identical between the two. I backed the data up from the windows 7 (using MySQL Workbench) and restored it on the 2012 machine.
I am running a query on both machine but I am getting different results. I have two tables, projects and projectsnotes with a 1:m relationship between them related on projects.id to projectsnotes.idProject. Each note is marked with a date (dComment). The goal of the query is to retrieve project information and the latest comment only.
Here's the query:
select space(1) as cAction,
p.id,
p.iNum,
p.cStatus,
p.cName,
p.cDesc,
ifnull(pl.cNickName, 'UNASSIGNED') as cProjectLeader,
IFNULL(concat (
date_format(pn.dComment, '%Y-%m-%d'),
': ',
pn.cComment
), '') as cComment,
date_format(p.dRequested, '%Y-%m-%d') as dRequested,
date_format(p.dRequired, '%Y-%m-%d') as dRequired,
format(p.nPercentComplete, 2) as nPercentComplete,
p.tLastUpdated,
p.bCompleted,
p.idProjectLeader
from projects p
left outer join projectleaders pl on p.idProjectLeader = pl.id
left outer join (
select idProject,
dComment,
cComment
from projectnotes
order by dComment desc,
tLastUpdated desc
) pn on p.id = pn.idProject
where p.cInstallCode = 'ITM'
and cStatus in ('Pending', 'Active', 'On Hold', 'Completed', 'Cancelled')
and bCompleted = 0
group by iNum
order by iNum;
Now, here's the weird part. When I run this on my Windows 7 machine, I get the right value for cComment. Specifically:
2017-03-28: Text from note replace
That is the latest note. When I run it on the 2012 server:
2016-05-17: Text from this note replaced too
If I run the subquery alone on the 2012 server, I get the right values (namely, a list of all the notes in the reverse order.
Oh, and this note is neither the first nor the last in the notes for this project.
So I am honestly wondering what is going on. Any thoughts on this would be greatly appreciated.
Thanks in advance.
This is expected behavior.
select ...
from projects p
left outer join projectleaders pl on p.idProjectLeader = pl.id
left outer join (...) pn on p.id = pn.idProject
where ...
group by iNum
order by iNum;
Due to MySQL's peculiar handling of GROUP BY, it will not report an error on this query. However, you must keep in mind that, since you use no aggregates, and the GROUP BY will eliminate lots of rows, the rows that are kept in the final result set are determined by rather obscure criteria...
For example:
SELECT a,b FROM t GROUP BY a
Which b will be returned? In some MySQL versions, this will be the first value of b that is found in table t. If table t is ordered in a certain way, this can be exploited. But I would definitely not trust that behavior to stay unchanged between versions... Also, remember MySQL is free to change your join order...
OK. I think I have a solution to this. Instead of doing it with a join I wrote a function that returned the value I needed as follows:
DROP FUNCTION if exists f_lastprojectnote;
DELIMITER $$
CREATE FUNCTION f_lastprojectnote(tidProject varchar(36))
RETURNS varchar(1000) DETERMINISTIC
BEGIN
DECLARE cRetVal VARCHAR(1000);
SELECT concat(date_format(pn.dComment, '%Y-%m-%d'), ': ', pn.cComment) INTO cRetVal
FROM projectnotes pn
WHERE idProject = tidProject
ORDER BY dComment DESC, tLastUpdated DESC
LIMIT 1;
RETURN cRetVal;
END$$
DELIMITER ;
It works...

Record does not appear in view yet appears in result of query for view

In MySQL, I have defined a view on two tables as follows:
delimiter $$
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost`<br/>
SQL SECURITY DEFINER VIEW `test`.`viewinschrijvingen` AS<br/>
select `i`.`student` AS `student`,<br/>
`i`.`opleidingscode` AS `opleidingscode`,<br/>
`i`.`inschrijvingsvorm` AS `inschrijvingsvorm`,<br/>
`i`.`brin` AS `brin`,<br/>
`i`.`brinvolgnummer` AS `brinvolgnummer`,<br/>
`o`.`onderwijsvorm` AS `onderwijsvorm`,<br/>
`o`.`opleidingniveau` AS `opleidingniveau`,<br/>
`o`.`naamopleidingkort` AS `naamopleidingkort`,<br/>
`o`.`instelling` AS `instelling`,<br/>
`o`.`studielast` AS `studielast`,<br/>
date_format(max(str_to_date(`i`.`datuminschrijving`,'%Y-%m-%d')),'%Y-%m-%d') AS `datuminschrijving`,<br/>
`o`.`gemeentenaam` AS `gemeentenaam` from<br/>
(`test`.`inschrijvingen` `i` left outer join `test`.`opleidingen` `o`<br/>
on((`i`.`opleidingscode` = `o`.`opleidingscode`)))<br/>
group by `i`.`opleidingscode`,`i`.`brin`,`i`.`brinvolgnummer`$$<br/>
When I query this view for the information on a specific student:
SELECT * FROM test.viewinschrijvingen WHERE student = '310018717'
the result is empty (no records returned). When I browse through the records in the view, there is no record for student 310018717 (obviously).
However, when I execute the query I used to create the view directly:
select `i`.`student` AS `student`,<br/>
`i`.`opleidingscode` AS `opleidingscode`,<br/>
`i`.`inschrijvingsvorm` AS `inschrijvingsvorm`,<br/>
`i`.`brin` AS `brin`,<br/>
`i`.`brinvolgnummer` AS `brinvolgnummer`,<br/>
`o`.`onderwijsvorm` AS `onderwijsvorm`,<br/>
`o`.`opleidingniveau` AS `opleidingniveau`,<br/>
`o`.`naamopleidingkort` AS `naamopleidingkort`,<br/>
`o`.`instelling` AS `instelling`,<br/>
`o`.`studielast` AS `studielast`,<br/>
date_format(max(str_to_date(`i`.`datuminschrijving`,'%Y-%m-%d')),'%Y-%m-%d') AS `datuminschrijving`,<br/>
`o`.`gemeentenaam` AS `gemeentenaam` from<br/>
(`test`.`inschrijvingen` `i` left outer join `test`.`opleidingen` `o`
on((`i`.`opleidingscode` = `o`.`opleidingscode`)))<br/>
WHERE student = '310018717'<br/>
group by `i`.`opleidingscode`,`i`.`brin`,`i`.`brinvolgnummer`<br/>
I do get a result (1 record, which is the result I expected). Can anybody help me to find what is causing this behaviour?
It probably has to do with your use of MySQL's GROUP BY extension versus the ANSI GROUP BY format. MySQL does not require you to group on every column that is not an aggregate function. For columns that you are not GROUPing on, MySQL can choose whatever value it wants for the column. In your case, you are not using the student field to group and thus it may not be choosing the value you are searching for.
You may want to try this query which uses the ANSI GROUP BY and see if you get the results you want.
delimiter $$
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`localhost`
SQL SECURITY DEFINER VIEW `test`.`viewinschrijvingen` AS
select
`i`.`student` AS `student`,
`i`.`opleidingscode` AS `opleidingscode`,
`i`.`inschrijvingsvorm` AS `inschrijvingsvorm`,
`i`.`brin` AS `brin`,
`i`.`brinvolgnummer` AS `brinvolgnummer`,
`o`.`onderwijsvorm` AS `onderwijsvorm`,
`o`.`opleidingniveau` AS `opleidingniveau`,
`o`.`naamopleidingkort` AS `naamopleidingkort`,
`o`.`instelling` AS `instelling`,
`o`.`studielast` AS `studielast`,
date_format(max(str_to_date(`i`.`datuminschrijving`,'%Y-%m-%d')),'%Y-%m-%d') AS `datuminschrijving`,
`o`.`gemeentenaam` AS `gemeentenaam`
from `test`.`inschrijvingen` `i`
left outer join `test`.`opleidingen` `o`
on `i`.`opleidingscode` = `o`.`opleidingscode`
group by
`i`.`student`,
`i`.`opleidingscode`,
`i`.`inschrijvingsvorm`,
`i`.`brin` AS `brin`,
`i`.`brinvolgnummer`,
`o`.`onderwijsvorm`,
`o`.`opleidingniveau`,
`o`.`naamopleidingkort`,
`o`.`instelling`,
`o`.`studielast`,
`o`.`gemeentenaam`$$

sql left join for two tables using a CONCAT string as the argument

I need to get a title from table 2, table 2 has title and id column.
Table 1 has some data and three of these columns concatenated together makeup the id that can be found in table 1.
I used CONCAT_WS() function and gave this column an alias name and need to use the Alias for the on argument(At least this is what I understood I needed to do)
I thought this could be a simple left join, yet it is not working for me.
This is my query
SELECT
table_openers.mail,
table_openers.f_name,
table_openers.l_name,
table_openers.Quality,
CONCAT_WS('-',
table_openers.esp,
table_openers.acc,
table_openers.group) as 't1aid',
table_groups.aid,
table_groups.group_name
FROM
lance_mailstats.table_openers
LEFT JOIN
lance_mailstats.table_groups ON table_groups.aid = t1aid;
I get results for mail, f_name, l_name, Quality and t1aid, but the aid and group_name columns of the second table return null.
I feel like you can't use an alias in the ON clause.
Try doing
LEFT JOIN
lance_mailstats.table_groups ON table_groups.aid = CONCAT_WS('-',
table_openers.esp,
table_openers.acc,
table_openers.group);
"You can use the alias in GROUP BY, ORDER BY, or HAVING clauses to refer to the column" (from dev.mysql.com/doc/refman/5.0/en/problems-with-alias.html).
And "The conditional_expr used with ON is any conditional expression of the form that can be used in a WHERE clause" (from dev.mysql.com/doc/refman/5.1/en/join.html).
So as a logical inference you're not allowed to use aliases in ON clauses.
try to use a subquery..
it goes like this.........
ex.
SELECT
tbl1.mail, tbl1.f_name, tbl1.l_name,tbl1.Quality, tbl1.t1aid,table_groups.aid,
table_groups.group_name
FROM
(SELECT
table_openers.mail,
table_openers.f_name,
table_openers.l_name,
table_openers.Quality,
CONCAT_WS('-',
table_openers.esp,
table_openers.acc,
table_openers.group) as 't1aid',
FROM
lance_mailstats.table_openers )tbl1
LEFT JOIN
lance_mailstats.table_groups ON table_groups.aid = tbl1.t1aid;