Where 'foo' OR 'bar' AND 'lol' OR 'rofl' MySQL - mysql

In what order would this be evaluated. My intension is that if it finds either foo or bar, it would also search for lol and rofl.
Is this totally in the woods? And if so, how would one evaluate an expression like that.

The AND operator has higher precedence than OR in MySql, so your current expression evaluates as:
WHERE 'foo' OR ('bar' AND 'lol') OR 'rofl'
Add parentheses to the expression if you want to force the evaluation order:
WHERE ('foo' OR 'bar') AND ('lol' OR 'rofl')

AND will be processed first, after that OR will be processed. So, it will be:
'foo' OR ('bar' AND 'lol') OR 'rofl'
After that, it is left to right order.

take a look at the documentation - AND has a higher precedence, so it would be like this:
WHERE 'foo' OR ( 'bar' AND 'lol' ) OR 'rofl'

SELECT
Id, Name
FROM
TestTable
WHERE
(Name = 'foo') OR (Name = 'bar') AND (Name = 'lol') OR (Name = 'rofl')
Will give you the following result in MS SQL Server:
1 foo
4 rofl
So it seems it will combine bar AND lol and evals foo and rofl seperately like this:
SELECT
Id, Name
FROM
TestTable
WHERE
(Name = 'foo') OR ((Name = 'bar') AND (Name = 'lol')) OR (Name = 'rofl')
What you probably want to do is (technically):
SELECT
Id, Name
FROM
TestTable
WHERE
((Name = 'foo') OR (Name = 'bar')) AND ((Name = 'lol') OR (Name = 'rofl'))

Related

Using case statement or IF inside a WHERE clause

