Unknown column in where clause when nested selection - mysql

I have to get results from different tables in one query. But got the unknown column error.
SET sql_mode = '';
SELECT
e_mills.m_id,
e_mills.mill_name,
e_cities.city_name,
e_sugardata.mill_closing_stock,
(
SELECT GROUP_CONCAT(mill_closing_stock SEPARATOR ', ')
FROM (
SELECT mill_closing_stock
FROM `e_sugardata`
WHERE m_id = e_mills.m_id
GROUP BY date_added
ORDER BY date_added DESC
LIMIT 0,4
) AS mill_closing_stock
) AS stock_chart
FROM e_mills
INNER JOIN e_cities
ON e_mills.city_id = e_cities.city_id
INNER JOIN e_sugardata
ON e_sugardata.m_id = e_mills.m_id
ORDER BY e_mills.province_id
ERROR
#1054 - Unknown column 'e_mills.m_id' in 'where clause'
UPDATE
Same query is working on my computer but not on other computer
UPDATE 2 working on MySQL 8
MySQL 8 DB Fiddle

To avoid an error in MySQL 5.7, you need to get rid of the nested query with a limit. Instead of a LIMIT clause, you can use the SUBSTRING_INDEX function. Also, the GROUP BY clause is unnecessary, especially since it does not work without changing sql_mode if the column list of the SELECT clause does not match the GROUP BY list.
-- SET sql_mode = ''; -- no more needed.
SELECT
e_mills.m_id,
e_mills.mill_name,
e_cities.city_name,
e_sugardata.mill_closing_stock,
(
SELECT
SUBSTRING_INDEX(
GROUP_CONCAT(mill_closing_stock ORDER BY date_added DESC SEPARATOR ', '
), ', ', 4
)
FROM `e_sugardata`
WHERE m_id = e_mills.m_id
) AS stock_chart
FROM e_mills
INNER JOIN e_cities
ON e_mills.city_id = e_cities.city_id
INNER JOIN e_sugardata
ON e_sugardata.m_id = e_mills.m_id
ORDER BY e_mills.province_id
db<>fiddle: MySQL 5.7 and MySQL 8

Related

Mysql query how to avoid rows nulls/empty fields while doing left join

