I am trying to perform a MySql select with many conditions, but want to perform a string comparison on a column that is an integer datatype. Is there a way to do this without having to cast the column to a varchar on every single condition within the where clause?
SELECT COUNT(*)
FROM tablename
WHERE CAST(col1 AS VARCHAR(10)) NOT LIKE '558%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '566%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '567%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '568%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '569%'
AND CAST(col1 AS VARCHAR(10)) NOT LIKE '579%';
Before you ask why I'm not doing integer comparison: Instead of casting to a varchar, I could also just use plain integer comparison, but then I still would have to perform a math operation, i.e. col1/100000, for every item in the where clause, which leads to the same problem as to how can I simplify the statement?
You can use subquery:
SELECT COUNT(*)
FROM
(
SELECT CAST(col1 AS VARCHAR(10)) AS col1
FROM tablename
) AS t
WHERE t.col1 NOT LIKE '558%'
...
The direct answer to your question is that casts are implicit in MySQL, so col1 NOT LIKE '556%' is equivalent to what you're doing.
It's always best to avoid using functions that reference column names in the WHERE clause, because that disables the use of indexes and requires every row in the table to be evaluated. I assume that you are aware of that, since you mentioned you would still "have to do a math operation."
If you actually know the scale of the number then a more correct query would be...
WHERE (col1 < 556 * 100000 OR col1 > 556 * 100000)
AND ...
If that's logically correct based on what you are doing, then it's a better solution, because the optimizer will do that math only once, converting those into constants, rather than doing it once per row.
Also note that if you do know the scale of the numbers, then LIKE '556______' is also more logically valid than using % since _ matches exactly one character, where % matches zero or more.
Related
I need to calculate the sum of one column(col2) , but the column has both numbers and text. How do I exclude the text alone before I use sum()?
The table has around 1 million rows, so is there any way other than replacing the text first?
My query will be :
Select col1,sum(col2) from t1 group by col1,col2
Thanks in advance
You can use regexp to filter the column:
Select col1,sum(col2) from t1 WHERE col2 REGEXP '^[0-9]+$' group by col1,col2
You could use MySQL built in REGEXP function.
to learn more visit : https://dev.mysql.com/doc/refman/5.1/en/regexp.html
Or another way is using CAST or CONVERT function
to learn in detail : https://dev.mysql.com/doc/refman/5.0/en/cast-functions.html
Hope this is helpful
Assuming you mean the number is at the beginning of the tex, the easiest way is simply to use implicit conversion:
Select col1, sum(col2 + 0)
from t1
group by col1, col2;
If col2 starts with a non-numeric character, then MySQL will return 0. Otherwise, it will convert the leading numeric characters to a number.
Note that your query doesn't really make sense, because you are aggregating by col2 as well as including it in the group by. I suspect you really want:
Select col1, sum(col2 + 0)
from t1
group by col1;
This case is similar to: S.O Question; mySQL returns all rows when field=0, and the Accepted answer was a very simple trick, to souround the ZERO with single quotes
FROM:
SELECT * FROM table WHERE email=0
TO:
SELECT * FROM table WHERE email='0'
However, my case is slightly different in that my Query is something like:
SELECT * FROM table WHERE email=(
SELECT my_column_value FROM myTable WHERE my_column_value=0 AND user_id =15 LIMIT 1 )
Which in a sense, becomes like simply saying: SELECT * FROM table WHERE email=0, but now with a Second Query.
PLEASE NOTE: It is a MUST that I use the SECOND QUERY.
When I tried: SELECT * FROM table WHERE email='( SELECT my_column_value FROM myTable WHERE my_column_value=0 LIMIT 1 )' (Notice the Single Quotes on the second query)
MySql SCREAMED Errors near '(.
How can this be achieved
Any Suggestion is highly honored
EDIT1: For a visual perspective of the Query
See the STEN_TB here: http://snag.gy/Rq8dq.jpg
Now, the main aim is to get the sten_h where rawscore_h = 0;
The CURRENT QUERY as a whole.
SELECT sten_h
FROM sten_tb
WHERE rawscore_h = (
SELECT `for_print_stens_rowscore`
FROM `for_print_stens_tb`
WHERE `for_print_stens_student_id` =3
AND `for_print_stens_factor_name` = 'Factor H' )
The result of the Second Query can be any number including ZERO.
Any number from >=1 Works and returns a single corresponding value from sten_h. Only =0 does not Work, it returns all rows
That's the issue.
CORRECT ANSWER OR SOLUTION FOR THIS
Just in case someone ends up in this paradox, the Accepted answer has it all.
SEE STEN_TB: http://snag.gy/Rq8dq.jpg
SEE The desired Query result here: http://snag.gy/wa4yA.jpg
I believe your issue is with implicit datatype conversions. You can make those datatype conversions explicit, to gain control.
(The "trick" with wrapping a literal 0 in single quotes, that makes the literal a string literal, rather than a numeric.)
In the more general case, you can use a CAST or CONVERT function to explicitly specify a datatype conversion. You can use an expression in place of a column name, wherever you need to...
For example, to get the value returned by my_column_value to match the datatype of the email column, assuming email is character type, something like:
... email = (SELECT CONVERT(my_column_value,CHAR(255)) FROM myTable WHERE ...
or, to get the a literal integer value to be a string value:
... FROM myTable WHERE my_column_value = CONVERT(0,CHAR(30)) ...
If email and my_column_value are just indicating true or false then they should almost certainly be both BIT NOT NULL or other two-value type that your schema uses for booleans. (Your ORM may use a particular one.) Casting is frequently a hack made necessary by a poor design.
If it should be a particular user then you shouldn't use LIMIT because tables are unordered and that doesn't return a particular user. Explain in your question what your query is supposed to return including exactly what you mean by "15th".
(Having all those similar columns is bad design: rawscore_a, sten_a, rawscore_b, sten_b,... . Use a table with two columns: rawscore, sten.)
I have a field number of type varchar. Even though it is of type varchar, it stores integer values with optional leading zeros. A sort orders them lexicographically ("42" comes before "9"). How can I order by numeric values ("9" to come before "42")?
Currently I use the query:
SELECT * FROM table ORDER BY number ASC
Try this
SELECT * FROM table_name ORDER BY CAST(field_name as SIGNED INTEGER) ASC
There are a few ways to do this:
Store them as numeric values rather than strings. You've already discounted that as you want to keep strings like 00100 intact with the leading zeros.
Order by the strings cast as numeric. This will work but be aware that it's a performance killer for decent sized databases. Per-row functions don't really scale well.
Add a third column which is the numeric equivalent of the string and index on that. Then use an insert/update trigger to ensure it's set correctly whenever the string column changes.
Since the vast majority of databases are read far more often than written, this third option above amortises the cost of the calculation (done at insert/update) over all selects. Your selects will be blindingly fast since they use the numeric column to order (and no per-row functions).
Your inserts and updates will be slower but that's the price you pay and, to be honest, it's well worth paying.
The use of the trigger maintains the ACID properties of the table since the two columns are kept in step. And it's a well-known idiom that you can usually trade off space for time in most performance optimisations.
We've used this "trick" in many situations, such as storing lower-cased versions of surnames alongside the originals (instead of using something like tolower), lengths of identifying strings to find all users with 7-character ones (instead of using len) and so on.
Keep in mind that it's okay to revert from third normal form for performance provided you understand (and mitigate) the consequences.
Actually i've found something interesting:
SELECT * FROM mytable ORDER BY LPAD(LOWER(mycol), 10,0) DESC
This allows you to order the field like:
1
2
3
10
A
A1
B2
10A
111
SELECT * FROM table ORDER BY number + 0
Trick I just learned. Add '+0' to the varchar field order clause:
SELECT * FROM table ORDER BY number+0 ASC
I now see this answer above. I am wondering if this is typecasting the field and an integer. I have not compared performance. Working great.
For a table with values like Er353, ER 280, ER 30, ER36
default sort will give
ER280
ER30
ER353
ER36
SELECT fieldname, SUBSTRING(fieldname, 1, 2) AS bcd,
CONVERT(SUBSTRING(fieldname, 3, 9), UNSIGNED INTEGER) AS num
FROM table_name
ORDER BY bcd, num;
the results will be in this order
ER30
ER36
ER280
ER353
you can get order by according to your requirement my using following sql query
SELECT * FROM mytable ORDER BY ABS(mycol)
given a column username containing VARCHAR's like these:
username1
username10
username100
one could do:
SELECT username,
CONVERT(REPLACE(username, 'username', ''), UNSIGNED INTEGER) AS N
FROM users u
WHERE username LIKE 'username%'
ORDER BY N;
it is not cheap, but does the job.
SELECT * FROM table ORDER BY number ASC
Should display what you want it to display.. looks like you're sorting it by id or number is not defined as integer at the moment.
MySQL ORDER BY Sorting alphanumeric on correct order
example:
SELECT `alphanumericCol` FROM `tableName` ORDER BY
SUBSTR(`alphanumericCol` FROM 1 FOR 1),
LPAD(lower(`alphanumericCol`), 10,0) ASC
output:
0
1
2
11
21
100
101
102
104
S-104A
S-105
S-107
S-111
Another option to keep numerics at a top, then order by alpha.
IF(name + 0, name + 0, 9999999), name
Rough and ready: order by 1*field_name
I ran a query that resulted in the string '1,2,3,4'.
How can I run a second query that treats that string as a list of numbers. So I'll be able to do:
select * from tbl where name not in (1,2,3,4)
I would like an answer in pure MySQL.
Well first of all, this usually means that your database structure is not good; you should normalize your database.
However, you can do what you want, with the FIND_IN_SET function:
SELECT * FROM tbl WHERE NOT FIND_IN_SET(name, '1,2,3,4')
Use FIND_IN_SET:
select * from tbl where FIND_IN_SET(name, '1,2,3,4') = 0
Like the other answer, I would also recommend normalizing your database if at all possible. This query could be slow as it will require a scan of the table. Even if there is an index on name this query won't be able to use it efficiently.
I'm run this query:
SELECT id,like - dislike as result
FROM mytable
Where the column like and dislike are unsigned integer. If the column dislike is greater than like mysql return number like 18446744073709551596, so seem that mysql treat this like unsigned and can't return negative number but continue the computation from a sort of MAX_UNSIGNED_INT. How can I have the correct result
Try casting the two values (or maybe only on of them)
SELECT id, convert(like, SIGNED ) - convert(dislike, SIGNED ) as result
FROM mytable
or only the result
SELECT id, convert(like - dislike, SIGNED ) as result
FROM mytable
In the first way you can get type overflow! The Second way is better, but I'm not sure it works with mysql.
You could try casting them as Int:
SELECT id, CAST(like AS INT) - CAST(dislike AS INT) as result FROM mytable