I'm trying to run a query on the result set of another query but getting errors which I cannot understand. I'm sure it's something small but I'm somehow missing it. This is the query:
SELECT
RLID,
NAME,
GROUP_CONCAT(SUBQUERY.Items SEPARATOR ', ') AS Items
FROM
(
SELECT
`rel_menu_item`.`ID` AS `RLID`,
`menu`.`Name` AS `Menu_Name`,
`item`.`Name` AS `Items`
FROM
`rel_menu_item`
JOIN
`menu` ON `menu`.`ID` = `rel_menu_item`.`Menu_ID`
JOIN
`item` ON `item`.`ID` = `rel_menu_item`.`Item_ID`
) AS SUBQUERY
GROUP BY
SUBQUERY.Name
Errors:
3 errors were found during analysis.
An expression was expected. (near "(" at position 90)
Unexpected token. (near "(" at position 90)
This type of clause was previously parsed. (near "SELECT" at position 95)
I found the errors. Here is the correct query:
SELECT
SUBQUERY.RLID,
SUBQUERY.Menu_Name,
GROUP_CONCAT(SUBQUERY.Items SEPARATOR ', ') AS Items
FROM
(
SELECT
rel_menu_item.ID AS RLID,
menu.Name AS Menu_Name,
item.Name AS Items
FROM
rel_menu_item
JOIN
menu ON menu.ID = rel_menu_item.Menu_ID
JOIN
item ON item.ID = rel_menu_item.Item_ID
) AS SUBQUERY
GROUP BY
SUBQUERY.Menu_Name
You should be writing this query without a subquery at all:
SELECT m.Id as RLID, m.Name as Menu_Name
GROUP_CONCAT(i.name SEPARATOR ', ') AS Items
FROM rel_menu_item rmi JOIN
menu m
ON m.ID = rmi.Menu_ID JOIN
item i
ON i.ID = rmi.Item_ID
GROUP BY m.Id, m.Name;
Notes:
The subquery is not needed.
Table aliases make the query easier to write and to read.
It is better to use the column from the primary key table menu.id rather than from the references foreign key. It doesn't really make a difference with inner joins, but it does make a difference with outer joins; hence, it is a bad practice.
You should include all non-aggregated columns in the GROUP BY.
Related
This question already has answers here:
Unknown Column In Where Clause
(16 answers)
Closed 3 years ago.
I am am trying to use a WHERE clause based on a scalar subquery result. The query executes correctly without the WHERE clause. With the WHERE clause I get Error Code: 1054. Unknown column 'available_services' in 'where clause'.
How can I achieve filtering based on the result of the subquery?
Also since subqueries can be pretty inefficient any suggestions of how to improve the query would be useful.
SELECT DISTINCT
`suppliers`.`id` AS `supplier_id`,
`suppliers`.`name`,
`suppliers`.`code`,
`suppliers`.`notes`,
(
SELECT GROUP_CONCAT(
`services`.`name`
ORDER BY `services`.`order`
SEPARATOR ', '
)
FROM `supplier_services`
LEFT JOIN `services`
ON `supplier_services`.`service_id` = `services`.`id`
WHERE
`supplier_services`.`service_id` = `services`.`id`
AND `supplier_services`.`supplier_id` = `suppliers`.`id`
GROUP BY `supplier_services`.`supplier_id`
) AS `available_services`
FROM `suppliers`
WHERE `available_services` like '%pet%'
GROUP BY `suppliers`.`id`
Hi you should as variable in query if would you like to reach subquerys result
SELECT DISTINCT
`suppliers`.`id` AS `supplier_id`,
`suppliers`.`name`,
`suppliers`.`code`,
`suppliers`.`notes`,
#available_services := (
SELECT GROUP_CONCAT(
`services`.`name`
ORDER BY `services`.`order`
SEPARATOR ', '
)
FROM `supplier_services`
LEFT JOIN `services`
ON `supplier_services`.`service_id` = `services`.`id`
WHERE
`supplier_services`.`service_id` = `services`.`id`
AND `supplier_services`.`supplier_id` = `suppliers`.`id`
GROUP BY `supplier_services`.`supplier_id`
) AS `available_services_as_column_view`
FROM `suppliers`
WHERE #available_services like '%pet%'
GROUP BY `suppliers`.`id`
In case anyone comes across this and has a similar problem the reason (as pointed out by Nico in the comments) is that while you can use table aliases in where clauses you can not use field aliases. You can however have field aliases in HAVING clauses.
The solution is to use
GROUP BY `suppliers`.`id`
HAVING `available_services` like '%pet%'
instead of
WHERE `available_services` like '%pet%'
GROUP BY `suppliers`.`id`
Alternatively the alias in the where clause could be replaced with the subquery again but that may be inefficient or it may be cached by mysql and not be an issue, you would need to check that carefully if you use that solution.
This is the query I use to fetch and display data for my profiles pages. Each category has its own tables because they are constantly being added to by users. I'm new to MYSQL and must be doing something wrong because the query takes 0.7 seconds for one provider (id=56), but 27 seconds (!!!) for provider with id=164. I thought they both had about the same amount of data tied to them, so I can't figure out why the one is taking so long.
Since I'm new to MySQL, I don't know if my long query is normal, or if there's a shorter, easier way to do it that I'm not realizing. However, it works just fine on all my providers except the one.
I did an EXPLAIN on both and the only difference was that the "Type" listed for the slow query had 4 "ALL"s and the faster one only had 2, same for the column that says "Extra," - the slow query had 4 that said "Using where; Using join buffer (Block Nested Loop)" and the fast had 2. I'm not sure what those mean, but that's what I'm trying to figure out.
Appreciate your help!
Changing/removing Concat and Distinct doesn't help.
SELECT `providers`.`id`,
`providers`.`provider_first_name`,
`providers`.`provider_last_name`,
`providers`.`p_date_added`,
`degrees`.`degree_type`,
GROUP_CONCAT(DISTINCT `degrees`.`degree_type` SEPARATOR ', ') AS
all_degrees,
`specialties`.`specialty`,
GROUP_CONCAT(DISTINCT `specialties`.`specialty` SEPARATOR ', ') AS
all_specialties,
`locations`.`city`, `locations`.`state`,
GROUP_CONCAT(DISTINCT CONCAT(`locations`.`city`, ', ',
`locations`.`state`)
ORDER BY `locations`.`city`
SEPARATOR '<br>'
) AS all_locations,
`practices`.`practice_name`,
GROUP_CONCAT(DISTINCT `practices`.`practice_name` SEPARATOR '<br>')
AS all_practices,
`links`.`link`,
GROUP_CONCAT(DISTINCT `links`.`link` SEPARATOR '<br>') AS
all_links,
`conditions`.`condition_name`,
GROUP_CONCAT(DISTINCT `conditions`.`condition_name` SEPARATOR ', ')
AS all_conditions,
`reviews`.`review`, `reviews`.`star_rating`,
`reviews`.`r_date_added`,
AVG(`reviews`.`star_rating`) AS rating
FROM `providers`
LEFT JOIN `degrees` ON `providers`.`id` = `degrees`.`prov_id`
LEFT JOIN `specialties` ON `providers`.`id` =
`specialties`.`prov_id`
LEFT JOIN `locations` ON `providers`.`id` = `locations`.`prov_id`
LEFT JOIN `practices` ON `providers`.`id` = `practices`.`prov_id`
LEFT JOIN `links` ON `providers`.`id` = `links`.`prov_id`
LEFT JOIN `conditions` ON `providers`.`id` = `conditions`.`prov_id`
LEFT JOIN `reviews` ON `providers`.`id` = `reviews`.`prov_id`
WHERE `id`= {$providerid}
GROUP BY `id`
Explode-Implode -- The JOINs explode the number of rows, then the GROUP BY implodes down to very few (apparently only one).
To avoid that, move the LEFT JOINs into the SELECT. For example:
SELECT ...
GROUP_CONCAT(DISTINCT `degrees`.`degree_type` SEPARATOR ', ') AS all_degrees,
...
LEFT JOIN `degrees` ON `providers`.`id` = `degrees`.`prov_id`
...
-->
SELECT ...
( SELECT GROUP_CONCAT(DISTINCT `degree_type` SEPARATOR ', ')
FROM `degrees`
WHERE `providers`.`id` = `prov_id`
) AS all_degrees,
...
And the final GROUP BY id can be removed.
At this point, the DISTINCT is probably redundant; try removing it.
EXPLAIN query
ALL means it is equivalent to full scan of table. To prevent this is add index on your table. Add index on a column which you normally use on searching or connecting certain data.
ROWS represents the cardinality of records whithin the indexed records. Smaller the number the better.
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
Reading more about EXPLAIN really helps.
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'
I have the following query:
SELECT
issue.`sequence` AS issue_sequence,
issue.`description` AS issue_description,
GROUP_CONCAT(DISTINCT(issue_category.`name`) SEPARATOR ', ') AS issue_category_name,
GROUP_CONCAT(DISTINCT(approach.`name`) SEPARATOR ', ') AS approach_name,
issue_approach.`issue_id` AS issue_approach_issue_id,
issue_approach.`approach_id` AS issue_approach_approach_id
FROM
`approach` approach
INNER JOIN `issue_approach` issue_approach ON approach.`id` = issue_approach.`approach_id`
INNER JOIN `issue` issue ON issue_approach.`issue_id` = issue.`id`
INNER JOIN `project` project ON issue.`project` = project.`id`
INNER JOIN `tenant` tenant ON project.`tenant_id` = tenant.`id`
INNER JOIN `issue_category` issue_category ON project.`id` = issue_category.`project`
INNER JOIN `user` user ON tenant.`id` = user.`tenant_id`
WHERE user.id = 1 AND project.id = 1
GROUP BY issue_category_name
ORDER BY issue_category.`name`, issue.`sequence`
I am having a problem with this line:
GROUP BY issue_category_name
Apparently, MySQL can't seem to Group by the alias for by GROUP_CONCAT result.
I am not really an expert with SQL, but is there a way I can group using the result of GROUP_CONCAT?
Sample data;
Categories: Network, Servers
Issue Id: 1
Description: Some description
Approaches: Some approaches to resolve the issue.
Basically, an issue can belong to one or many categories. I am concatenating categories for each issue. What i want to do is group the results by the result of concatenation of categories. So for example group issues whose categories are Network,Servers.
Thanks.
Im not a MySQL user, but change your group by to
Group By GROUP_CONCAT(DISTINCT(issue_category.`name`) SEPARATOR ', ')
With reference to SQL EXECUTION ORDER, the reason why this will not work is because the select statement is the last statement to be executed so that sql engine will not be knowing your column alias while grouping the records as GROUP BY occurs before SELECT. So that as Charles Bretana's answer suggests, put
Group By GROUP_CONCAT(DISTINCT(issue_category.`name`) SEPARATOR ', ')
in your group by clause. It will work fine then.
Hope this helps you.
I have this query:
SELECT
course_category.id AS languageId,
course_category.code AS languageCode,
course_category.name AS languageName,
(
SELECT
SUM(gradebook_result.score)
FROM
gradebook_result
JOIN
gradebook_evaluation ON gradebook_evaluation.id=gradebook_result.evaluation_id
JOIN
gradebook_category ON gradebook_category.id=gradebook_evaluation.category_id
WHERE
gradebook_category.course_code=course_category.code
) AS languageWordsTranslated
FROM
course_category
WHERE
course_category.code != 'GEN'
ORDER BY
name
ASC
The problem occurs inside the nested SELECT where I get an error referencing the course_category table from within the SELECT on line:
WHERE
gradebook_category.course_code=course_category.code
Giving error:
Unknown column 'course_category.code' in 'where clause'
I have done this query before with other projects the only difference is that this one has joins within it. Any ideas?
EDIT: I removed the joins and hardcoded:
WHERE
course_category.code = 'ARA'
Seems like the joins mess it up, any way to fix that??
Try to do it a bit different way, using subquery and joining to it:
SELECT
course_category.id AS languageId,
course_category.code AS languageCode,
course_category.name AS languageName,
t.total AS languageWordsTranslated
FROM
course_category
JOIN (
SELECT gradebook_category.course_code, SUM(gradebook_result.score) as total
FROM gradebook_result
JOIN gradebook_evaluation ON gradebook_evaluation.id=gradebook_result.evaluation_id
JOIN gradebook_category ON gradebook_category.id=gradebook_evaluation.category_id
GROUP BY gradebook_category.course_code
) t ON t.course_code = course_category.code
WHERE
course_category.code != 'GEN'
ORDER BY
name
ASC