Why Can't I Use Defined Variable in Where Clause - mysql

My query is:
SELECT
offer,
(SELECT
AVG(offer)
FROM
project_bids
) as var1
FROM
`project_bids`
WHERE
offer > var1
It causes "#1054 - Unknown column 'var1' in 'where clause'" error. Can anybody expalain why gives that error ? (i know working sql but i want to learn why it fails)

The sequence of execution of clauses of a SELECT statement is mentioned here:
http://blog.sqlauthority.com/2007/06/14/sql-server-easy-sequence-of-select-from-join-where-group-by-having-order-by/
Alias of an column can not be used in any clause except the last clause "ORDER BY".

you would have to move "var1" out of the where and put in it to a having statement
the where statement does not have access to columns created in the select statement

Write it as below:
SELECT offer, (SELECT AVG(offer) FROM project_bids) as var1 FROM project_bids WHERE offer > (SELECT AVG(offer) FROM project_bids)

Related

Is it possible to run a MySQL query based on the result of an alias?

SELECT CASE
WHEN col1_alias='' THEN 'empty value'
ELSE 'has value'
END AS result,
(/* a complicated mysql SELECT statement */) AS col_alias
FROM my_table;
The above MySQL query gives me Unknown column 'col_alias' in 'field list' error.
Is it possible to generate the result column based on the value of col?
I don't want to write the complicated MySQL SELECT statement for the second time.
============================== EDIT ================================
Sorry, I forgot to mention that my real situation is more complicated than the query pasted above.
My real query contains JOIN and GROUP BY. Like this:
SELECT
my_table.id AS id,
CASE
WHEN col1_alias='' THEN 'empty value'
ELSE 'has value'
END AS result,
(/* a complicated mysql SELECT statement */) AS col_alias,
another_table.name AS name
FROM my_table
LEFT JOIN another_table
ON
`my_table`.`id` = `another_table`.`id`
GROUP BY
`another_table`.`name`;
Is it possible to avoid Unknown column 'col_alias' in 'field list' in this situation?
I think I might have to write part of the query results to a temporary table. Then write a second query that runs against the original and the temporary table.
However, I still wish that I can use only one query to accomplish the goal.

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.

Can not Access Aliased Columns in Select Statement (MySQL)

I have a problem with Aliased Columns in MySQL!
My Query:
SELECT Price AS Pr, (Pr*10/100) FROM MyTable;
MySQL WorkBench Error: UnKnown Column 'Pr' in Field List !!!
I tested my query in W3Schools with no error !
I tested my query in W3Schools with no error!
This doesn't prove that your query is valid.
You can only use aliases in GROUP BY, ORDER BY or HAVING clauses. Your usage variant is not allowed, because the value of alias is not known when MySQL is selecting the 2-nd column.
I've got a suspicion that W3Schools uses MS Access to run user queries, and MS Access does allow such atrocity as referencing column aliases in a SELECT clause that are defined in the same SELECT clause.
The standard doesn't allow this and MySQL does follow standard in this particular case.
As for solution to your problem, I can see two options.
The more generic solution, which would run in probably any SQL product, would be to use a derived table:
SELECT
Pr,
(Pr * 10 / 100) AS SomethingElse
FROM
(
SELECT
SomeComplexExpression AS Pr
FROM MyTable
) AS sub
;
The other option would be to use a variable, which is MySQL-specific:
SELECT
#Pr := SomeComplexExpression AS Pr,
(#Pr * 10 / 100) AS SomethingElse
FROM MyTable
;
Finally, if you need to test/demonstrate if something can/cannot work in MySQL, I'd recommend using SQL Fiddle.

select with MD5 + CONCAT using where

Where problem ?
select work fine.. when check in where - give error
Unknown column 'confirm' in 'where clause'
SELECT
users_id, MD5(CONCAT(users_pass, users_email)) AS confirm
FROM
(users_items)
WHERE users_active = 0
AND confirm = '39a5eccb97f63a2bb649ddd95c5a3ba7'
LIMIT 1
because confirm is an alias.
You can't use an alias in the where clause in the same level of query.
You have to do
where xxx
and MD5(CONCAT(users_pass, users_email)) = '39a5eccb97f63a2bb649ddd95c5a3ba7'
Or, as stated by Vatev, you can use an alias in an HAVING clause. But use an HAVING clause may have an impact on performance.
Cause where filters your query (trying to use indexes, for example), and the HAVING clause is filtering on these filtered datas.
where xxx
HAVING confirm = '39a5eccb97f63a2bb649ddd95c5a3ba7'
SELECT
users_id,
MD5(CONCAT(users_pass, users_email)) AS confirm
FROM
(users_items)
WHERE
users_active = 0
AND MD5(CONCAT(users_pass, users_email)) = '39a5eccb97f63a2bb649ddd95c5a3ba7'
LIMIT 1
As for HAVING clause, AFAIK, it is used only with GROUP BY.
Added:
"In general, clauses used must be given in exactly the order shown in the syntax description. For example, a HAVING clause must come after any GROUP BY clause and before any ORDER BY clause."
"Do not use HAVING for items that should be in the WHERE clause. For example, do not write the following:
SELECT col_name FROM tbl_name HAVING col_name > 0;
Write this instead:
SELECT col_name FROM tbl_name WHERE col_name > 0;"
These are quotations from http://dev.mysql.com/doc/refman/5.0/en/select.html.

having condition on result of a subquery in mysql

i am trying to run a query like this
SELECT a, b , c, (SELECT INNULL(x,y)) as mycol WHERE mycol < 400 ;
BUt it gives the error
#1054 - Unknown column 'mycol' in 'where clause'
What would be the right way to do this?
Thanks.
It's so in MS SQL, so I assume, that the same problem is in MySQL.
Try to change WHERE to HAVING. WHERE clause doesn't see your renamed columns.
HAVING is working the same way as WHERE, like (mycol < 400 AND a > 5).
GROUP BY should be before HAVING.
Check the examples in the link.
http://www.databasejournal.com/features/mysql/article.php/3469351/The-HAVING-and-GROUP-BY-SQL-clauses.htm
#hgulyan I doubt your answer. It is not the renaming that prevents one from using WHERE clause, rather it is the subquery. So lets say I have a query:
SELECT id as ID FROM user WHERE ID > 10;
This is going to work perfectly fine.
Now lets say I have one more query:
SELECT name, (SELECT id FROM user_detail WHERE user_id = 20) as ID FROM user WHERE ID > 19;
This particular query will produce error as:
Unknown column ID
So, it's about using subquery and column aliases and not just column aliases.
Thus in this case you will have to use HAVING instead of WHERE.