select with MD5 + CONCAT using where - mysql

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.

Related

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.

Expression in mysql order by not being evaluated

This problem began when I was trying to set the order by column from a bound statement.
This is not working for me:
select * from testTable order by field(?, 'userid','name') asc;
The field() function is not being evaluated for some reason.
After further investigation I found that this also does not work:
select * from testTable order by (1+1) asc
Are these both the same problem? And what is the solution?
I'm just guessing, but I think it is plausible that you can't use ORDER BY #ColumnIndex (For example ORDER BY 2) when you are using SELECT *.
Try specifying all the columns you are willing to select, or use column names in the order by clause.

Use the result of the MySQL SELECT query as a WHERE condition in the same query

I'm trying to do this query:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" >= 1
But I'm getting the result of NULL. What I should be getting is 99, as the range of peg_num is 00 to 99.
The value checked against "indicator" should actually be a user input, so I want it to be versatile. But, it does give me the correct result if I flip the equality around:
SELECT MAX(`peg_num`)
AS "indicator"
FROM `list`
WHERE `list_id` = 1
AND "indicator" <= 1
Why would it do this?
Edit:
As suggested, I'm using the HAVING clause... but I just ditched the alias for now anyway:
SELECT MAX(`peg_num`) AS "indicator"
FROM `list`
GROUP BY `list_id`
HAVING MAX(`peg_num`) <= 40
Still very stubborn. It gives me 99 now no matter the value in the having clause, regardless of the inequality.
Edit2:
As a clarification:
What I want to happen is the query select the largest value in the range of peg_num, but only if it is larger than a user-given input. So, the max in this case is 99. If the user wants to select a number like 101, he/she can't because it's not in the range.
Because of double quotes, "indicator" in WHERE clause is interpreted as a string. Thus, it evaluates to 0, meaning it is always less than 1. Column names must be escaped in backticks.
Keep in mind that WHERE clause is executed before SELECT an hence aliases defined in SELECT can not be used in WHERE clause.
SELECT MAX(`peg_num`) AS `indicator`
FROM `list`
WHERE `list_id` = 1
HAVING `indicator` >= 1
You might want to check out the link on the answer to another Stack question about not being allowed to use alias in where clause:
Can you use an alias in the WHERE clause in mysql?
Paul Dixon cites:
It is not allowable to refer to a column alias in a WHERE clause,
because the column value might not yet be determined when the WHERE
clause is executed. See Section B.1.5.4, “Problems with Column
Aliases”.
Also:
Standard SQL disallows references to column aliases in a WHERE clause.
The behavior you're seeing in your query when you swap the '<=' and '>=' operators, results from the query comparing the string/varchar 'indicator' to the number 1.
That's why you see the correct answer..when ('indicator' >= 1) which is true, and null when ('indicator' <= 1) which is false.
I don't know, but I'm amazed either of them work at all. WHERE works serially on fields belonging to individual records and I wouldn't expect it to work on "indicator" since that's a group calculation.
Does this do what you want?
SELECT max(`peg_num` ) AS "indicator"
FROM actions
WHERE `peg_num` >=1
AND `list_id` <= 1
WHERE happens before SELECT, and don't know what's "indicator".
You should use HAVING (with GROUP BY) to use the SELECT fields
Here's the documentation for syntax
http://dev.mysql.com/doc/refman/5.5/en/select.html
Something like this is the idea
SELECT MAX(peg_num) AS indicator
FROM list
WHERE list_id = 1
HAVING indicator <= 1
I can't test it and i never met Mysql so just the idea,
You should use HAVING
No quotes in HAVING condition
This must work:
SELECT MAX(peg_num)
AS indicator
FROM list
WHERE list_id = 1
HAVING indicator >= 1
I completely re-invented my query and it worked. The thing is, I had to use a nested query (and I wanted to not do that as much as possible, my professor had always discouraged it).
Anyway, here it is:
SELECT IF(`key` < 900, `key`, null) `key`
FROM (
(
SELECT MAX( `peg_num` ) AS `key`
FROM `list`
WHERE `list_id` =1
) AS `derivedTable`
)

Can we use aliased field to use in ORDER BY clause in MySQL?

Can we use aliased field name in ORDER BY clause?
For example:
SELECT id, name AS firstname
FROM users
ORDER BY firstname
Is it possible? When I tried this it errored out.
An alias can be used in a query select list to give a column a
different name. You can use the alias in GROUP BY, ORDER BY, or HAVING
clauses to refer to the column.
Check here.
Try with this one, I have added back-ticks to column name and table Because name is the reserved word :
SELECT `id`, `name` AS firstname
FROM `users`
ORDER BY firstname
Yes, you can certainly use column aliases in your "order by" clause.
You can verify it works with the built-in mySql "user" table:
select User as name,Host from user order by name;
If it "errored out", then something else must have been wrong with your query. Please cut/paste the exact error message.
You cannot use alias in GROUP BY Clause in MS SQL SERVER
In order to tell of you can use aliases in certain clauses, check the order in which SQL procceses the the queries and it is as follows:
-from
-where
-group by
-having
-order by

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.