mysql 'Unknown column' error - mysql

What is wrong with this:
SELECT *,
GROUP_CONCAT(DISTINCT w.tag_word ORDER BY w.tag_word ASC SEPARATOR ' ') AS tags,
MATCH (title, description, tags) AGAINST ('london') AS score
FROM article G
JOIN tag_index I ON G.article_id = I.tag_target_id
JOIN tag_word W ON I.tag_word_id = W.tag_word_id
WHERE I.tag_type_id = 1 AND MATCH (title, description, tags) AGAINST ('london')
GROUP BY G.article_id
I get the error 'Unknown column 'tags' in 'field list''
UPDATE:
Thank you Parrots for pointing out that I need the HAVING clause. I still can not figure out how to implement it. I can only guess it can not be done in one query and needs to be a subquery.

Since "tags" a value you're creating using GROUP_CONCAT you need to use the having clause. Whenever you want to apply a condition to stuff after the grouping, use having. It works the same as where just after the grouping.
Where in your code example is trying to be applied to filter the results from article that will eventually be grouped to build things like "tags".

Related

Mysql - Alias in Left Outer Join giving error

I have been looking at examples in Stackoverflow but none have given me results, I have a query in which "select" there is an alias that I then need to use with a "LEFT OUTER JOIN" to compare it with the column of another table but when I execute it it generates an error of unknown column, I have been reading that a second JOIN is required but I do not know how to do it.
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(embed, '/', -2), '"', 1) as idvideo, embed, thumbnail, title,
MATCH(title, tags, category) AGAINST('peruvian food') as score
FROM peruvian_food
LEFT OUTER JOIN peruvian_food_del ON (peruvian_food.idvideo = peruvian_food_del.id_video_del)
WHERE MATCH(title, tags, category) AGAINST('peruvian food' IN BOOLEAN MODE)
AND peruvian_food_del.id_video_del IS NULL
LIMIT 30
I am getting the following error:
#1054 - Unknown column 'idvideo' in 'on clause'
The error is saying that the table peruvian_food does not contain a column named idvideo.
If we are attempting to reference the expression in the SELECT list that is assigned the alias idvideo, that reference is not allowed in the ON clause within the same SELECT. Even if a reference like that was allowed, we wouldn't qualify it with the peruvian_food. table name; there isn't a column named idvideo in that table.
Simplest workaround is to repeat the expression used in the SELECT list:
ON ( SUBSTRING_INDEX(SUBSTRING_INDEX(peruvian_food.embed, '/', -2), '"', 1) = ...
If we need to reference the idvideo alias, we would need to use an inline view, so that the column name was from a derived table.
We're just guessing at the specifiction... what it is we're trying to achieve. (I'm not even sure there was a question being asked; reads more like a status report than a question, so we're also just guessing at what question is being asked.)

How to find rows in SQL that end with the same string?

I have a question similar to the one found here: How to find rows in SQL that start with the same string (similar rows)?, and this solution works in MySQL 5.6 but not 5.7.
I have a database (t) with multiple columns, the important ones being id and filepath, and what I am trying to accomplish is retrieving all the file paths which have the same last 5 characters. The following works in MySQL5.6, and the second SELECT works fine in 5.7:
SELECT id, filepath FROM t
WHERE SUBSTRING(filepath, -5) IN
(
SELECT SUBSTRING(filepath, -5)
FROM t
GROUP BY SUBSTRING(filepath, -5)
HAVING COUNT(*) > 1
)
But when I try to run it on 5.7 I get the error
Expression #1 of HAVING clause is not in GROUP BY clause and contains
nonaggregated column 't.filepath' which is not functionally dependent on
columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by
Sample data:
id filepath
1 /Desktop/file1.txt
2 /Desktop/file2.txt
3 /Desktop/file1.txt
and I would want to return the rows with id 1 and 3. How can I fix this for MySQL5.7?
EDIT: Also can anybody point me in the right direction for the SQL to remove the duplicates? So I would want to remove the entry for id 3 but keep the entry for id 1 and 2.
Please read the mysql documentation on the subject GROUP BY and sql_mode only_full_group_by (like your error message says):
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
I think changing the inner query to this might fix the problem:
SELECT SUBSTRING(filepath, -5) AS fpath
FROM t
GROUP BY fpath
HAVING COUNT(fpath) > 1
Edit:
As to your question of why adding the "AS fpath" works:
Adding the alias "fpath" is just a clean way to do this. The point of ONLY_FULL_GROUP_BY is that each field you use in the SELECT, HAVING, or ORDER BY must also be in the GROUP BY.
So I added the fpath-alias for multiple reasons:
For performance: The query you wrote had SUBSTRING(filepath, -5) twice, which
is bad for performance. Mysql has to execute that SUBSTRING call twice,
while in my case it has to do it only once (per row).
To fix the group-by issue: You had COUNT() in the having, but "" was not in your GROUP BY statement (I'm not even sure whether that would be possible). You had to count "something", so since "fpath" was in your SELECT and in your GROUP BY, using that as your COUNT() would fix the problem.
I prefer not to put subqueries in an IN() predicate because MySQL tends to run the subquery many times.
You can write the query differently to put the subquery in the FROM clause as a derived table. That will make MySQL run the subquery just once.
SELECT id, filepath
FROM (
SELECT SUBSTRING(filepath, -5) AS suffix, COUNT(*) AS count
FROM t
GROUP BY suffix
HAVING count > 1
) AS t1
JOIN t AS t2 ON SUBSTRING(t2.filepath, -5) = t1.suffix
This is bound to do a table-scan though, so it's going to be a costly query. It can't use an index when doing a substring comparison like that.
To optimize this, you might create a virtual column with an index.
ALTER TABLE t
ADD COLUMN filepath_last VARCHAR(10) AS (SUBSTRING_INDEX(filepath, '/', -1)),
ADD KEY (filepath_last);
Then you can query it like this, and at least the subquery uses an index:
SELECT id, filepath
FROM (
SELECT filepath_last, COUNT(*) AS count
FROM t
GROUP BY filepath_last
HAVING count > 1
) AS t1
STRAIGHT_JOIN t AS t2 ON t2.filepath_last = t1.filepath_last
The solution that ended up working for me was found here: Disable ONLY_FULL_GROUP_BY
I ran SELECT ##sql_mode then SET ##sql_mode = followed by a string containing all the values returned by the first query except for only_full_group_by, but I'm still interested in how this is to be accomplished without changing the SQL settings.

How to put a CASE statement in the GROUP BY clause

I've got a table with one column that is a comma separated list of possible values. I'd like to query, grouped by each individual possible value.
As a test, I've written this query:
SELECT
`Please_identify_which_of_the_following_classroom_hardware_you_c2`,
count(`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`) as count,
`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`
FROM
`data_Copy_of_Faculty_survey_on_technology_in_the_classroom_Respo`
GROUP BY
`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`,
CASE
WHEN `Please_identify_which_of_the_following_classroom_hardware_you_c2` LIKE '%Elmo%' THEN 'Elmo'
END
(Please excuse the column names, they're auto-generated)
I know the CASE statement isn't incredibly useful at this point, but I'm just trying to get the query to run. I'm getting an 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 'THEN 'Elmo' END' at line 10
For the life of me I can't find what's wrong with the query. Any insight would be appreciated.
EDIT: I've tried with single and double quotes - same problem regardless of the quote used.
UPDATED: As Mark has pointed out, even if I get this query to parse, the results won't be what I'm looking for. I'm still curious why this doesn't parse, but the query is not the solution to my initial problem.
The reason you're seeing issues is that your GROUP BY attributes didn't align with the SELECT attributes.
As the MySql docs put it:
"SQL92 and earlier does not permit queries for which
the select list, HAVING condition, or ORDER BY list refer
to nonaggregated columns that are neither named in the GROUP BY
clause nor are functionally dependent on (uniquely determined by)
GROUP BY columns"
In other words, since the ...c2 attribute was not "functionally dependent on" your CASE ... END attribute, there was a mismatch between SELECT and GROUP BY, and thus an error.
One way to mitigate the error (and possibly make the query more readable), is to do the CASE once and then do the aggregates on the resulting relation.
SELECT c2, tec1, COUNT(tec1)
FROM
(SELECT
CASE
WHEN `Please_identify_which_of_the_following_classroom_hardware_you_c2` LIKE '%Elmo%'
THEN 'Elmo'
ELSE
`Please_identify_which_of_the_following_classroom_hardware_you_c2`
END AS c2,
`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`) AS tec1
FROM
`data_Copy_of_Faculty_survey_on_technology_in_the_classroom_Respo`) t
GROUP BY c2, tec1
Try This:
SELECT
CASE
WHEN `Please_identify_which_of_the_following_classroom_hardware_you_c2` LIKE '%Elmo%' THEN 'Elmo'
ELSE `Please_identify_which_of_the_following_classroom_hardware_you_c2`
END AS `Please_identify_which_of_the_following_classroom_hardware_you_c2`,
count(`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`) as count,
`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`
FROM
`data_Copy_of_Faculty_survey_on_technology_in_the_classroom_Respo`
GROUP BY
`_How_would_you_rate_your_overall_skill_in_using_educational_tec1`,
CASE
WHEN `Please_identify_which_of_the_following_classroom_hardware_you_c2` LIKE '%Elmo%' THEN 'Elmo'
ELSE `Please_identify_which_of_the_following_classroom_hardware_you_c2`
END

Concatenation is not working in select query

We are fetching list of ordered products from database including join with order table.
We want to list all orders with how many quantity of products order in each order on the basis of passed product ids. We also want to display customer name which was placed the order. So, as per our knowledge we have created an query to get items as:
SELECT
`main_table`.*,
`order`.*,
SUM(main_table.qty_ordered - main_table.qty_canceled) AS `custom_qty`,
SUM(main_table.row_total) AS `custom_row_total`,
SUM(main_table.tax_amount) AS `tax_amount`,
SUM(main_table.hidden_tax_amount) AS `hidden_tax_amount`,
SUM(main_table.discount_amount) AS `discount_amount`,
CONCAT(order.customer_firstname, ' ' ,order.customer_middlename, ' ', order.customer_lastname) AS full_name
FROM `sales_flat_order_item` AS `main_table`
INNER JOIN `sales_flat_order` AS `order` ON main_table.order_id=order.entity_id
WHERE (((((main_table.product_id = '902') OR (main_table.product_id = '903') OR (main_table.product_id = '904'))))) AND (main_table.store_id = '1') AND (CONCAT(order.customer_firstname, order.customer_middlename, order.customer_lastname) like '%rag%')
GROUP BY `main_table`.`sku`
All the aggregate functions used in above query working fine except concat(). Every time we will get the value of full_name column as NULL even we have name the corresponding concatenated columns.
Please any one helps me to figure out why this is not working. Are we doing something wrong in the above query?
Thanks in advance.
As CONCAT() returns NULL if any argument is NULL I'm guessing maybe one of the three arguments is NULL?
Try using the CONCAT_WS() function instead (as you use separators anyway) which skips null values.
CONCAT_WS(' ', order.customer_firstname, order.customer_middlename, order.customer_lastname) AS full_name
See the documentation for more information.
On a side note: you might want to look into how you can use table aliases to shorten the query text and make it more readable.
Are you sure EVERY column has an value? (Middlename?)
The MYSQL manual says:
SELECT CONCAT('My', NULL, 'QL')
-> NULL

Ruby on Rails - Find by SQL adding apostrophes

I have wrote a SQL query which I am using in my model, provided below:
Tag.find_by_sql(["SELECT tags.id, tags.name, count(*) AS count FROM tags
INNER JOIN taggings ON tags.id = taggings.tag_id
WHERE
(taggings.taggable_type = 'Discussion' AND taggings.taggable_id IN (SELECT id FROM `discussions` WHERE discussions.group_id = ?))
GROUP BY tag_id ORDER BY ? LIMIT ?;", self.id, self.id, self.id, self.id, order, limit])
This works fine and pulls out the required tags. However the tags do not order correctly. I noticed in the server console that the query has apostrophes around the order statement like so:
ORDER BY 'count desc'
When I remove the apostrophes, like so:
ORDER BY count desc
and run the query manually it pulls the tags in the correct order. Is there a way to stop the apostrophes being added to the query?
Cheers
Tony
the reason is because you have parameterized the column name
ORDER BY ?
The value you have pass has been sanitized that's why it becomes 'count desc'.
You cannot pass column names and tables name by design. The only way is to concatenate the column name within the string.