SQL Query with possible null parameters - mysql

I have to do a query SQL to search into the table below
Person
Name - Surname - Age
using Name, Surname ad Age as parameter of my query.
Since this query is generated dinamically, may happen that one of this parameters is equal to "" or null. In this case I expect that the behavior obtained is:
If Name = "", I want to search for surname and age regardless of the
name (every name).
I have found a possible solution to this problem and is to use a LIKE statement, in this way:
SELECT * ...
WHERE Surname like '%%' AND Name like '%%' AND Age like '%%'
When I put %% in the like it returns me all records of the table.
Is this correct or there is another way?

SQL offers methods for those issues.
You can easily use (Surname IS NULL OR Name = '' OR ...)
See: https://dev.mysql.com/doc/refman/5.7/en/is-null-optimization.html
Theres also a thread with almost the same question: MySQL syntax checking if parameter is null

...
Where (IsNull(#SurName, '') = '' OR #SurName = t.SurName)
AND (IsNull(#Name, '') = '' OR #Name = t.Name)
AND (IsNull(#Age, '') = '' OR #Age = t.Age)

For sql server it could look something like this:
select *
from t
where (
Surname like '%'+#Surname+'%'
or coalesce(#Surname,'') = ''
)
and (
Name like '%'+#Name+'%'
or coalesce(#Name,'') = ''
)
and (
Age like '%'+#Age+'%'
or coalesce(#Age,'') = ''
)
catch-all queries
Dynamic Search Conditions - Erland Sommarskog
Catch-all queries - Gail Shaw

SELECT * ...
WHERE
IF(NAME IS NULL OR NAME='',Surname LIKE '%%' AND Age LIKE '%%', Surname LIKE '%%' AND NAME LIKE '%%' AND Age LIKE '%%');

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).

MySQL function IFNULL is not working correctly with Wildcards

I have a SQL Script where I am using wildcard in If Null statement.
I am looking to show all other records regardless of field has null values in it.
SELECT * FROM ABC WHERE (Value=1 AND
Prefix like IFNULL(${parameter:X},'%')
AND
Base like IFNULL(${parameter:Y},'%')
AND
Suffix like IFNULL(${parameter:Z},'%')
AND
Area like IFNULL(${parameter:Ax},'%')
);
I am expecting the result should show all values regardless if Area filed value is null
Don't use like. It will filter out NULL values in the data. Just do:
WHERE (NewestVersion = 1 AND
(Prefix like ${param:PrefixLookup} or ${param:PrefixLookup} is null) AND
(Base like ${param:BaseLookup} or ${param:BaseLookup} is null) AND
(Suffix like ${param:SuffixLookup} or ${param:SuffixLookup} is null) AND
(Custom2 like ${param:DRELookup} or ${param:DRELookup} is null)
If you have empty strings, then comparisons to NULL will not help. Just use:
WHERE (NewestVersion = 1 AND
(Prefix like ${param:PrefixLookup} or ${param:PrefixLookup} = '') AND
(Base like ${param:BaseLookup} or ${param:BaseLookup} = '') AND
(Suffix like ${param:SuffixLookup} or ${param:SuffixLookup} = '') AND
(Custom2 like ${param:DRELookup} or ${param:DRELookup} = '')

query sql table By First_Name and/or Last_Name

I need to write a query that query customer table base on first_name and/ or last_name. in my query it works for example when I run with firstname =Ann it brings all the customers with that firstname and when I run with lastname=sam brings all will that last name, but when I run with 'Ann','Sam' instead of bring only one record that is match this it brings all with firstname Ann or last same sam so it bring several records.
select * from customer
where WHERE --(CONVERT(varchar(50),decryptbykey([Account_Number]))=
#UserName or ce.Email= #UserName or Username=#UserName )
((CONVERT(varchar(50),decryptbykey([First_Name]))) =#First_Name)
and (CONVERT(varchar(50),decryptbykey([Last_Name])) =#Last_Name)
or ((CONVERT(varchar(50),decryptbykey([First_Name]))) =#First_Name)
or (CONVERT(varchar(50),decryptbykey([Last_Name])) =#Last_Name)
In this scenario I'd treat each parameter as optional. If provided then enforce the condition, otherwise skip that check. This type of query is convenient in the sense that you do not have to maintain n! versions of your query, however I must warn you this is prone to bad cached query plans.
If you experience a significant slowdown that you cannot explain you might want to tack 'OPTION (RECOMPILE)' to the end of you query. In general this may seem like a bad idea but I'd rather SQL server take an extra 5 ms each query than take 30 seconds once. Locks, database load, user experience, etc. As usual, forcing query options is generally a bad idea and should only be done if there is no other reasonable solution.
IF (#UserName_Name = '')
SET #First_Name = NULL;
IF (#First_Name = '')
SET #First_Name = NULL;
IF (#Last_Name = '')
SET #First_Name = NULL;
select *
from customer
where (#UserName IS NULL
OR Username = #UserName
OR Email = #UserName
OR CONVERT(varchar(50), decryptbykey([Account_Number])) = #UserName)
AND (#First_Name IS NULL OR CONVERT(varchar(50), decryptbykey([First_Name])) = #First_Name)
AND (#Last_Name IS NULL OR CONVERT(varchar(50), decryptbykey([First_Name])) = #Last_Name);
This might not be pretty, but it works as you describe it.
If exact match on both Firstname AND Lastname only the exact match is returned (could be more than one though). If match on only Firstname OR Lastname, all matching records are returned
SELECT * FROM customer
WHERE
(
(First_name = (CASE WHEN (First_name = #First_Name AND Last_name = #Last_Name) THEN #First_Name END))
AND
(Last_name = (CASE WHEN (First_name = #First_Name AND Last_name = #Last_Name) THEN #Last_Name END))
)
OR
(
(First_name = (CASE WHEN (First_name = #First_Name AND Last_name <> #Last_Name) THEN #First_Name END))
OR
(Last_name = (CASE WHEN (First_name <> #First_Name AND Last_name = #Last_Name) THEN #Last_Name END))
)
You'll have to add your other filters and CONVERTs yourself.

Null value matching in mySql

I have three tables in a mysql database . Deseasetype(DTID,TypeName) , Symptom(SID, SymptomName, DTID) , Result(RID, SID1, SID2, SID3, result).1st two table, i think is clear enough.
In result table: there will be combination's of symtoms and any values of SymID1/ SymID2/ SymID3 can be null. here i send a picture of the table result.
I want to input some symptom and output will be the result from the 'Result' table.
For that i wrote this query:
$query = "select Result from result where (result .SID1= '$symptom1') AND (result.SID2= '$symptom2' ) AND (result.SID3 = '$symptom3')";
This work only when three symptom's have value. but if any of the symptom's are null, then no result found. May be the query should be more perfect.
**please avoid any syntax error in my writing.
That's because you are comparing NULL to an empty string, and they aren't equal. You could try this instead:
SELECT Result
FROM symptom
WHERE IFNULL(symptom.SID1, '') = '$symptom1'
AND IFNULL(symptom.SID2, '') = '$symptom2'
AND IFNULL(symptom.SID3, '') = '$symptom3'
Notes:
You need to correctly escape the values of $symptom1, $symptom2 and $symptom3.
This won't efficiently use indexes.
As mark pointed out, the query is eventually falling down to compare with null if you are not escaping the null.
Or you can slightly change your logic to show a empty symptom with value '0' and then using the coalesce function you can easily build your query.
Does this work?
$query = "select Result from result
where (result.SID1 = '$symptom1' OR result.SID1 IS NULL) AND
(result.SID2 = '$symptom2' OR result.SID2 IS NULL) AND
(result.SID3 = '$symptom3' OR result.SID3 IS NULL)";

Dynamic values inside the mysql query

I am trying to get result using below query, idRegion is recorded in database as 1,2,3,4 for each franchisee, so what I want is to display all franchisees with idRegion 2. I am getting idRegion via $_Get. this display only first digit before coma, I think so it should ready whole string 1,2,3,4 ? When I am working with static values that works?
$colname_franchisee = "-1";
if (isset($_GET['id'])) {
$colname_franchisee = $_GET['id'];
}
$query_franchisee = sprintf("SELECT * FROM franchise WHERE stiShowInLinks = 'Y' AND idRegion LIKE '%s%' ORDER BY stiName ASC", $colname_franchisee);
This should work although I do not like your database design:
$query_franchisee = sprintf("
SELECT *
FROM franchise
WHERE
stiShowInLinks = 'Y' AND (
idRegion = '%d' OR
idRegion LIKE '%d,%%' OR
idRegion LIKE '%%,%d' OR
idRegion LIKE '%%,%d,%%'
)
ORDER BY stiName ASC
",
$colname_franchisee,
$colname_franchisee,
$colname_franchisee,
$colname_franchisee
);
The sprintf function treats the % character as a format specifier and treats at the next few characters in a special way. In order to use the % character literally, you must use %%. So after sprintf, your query becomes:
idRegion = '1234' OR
idRegion LIKE '1234,%' OR
idRegion LIKE '%,1234' OR
idRegion LIKE '%,1234,%'
$colname_franchisee = "-1";
if (isset($_GET['id'])) {
$cf = intval($_GET['id']); only if id integer.
}
$query_franchisee = "SELECT * FROM franchise
WHERE stiShowInLinks = 'Y'
AND idRegion LIKE '%cf%'
ORDER BY stiName ASC", $cf);