IF... ELSE in WHERE clause MySQL - mysql

I'm trying to use a IF...ELSE function in a MySQL WHERE statement without success.
I have this query:
SELECT id
FROM mytable
WHERE restrcountry NOT LIKE '%*nl*%'
AND (IF languages LIKE '%*nl*%', 1, 0) = 1;
Ok, this is my query with IF statement.
However, how can I use also "ELSE"?
Example, I would like to do something similar:
IF language match nl ---> select id field where language is nl
ELSE IF language NOT match nl ---> select id field where language is en
How can I do this in a MySQL query, please?
Thanks to all!

The syntax for IF is :
IF(test_expr, then_expr, else_expr)
so you could do something like IF(test1, result1, IF(test2, result2, else_result)) but it would not be very readable, so there's the CASE expression for that purpose.
CASE WHEN test1 THEN result1
WHEN test2 THEN result2
ELSE else_result END
If you want to condition a select column, you can use the IF in the select fields directly:
SELECT IF(match, nl_column en_column) AS lang
FROM table
Note that an expression in a where clause is either TRUE or FALSE, so writing
IF(expr, TRUE, FALSE)
is the same as
expr

use CASE instead
CASE
WHEN languages LIKE '%*nl*%' THEN 1
WHEN languages NOT LIKE '%*nl*%' THEN 0
END as languages

Related

selecting values that do not have '_' with mysql

I was looking for a way to exclude values with a '_' in the results set from a mysql database.
Why would the following sql statement return no results?
select questionKey
from labels
where set_id = 674
and questionKey like 'Class%'
and questionKey not like '%_%' ;
which was the first sql I tried where as
select questionKey
from labels
where set_id = 674
and questionKey like 'Class%'
and locate('_',questionKey) = 0 ;
returns
questionKey
ClassA
ClassB
ClassC
ClassD
ClassE
ClassF
ClassG
ClassNPS
ClassDis
which is the result I wanted. Both SQL statements appear to me to be logically equivalent though they are not.
As tadman and PM77 already pointed out, it's a special character. If you want to use the first query, try to escape it like this (note the backslash):
select questionKey
from labels
where set_id = 674
and questionKey like 'Class%'
and questionKey not like '%\_%' ;
In the LIKE context _ takes on special meaning and represents any single character. It's the only one other than % that means something here.
Your LOCATE() version is probably the best here, though it's worth noting that doing table scans like this can get cripplingly slow on large amounts of data. If underscore represents something important you might want to have a flag field you can set and index.
You could also use a regular expression to try and match records with a single condition:
REGEXP '^Class[^_]+'

Can my code using two EXISTS clauses be simplified using a CASE statement?

I have an input file that contains some rows with wild cards and some without. If there is a wildcard (*) in the input, I want to compare to a substring of the database element. If there is no wildcard, I will compare on the exact value of the input string and the full database element.
My current code looks like this:
SELECT *
FROM path.dbfile dbf
WHERE (
EXISTS
(SELECT 1
FROM path.infile slt
WHERE slt.ndc = dbf.ndc
and LOCATE('*', slt.ndc) = 0) OR
EXISTS
(SELECT 1
FROM path.infile slt
WHERE substr(dbf.ndc,1,locate('*', slt.ndc)-1) =
substr(slt.ndc,1,locate('*', slt.ndc)-1)
and LOCATE('*', slt.ndc) <> 0)
)
The code works, but I thought it might be simplified if I could combine the OR clauses into one CASE statement. I have not been able to get anything to work with a CASE. Any ideas?
Your two subqueries refer to the same table. You should be able to collapse them into one subquery by ORing together their WHERE clauses. I know it doesn't specifically answer your question about CASE, but it should simplify your query a bit.
Simply move WHERE clause from second EXIST to first one:
SELECT *
FROM path.dbfile dbf
WHERE (
EXISTS
(SELECT 1
FROM path.infile slt
WHERE
(slt.ndc = dbf.ndc
and LOCATE('*', slt.ndc) = 0) OR
(substr(dbf.ndc,1,locate('*', slt.ndc)-1) =
substr(slt.ndc,1,locate('*', slt.ndc)-1)
and LOCATE('*', slt.ndc) <> 0))
)
Correct me if I'm wrong but I believe your logic works out as:
SELECT DISTINCT dbf.*
FROM path.dbfile dbf
JOIN path.infile slt
WHERE LOCATE(SUBSTRING_INDEX(slt.ndc,'*',1), dbf.ndc) = 1;
The function SUBSTRING_INDEX returns the whole string if the delimiter is not present.
Another option is:
SELECT DISTINCT dbf.*
FROM path.dbfile dbf
JOIN path.infile slt
WHERE dbf.ndc LIKE REPLACE(REPLACE(slt.ndc, '_', '\\_'), '*', '%');
Which allows you to use * like % in the LIKE operator, assuming you don't have any percent signs in your filenames.
I have escaped any underscores as these too are a special character for LIKE, meaning one of any character.