I have several stored procedures that are almost identical but have some different AND parts inside a WHERE clause.
Based on a variable deptname, I want to add additional AND/OR conditions to my already existing WHERE clause. So kind of like IF/CASE WHEN on the part that is different.
Think about it as string concatenation
query_string = 'WHERE a= XYZ AND B= 123"
if deptname = a: query_string + "AND additional conditions for dept a"
else if deptname = b:query_string + "AND additional conditions for dept b"
What is the appropriate way to use a variable?
here is some pseudo code of what I am trying to do
SELECT
personID AS pid,
personcode,
persondeptcode,
more_fields AS fields
FROM
TABLE_XYZ
WHERE
--shared parts
personcode = 'C'
AND
persondeptcode = 'MAJ'
--- NOW the different part
IF #deptname = "deptA"
AND
(
PROGRAM_LDESCR IN
(
'prog1',
'prog2',
'prog3'
)
OR
aprogram IN ('aprogram1')
OR
(aprogram IN ('aprogram2') AND PLAN_LDESCR IN ('plan123'))
);
--- THIS IS A DIFFERENT DEPT SO WE HAVE DIFFERENT AND PART
ELSE IF #deptname = "deptB"
(
PROGRAM_LDESCR IN
(
'1234'
)
OR
aprogram IN ('a1234')
);
You can use a CASE expression in this case, the important thing is to make sure you have an ELSE clause to ensure the expression remains true if #deptname is not one of the two values with extra conditions:
WHERE personcode = 'C'
AND persondeptcode = 'MAJ'
AND (CASE #deptname
WHEN "deptA" THEN PROGRAM_LDESCR IN ('prog1', 'prog2', 'prog3')
OR aprogram IN ('aprogram1')
OR aprogram IN ('aprogram2') AND PLAN_LDESCR IN ('plan123')
WHEN "deptB" THEN PROGRAM_LDESCR IN ('1234')
OR aprogram IN ('a1234')
ELSE 1
END)
Here is a simple demo of a CASE expression used in this fashion.
You seem to want something like:
AND
(#deptname = 'dept123' AND (PROGRAM_LDESCR IN ('1234') OR aprogram IN ('a1234')) OR
#deptname <> 'dept123'
)
To combine the last part of the WHERE clause (if I'm understanding your commented-code correctly), you could do something like the following:
SELECT
personID AS pid,
personcode,
persondeptcode,
more_fields AS fields
FROM
TABLE_XYZ
WHERE
personcode = 'C'
AND persondeptcode = 'MAJ'
AND (
(#deptname="deptA" AND (PROGRAM_LDESCR IN ('prog1', 'prog2', 'prog3') OR aprogram IN ('aprogram1') OR (aprogram IN ('aprogram2') AND PLAN_LDESCR IN ('plan123'))))
OR
(#deptname="deptB" AND (PROGRAM_LDESCR IN ('1234') OR aprogram IN ('a1234'))
)
Normally you would use the WHERE clause to filter out unnecessary rows of data and a CASE statement if you wanted to actually change the value in the SELECT statement (I rarely see CASE statements outside a SELECT clause, unless it is doing something like a complex sort).

Flexible search Query for stringset?

Please find the below query:
Table Name : B
query : select * from {B}
ID comp
1 d,e,f
I want to check if the value 'f' is present in comp, or not, using an SQL/Flexible search Query.
Is it possible to write a sql query for this scenario?
Update :
SELECT DISTINCT {b:pk} FROM {A AS a left join B as B on {a:ncode} = {b:ncode} and {a:qCode} = {b:qCode}}
WHERE
{a:compID} IN ()
Assume a:compID is "f"
What should be my subquery after the IN operator to achieve my requirement?
SELECT * FROM {B} where {comp} LIKE '%,f,%'
You can search in string in mysql:
//full search:
SELECT * FROM A WHERE comp LIKE '%f%'
// start with f
SELECT * FROM A WHERE comp LIKE '%f'
// end with f
SELECT * FROM A WHERE comp LIKE 'f%'
This will work:
SELECT FIND_IN_SET('f',(SELECT comp FROM t));
Run this code on Fiddle
If you want to check present or not present then:
SELECT case when FIND_IN_SET('f',(SELECT comp FROM t))=0 then'not present'
else 'present' end from dual;
Start with f
LIKE 'f%'
End with f
LIKE '%f'

How to check if a variable equals to part of one of the columns in a table in the Database?

For example I have a variable $num = 123; and another one called `$name=joe;' , and there is a Database that contains a table called "data" and inside this table there are two columns (num [type=varchar(255)] - name[type=varchar(255)]) .
For example these query exists in the DB :
num = 123456 , name = joe
How to make a check that the first "3" numbers equals the $num variable and the name equals variable $name ?
I tried this but it didn't work:
SELECT * FROM data Where SUBSTRING(num , 0 , 3) = '123' AND name = 'joe'
In MySQL, substring indexing starts at 1:
WHERE SUBSTRING(num , 1 , 3) = '123' AND name = 'joe'
But LEFT() or LIKE would more commonly be used:
WHERE LEFT(num , 3) = '123' AND name = 'joe'
WHERE num = '123%' AND name = 'joe'
The advantage of LIKE is that it can make use of an index . . . even one on (name, num).
The MySQL substring() function is 1-based, not 0-based, so this should work for you:
SELECT * FROM data Where SUBSTRING(num , 1 , 3) = '123' AND name = 'joe'

SQL Query w/ multiple name / value pairs in Where clause

I have a table called Properties (pid, uid, pname, pvalue). The pid column is auto generated. Each uid (user id) could have multiple name value pairs stored in the pname and pvalue.
As an input I've multiple name value pairs for pname and pvalue which forms a complicated boolean expression.
For example: let's start w/ one name value pair. Say I want to retrieve all uid's whose 'favorite_color' is 'red'.
I wrote an SQL query:
SELECT *
FROM properties
WHERE ((pname = 'favorite_color') and (pvalue = 'red'))
The query soon gets complicated if I had to retrieve something like, fetch all uid's whose 'favorite_color' is 'red' or 'blue' and 'favorite_drink' is 'juice' or ' 'milk' and 'favorite_ hobby' is 'music' or 'art' etc.
I wrote an SQL query:
SELECT *
FROM properties
WHERE (((pname = 'favorite_color') and (pvalue = 'red'))
OR ((pname = 'favorite_color') and (pvalue = 'blue')))
AND (((pname = 'favorite_drink') and (pvalue = 'juice'))
OR ((pname = 'favorite_drink') and (pvalue = 'milk')))
AND (((pname = 'favorite_hobby') and (pvalue = 'music'))
OR ((pname = 'favorite_hobby') and (pvalue = 'art')))
I got the expression correct but unfortunately it fails because the evaluation is done on each row. What if I wanted to add more name value pairs to the where clause?
Questions:
Is it possible to write and SQL query for this?
The other idea I had was to fetch all the pname, pvalue pairs for each user, build a dynamic expression using an expression language and my input name value paris to evaluate it. I've apache's JEXL in mind.
To do the ANDs you need to do as many self-joins as you have and-ed conditions:
SELECT *
FROM Properties p1, Properties p2, Properties p3
WHERE p1.uid = p2.uid AND p1.uid = p3.uid
AND (p1.pname = 'favorite_color' AND p1.pvalue IN ('red', 'blue'))
AND (p2.pname = 'favorite_drink' AND p2.pvalue IN ('juice', 'milk'))
AND (p3.pname = 'favorite_hobby' AND p2.pvalue IN ('music', 'art'))
EDIT:
Another possibility is to denormalize the data, and then use FIND_IN_SET() or RLIKE:
SELECT uid, group_concat(concat(pname, '=', pvalue)) props
FROM Properties
GROUP BY uid
HAVING props RLIKE 'favorite_color=(red|blue)'
AND props RLIKE 'favorite_drink=(juice|milk)'
AND props RLIKE 'favorite_hobby=(music|art)'
SELECT p1.*,p2.pname,p2.pvalue,p3.pname,p3.pvalue
FROM (
(Select *
from Properties
where (pname = 'favorite_color' AND pvalue IN ('red', 'blue')) p1,
(Select *
from Properties
where (pname = 'favorite_drink' AND pvalue IN ('juice','milk')) p2,
(Select *
from Properties
where (pname = 'favorite_hobby' AND pvalue IN ('music', 'art')) p3,
)
WHERE p1.uid = p2.uid AND p1.uid = p3.uid

In SQL, is there something like: WHERE x = ANY_VALUE?

In a SQL query like this:
SELECT *
FROM MyTable
WHERE x = 5;
is it possible to modify the WHERE condition so that SELECT looks for every value of x? Something like (wrong syntax):
SELECT *
FROM MyTable
WHERE x = ANY_VALUE;
The reason behind this question is that I have to parse and modify some SQL queries through some C++ code I am writing. I know in this case I could just remove or comment the whole WHERE condition, but this is a simplification.
Thank you.
In cases like this, you normally would do something like this:
SELECT *
FROM MyTable
WHERE x = SOME_VALUE OR 1 = 1;
SOME_VALUE is arbitrary, it can be anything matching the type of the column, because the WHERE clause will always be true because of the second part.
You could just omit WHERE clause. :)
While I think it's really the wrong way to go about it (just make the effort to remove the Where), how about where x = x? It won't work if X is null (you'd have to use "x is null or x = x") but don't bother if you know x won't be null.
You can try that:
SELECT *
FROM MyTable
WHERE x = x OR x IS NULL;
You could make your query like this
DECLARE #VALUE as (type of x)
--SET #VALUE = ''
SELECT *
FROM MyTable
WHERE (#VALUE IS NULL OR x = #VALUE);
and your parse would only have to replace
the: --SET #VALUE = '' line for one with the value you want, minus the comment, like: SET #VALUE = 'abc'
hope this helps