I have tried a query in mysql which works fine as:
SELECT medias.id,medias.hash,medias.customid,medias.timestamp,medias.uploaded,
medias.data_updated, mediadetails.media_id, mediadetails.city,
mediadetails.state_province, mediadetails.postal_code
FROM medias
LEFT JOIN mediadetails ON medias.id=mediadetails.media_id
ORDER BY medias.data_updated DESC
LIMIT 5;
Now I am trying to get those rows which do not have empty city/state_provice/postal_code.
Tried this :
SELECT medias.id, medias.hash,medias.customid, medias.timestamp,medias.uploaded,
medias.data_updated, mediadetails.media_id, mediadetails.city,
mediadetails.state_province, mediadetails.postal_code
FROM medias
LEFT JOIN mediadetails on medias.id=mediadetails.media_id
ORDER BY medias.data_updated DESC
WHERE medias.city<>''
AND medias.state_province<>''
AND medias.postal_code<>''
LIMIT 5;
However getting error:
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where medias.city<>'' and medias.state_province<>'' and medias.postal_code<>'' l' at line 1
Can I get help on how to do it?
Empty usually means null.
In this case don't compare the column value to '', but use IS NOT NULL.
In any case, you can use coalesce():
SELECT
medias.id, medias.hash,medias.customid, medias.timestamp,
medias.uploaded, medias.data_updated,
mediadetails.media_id, mediadetails.city,
mediadetails.state_province, mediadetails.postal_code
FROM medias INNER JOIN mediadetails
ON medias.id=mediadetails.media_id
WHERE
COALESCE(mediadetails.city, '') <>''
AND
COALESCE(mediadetails.state_province, '') <>''
AND
COALESCE(mediadetails.postal_code, '') <>''
ORDER BY mediadetails.data_updated DESC
LIMIT 5;
Although this would work in most cases:
WHERE
mediadetails.city IS NOT NULL
AND
mediadetails.state_province IS NOT NULL
AND
mediadetails.postal_code IS NOT NULL
I am going to assume your WHERE clause meant to reference table mediadetails. An observations: A NULL field when compared with any value will never compare TRUE. Thus, your WHERE clause will only select columns from the meidadetails table for non-NULL (and non-empty) values for the specified columns and the MySQL optimizer will replace your OUTER JOIN with an INNER JOIN. You might as well make it explicit:
SELECT medias.id, medias.hash,medias.customid, medias.timestamp,medias.uploaded,
medias.data_updated, mediadetails.media_id, mediadetails.city,
mediadetails.state_province, mediadetails.postal_code
FROM medias
INNER JOIN mediadetails on medias.id=mediadetails.media_id
WHERE mediadetails.city <>''
AND mediadetails.state_province <>''
AND IFNULL(mediadetails.postal_code <>''
ORDER BY mediadetails.data_updated DESC
;

Difference query lastest result each group when using "group by" clause between MySQL 5.6 and 5.7

My question is that I used the same SQL query below on MySQL 5.6(Windows) and MySQL 5.7.21(Linux), got different results.
My requirement is getting the lastest row each group, the result from MySQL 5.6 did, but MySQL 5.7 did not get the latest row each group instead earliest row. It seems like that MySQL 5.7 optimized my query "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt" without ordered.
I need MySQL 5.7 to get the same query result like 5.6 does. Is there any tricky I made mistakes?
SELECT
chn.channel_id,
CONCAT(
IFNULL(p_chn.channel_path, ''),
'/',
IFNULL(chn.channel_path, '')
) AS channel_path,
chnext.channel_name,
cnt.content_id,
cntex.title,
cntex.short_title,
cntex.release_date,
cntex.origin,
cntex.title_img,
cntex.type_img,
cntex.description AS descriptionStr,
cnt.sort_date
FROM
(
SELECT
*
FROM
jc_content
ORDER BY
sort_date DESC
) cnt
LEFT JOIN jc_content_ext cntex ON cnt.content_id = cntex.content_id
LEFT JOIN jc_channel chn ON chn.channel_id = cnt.channel_id
LEFT JOIN jc_channel p_chn ON chn.parent_id = p_chn.channel_id
LEFT JOIN jc_channel_ext chnext ON chnext.channel_id = cnt.channel_id
WHERE
cnt.`status` = 2
AND p_chn.channel_path = 'cp'
GROUP BY
channel_path
ORDER BY
cnt.sort_date DESC
Edited after asking;
Here is my solution, I found it out inadvertently. Just add "limit" after the derived query.
SELECT
chn.channel_id,
CONCAT(
IFNULL(p_chn.channel_path, ''),
'/',
IFNULL(chn.channel_path, '')
) AS channel_path,
chnext.channel_name,
cnt.content_id,
cntex.title,
cntex.short_title,
cntex.release_date,
cntex.origin,
cntex.title_img,
cntex.type_img,
cntex.description AS descriptionStr,
cnt.sort_date
FROM
(
SELECT
*
FROM
jc_content
ORDER BY
sort_date DESC
<em>LIMIT 100</em>
) cnt
LEFT JOIN jc_content_ext cntex ON cnt.content_id = cntex.content_id
LEFT JOIN jc_channel chn ON chn.channel_id = cnt.channel_id
LEFT JOIN jc_channel p_chn ON chn.parent_id = p_chn.channel_id
LEFT JOIN jc_channel_ext chnext ON chnext.channel_id = cnt.channel_id
WHERE
cnt.`status` = 2
AND p_chn.channel_path = 'cp'
GROUP BY
channel_path
ORDER BY
cnt.sort_date DESC
As you can see, when I add the limit it works. I tried to figure out and I used "EXPLAIN" SQL, It showed below:
enter image description here
Without "limit" by "EXPLAIN" it showed below:
enter image description here
Thus I could infer from the upons that MySQL 5.7 does optimize my query "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt" without ordered, when I put limit behind, it becomes a derived table then it works. I used "EXPLAIN" on MySQL 5.6, it did not optimize the "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC ) cnt", it showed select_type of "DERIVED" and queried all rows.
Also I found the tricky point, once I changed the limit value, like "FROM ( SELECT * FROM jc_content ORDER BY sort_date DESC LIMIT 400 ) cnt", "EXPLAIN" that, it showed:
enter image description here
I tested the change of the limit value, I found that when the value is greater than 397, it would query all table rows(Total row count is 33021). Probably it's optimized mechanism of MySQL 5.7

Sub sub-query can't find joined column in parent select

I'm running into some trouble with SQL:
Basically I'm trying to get a result set back that contains a sum of ALL questions asked to employees (grouped by company) and also add the "onetime_items" which are manually added items in a different table.
I currently have this SQL statement (I'm using MySQL):
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(emailaddress, '_', a.id)),
(
SELECT GROUP_CONCAT(items SEPARATOR '; ') as OneTimeItems
FROM (
SELECT CONCAT_WS(
': ', oi.item_name, SUM(oi.item_amount)
) items
FROM onetime_item oi
WHERE oi.company_id = e.company_id
AND oi.date BETWEEN '2015-12-01'
AND LAST_DAY('2015-12-01')
GROUP BY oi.item_name
) resulta
)
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q
LEFT JOIN employee e ON q.employee_id = e.id
WHERE 1=1
AND YEAR(created_at) = '2015'
AND MONTH(created_at) = '12'
GROUP BY e.company_id
Now I get the following error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.company_id' in 'where clause'
The dates used are dummy dates.
This column DOES exist in the table employee and the left join works ( I tried entering an id manually instead of using the column reference and it worked, I got the right result back)
Any idea as to why the reference to e.company_id fails?
Thanks to dba.stackexchange.com
link: https://dba.stackexchange.com/questions/126339/subquery-cant-find-column-from-superquerys-join
Answer by ypersillycubeᵀᴹ
Here's the answer that was posted there, hopefully someone else will profit as well from this!
The cause of the problem was identified by #Phil in the comments: in the comments:
Probably because it's nested too deep
You have 2 layers of nesting and the reference of table e cannot "see" through these 2 layers in MySQL.
Correlated inline subquery can usually be converted to derived tables and then LEFT joined to the other tables in the FROM clause but they have to be turned into uncorrelated (in MySQL. In other DBMS, you could use a LATERAL join or the similar OUTER APPLY.
A first rewrite to get the job done:
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(q.emailaddress, '_', e.id)),
dv.OneTimeItems
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q
LEFT JOIN employee e ON q.employee_id = e.id
LEFT JOIN
(
SELECT company_id,
GROUP_CONCAT(items SEPARATOR '; ') AS OneTimeItems
FROM (
SELECT oi.company_id,
CONCAT_WS(
': ', oi.item_name, SUM(oi.item_amount)
) items
FROM onetime_item oi
WHERE oi.date BETWEEN '2015-12-01'
AND LAST_DAY('2015-12-01')
GROUP BY oi.company_id, oi.item_name
) resulta
GROUP BY company_id
) AS dv
ON dv.company_id = e.company_id
WHERE 1=1
AND YEAR(q.created_at) = '2015'
AND MONTH(q.created_at) = '12'
GROUP BY e.company_id ;
Test in SQLfiddle.
Unrelated to the issue comments:
There is GROUP BY e.company_id while the select list has e.id, LEFT(e.firstname, 1), e.lastname. All these will give arbitrary result from a (more or less random) employee for each company - or even in extremely rare cases arbitrary results from 2 or 3 different employees! MySQL allowed (before 5.7) such bad use of group by that could cause erroneous results. It has been fixed in 5.7 and the default settings would reject this query.
The condition:
YEAR(created_at) = '2015' AND MONTH(created_at) = '12'
cannot make use of indexes. It's better to rewrite with either BETWEEN if the column is of DATE type of with an inclusive-exclusive range condition, which works flawlessly with any datetime type (DATE, DATETIME, TIMESTAMP) of any precision:
-- use only when the type is DATE only
date BETWEEN '2015-12-01' AND LAST_DAY('2015-12-01')
or:
-- use when the type is DATE, DATETIME or TIMESTAMP
created_at >= '2015-12-01' AND created_at < '2016-01-01'

MySQL unknown column using subquery

I receive an error when i execute this query:
SELECT
(SELECT count(cp_projeto_view.id) FROM cp_projeto_view WHERE cp_projeto_view.id_projeto = cp_projeto.id AND cp_projeto_view.id_pessoa = 467 LIMIT 1) AS qtde_visualizacoes
FROM cp_projeto
WHERE qtde_visualizacoes = 0
The error is: #1054 - Unknown column 'qtde_visualizacoes' in 'where clause'
Why qtde_visualizacoes does not exists?
Thank you very much!
You cannot use a column alias in a where clause (unless you use a subquery). MySQL has an extension where you can use having instead:
SELECT (SELECT count(cp_projeto_view.id)
FROM cp_projeto_view
WHERE cp_projeto_view.id_projeto = cp_projeto.id AND cp_projeto_view.id_pessoa = 467
LIMIT 1
) AS qtde_visualizacoes
FROM cp_projeto
HAVING qtde_visualizacoes = 0
EDIT:
The query that you probably want is more like:
select p.*
from cp_projecto p
where not exists (select 1 from cp_projeto_view pv where pv.id_projeto = p.id and pv.id_pessoa = 467)
This will return all cp_projectos that have no matching rows in cp_projeto_view. Your original query would only return rows with a single column of 0s, which doesn't make much sense. If you want the count, then do:
select count(*) as cnt
from cp_projecto p
where not exists (select 1 from cp_projeto_view pv where pv.id_projeto = p.id and pv.id_pessoa = 467)
And, for performance, create an index on cp_projeto_view(projeto, id_pessoa).

How to access outer column values in mysql subquery?

In mysql I have this query
SELECT m.*
FROM members m
RIGHT JOIN (SELECT
IF(`from member_id`=1, `to member_id`, `from member_id`) as other_id, text, `date sent`
FROM message
WHERE ((`from member_id`=1 AND `to member_id`=m.id) OR (`to member_id`=1 OR `from member_id`=m.id))
ORDER BY `date sent` DESC
LIMIT 1
) as t on 1=1
ORDER BY t.`date sent` DESC
and I'm getting this error:
Unknown column 'm.id' in 'where clause'
How can I pass the members column value in the sub query select statement?
I am creating this sub query so it evaluates to 1 row, then I want to attach it to the right of the outer select statement.
Thanks.
You need to SELECT the from member_id/to member_id values in the subquery. Then, you can join the table m on the derived table where you will have access to the values.
) as t on t.`from member_id` = 1 AND t.`to member_id` = m.id
OR t.`to member_id` = 1 OR t.`from member_id` = m.id