Select all columns with ascii code in mysql

I have a code which I recently discovered :) and it does do its job and well done I might add. But, I want to check all columns instead of checking it by column. Is it possible
Check my code below:
SELECT column_name
FROM table_name
WHERE column_name REGEXP '[[.DLE.]-[.US.]]'
Now, what I want is something like this but it won't work
SELECT *
FROM table_name
WHERE REGEXP '[[.DLE.]-[.US.]]'
Kindly advice and I apologize for asking many questions :)
REGEXP is a binary operator which means you have to have a left operand and a right operand.
Like most arithmetic operators.
You could check all columns like this:
SELECT *
FROM table_name
WHERE CONCAT(a, b, c, d, ...) REGEXP '[[.DLE.]-[.US.]]'
I'm using ... for the sake of the example, but you'd need to name all your columns explicitly. There's no option to use a wildcard for the columns inside an expression.
You can't set "all columns" in a single SET clause. You'd need to do something like the following:
UPDATE table_name SET
a = REPLACE(a,char(16),''),
b = REPLACE(b,char(16),''),
c = REPLACE(c,char(16),''),
d = REPLACE(d,char(16),''),
...similar for other columns;
If you think this is an unexpected omission in the SQL language, then I wonder if you can name any other programming language that lets you compare to or assign a value to "all variables" in a single expression?

Regexp inside of 'where' method

I need a method that will go through database and return appropriate results. in this case its searching for books by author, title, publishing date or ISBN code. I decided to use where() method but i encountered two problems:
1) i have trouble searching by multiple fields. its easy looking for a title:
def self.browse(query)
if query.nil?
nil
else
self.where("title REGEXP :query", query: query)
end
end
but i dont know how to set it to look for title OR author OR isbn etc. tried
self.where("(title OR author OR publishing_date OR isbn) REGEXP :query", query: query)
but it doesnt work
and second, i want my query to match only a beginning or the end of the word. in mysql Workbench its pretty easy but i have a hard time doing it in Rails. here's what i've tried so far (and failed):
self.where("title REGEXP :query", query: /^(query)*$/)
self.where("title REGEXP /^:query/", query: query)
self.where("title REGEXP :query", query: $"query"^)
Needless to say, on the internet i found many different docs or tutorials, one saying "^" should be at the end, the other it should be at the beginning...
1) You will want to use parentheses and both AND and OR clauses in your where sql:
(title IS NOT NULL AND title REGEXP :id_query) OR (name IS NOT NULL AND name REGEXP :name_query)
2) You will want to use both ^ (beginning of line) and $ (end of line), like this.
(^something|something$)
Here is an example of the whole thing that I matched against my own code. Replace id and name with your own columns, and put extra OR's in there to match against more columns
Charity.where("(id IS NOT NULL AND id REGEXP :id_query) OR (name IS NOT NULL AND name REGEXP :name_query)", id_query:'1', name_query:'(^a|a$)')
Here is the to_sql output of the above:
Charity.where("(id IS NOT NULL AND id REGEXP :id_query) OR (name IS NOT NULL AND name REGEXP :name_query)", id_query:'1', name_query:'(^a|a$)').to_sql
=> "SELECT `charities`.* FROM `charities` WHERE ((id IS NOT NULL AND id REGEXP '1') OR (name IS NOT NULL AND name REGEXP '(^a|a$)'))"
This should do it:
self.where("title REGEXP ? OR author REGEXP ? OR publishing_date REGEXP ? OR isbn REGEXP ?", query, query, query, query)
The "?" will be subbed in order by the included variables. If you want to use the same regexp for each column, then just plug the code in as-is
As for the second part, you may want to check out the LIKE operator.
To match a column which starts with a given string you'd do:
self.where("title LIKE ?", (query + "%"))
And to match a column that ends in a particular string:
self.where("title LIKE ?", ("%" + query))
create your sql query and pass into ActiveRecord execute method,it will excute sql query and do not need to change in ActiveRecord query
sql query = "your sql query"
ActiveRecord::Base.connection.execute(sql query)
You can use or:
class MyARModel < ActiveRecord::BAse
scope :search, ->(rgx) do
where('title REGEXP ?', rgx)
.or('author REGEXP ?' rgx)
.or('publishing_date REGEXP ?' rgx)
.or('isbn REGEXP ?' rgx)
end
#...

Difference between LIKE and = in MYSQL?

What's the difference between
SELECT foo FROM bar WHERE foobar='$foo'
AND
SELECT foo FROM bar WHERE foobar LIKE'$foo'
= in SQL does exact matching.
LIKE does wildcard matching, using '%' as the multi-character match symbol and '_' as the single-character match symbol. '\' is the default escape character.
foobar = '$foo' and foobar LIKE '$foo' will behave the same, because neither string contains a wildcard.
foobar LIKE '%foo' will match anything ending in 'foo'.
LIKE also has an ESCAPE clause so you can set an escape character. This will let you match literal '%' or '_' within the string. You can also do NOT LIKE.
The MySQL site has documentation on the LIKE operator. The syntax is
expression [NOT] LIKE pattern [ESCAPE 'escape']
LIKE can do wildcard matching:
SELECT foo FROM bar WHERE foobar LIKE "Foo%"
If you don't need pattern matching, then use = instead of LIKE. It's faster and more secure. (You are using parameterized queries, right?)
Please bear in mind as well that MySQL will do castings dependent upon the situation: LIKE will perform string cast, whereas = will perform int cast. Considering the situation of:
(int) (vchar2)
id field1 field2
1 1 1
2 1 1,2
SELECT *
FROM test AS a
LEFT JOIN test AS b ON a.field1 LIKE b.field2
will produce
id field1 field2 id field1 field2
1 1 1 1 1 1
2 1 1,2 1 1 1
whereas
SELECT *
FROM test AS a
LEFT JOIN test AS b ON a.field1 = b.field2
will produce
id field1 field2 id field1 field2
1 1 1 1 1 1
1 1 1 2 1 1,2
2 1 1,2 1 1 1
2 1 1,2 2 1 1,2
According to the MYSQL Reference page, trailing spaces are significant in LIKE but not =, and you can use wildcards, % for any characters, and _ for exactly one character.
I think in term of speed = is faster than LIKE. As stated, = does an exact match and LIKE can use a wildcard if needed.
I always use = sign whenever I know the values of something. For example
select * from state where state='PA'
Then for likes I use things like:
select * from person where first_name like 'blah%' and last_name like 'blah%'
If you use Oracle Developers Tool, you can test it with Explain to determine the impact on the database.
The end result will be the same, but the query engine uses different logic to get to the answer. Generally, LIKE queries burn more cycles than "=" queries. But when no wildcard character is supplied, I'm not certain how the optimizer may treat that.
With the example in your question there is no difference.
But, like Jesse said you can do wildcard matching
SELECT foo FROM bar WHERE foobar LIKE "Foo%"
SELECT foo FROM bar WHERE foobar NOT LIKE "%Foo%"
More info:
http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html
A little bit og google doesn't hurt...
A WHERE clause with equal sign (=) works fine if we want to do an exact match. But there may be a requirement where we want to filter out all the results where 'foobar' should contain "foo". This can be handled using SQL LIKE clause alongwith WHERE clause.
If SQL LIKE clause is used along with % characters then it will work like a wildcard.
SELECT foo FROM bar WHERE foobar LIKE'$foo%'
Without a % character LIKE clause is very similar to equal sign alongwith WHERE clause.
In your example, they are semantically equal and should return the same output.
However, LIKE will give you the ability of pattern matching with wildcards.
You should also note that = might give you a performance boost on some systems, so if you are for instance, searching for an exakt number, = would be the prefered method.
Looks very much like taken out from a PHP script. The intention was to pattern-match the contents of variable $foo against the foo database field, but I bet it was supposed to be written in double quotes, so the contents of $foo would be fed into the query.
As you put it, there is NO difference.
It could potentially be slower but I bet MySQL realises there are no wildcard characters in the search string, so it will not do LIKE patter-matching after all, so really, no difference.
In my case I find Like being faster than =
Like fetched a number of rows in 0.203 secs the first time then 0.140 secs
= returns fetched the same rows in 0.156 secs constantly
Take your choice
I found an important difference between LIKE and equal sign = !
Example: I have a table with a field "ID" (type: int(20) ) and a record that contains the value "123456789"
If I do:
SELECT ID FROM example WHERE ID = '123456789-100'
Record with ID = '123456789' is found (is an incorrect result)
If I do:
SELECT ID FROM example WHERE ID LIKE '123456789-100'
No record is found (this is correct)
So, at least for INTEGER-fields it seems an important difference...