Dynamic MySQL Where Clause in Stored Procedure - mysql

I have a question and maybe its simple (for you Gurus).
I'm transposing my SQL Paging class from C# to a MySQL Stored Procedure. In my C# home-made object, the query is dynamically built based off a criteria. Example:
if(keywords is not null)
{
whereClause += "WHERE description LIKE '%keywords%'"
}
if(price is not null)
{
whereClause += "AND price = '%price%'"
}
....
string query = "SELECT col1, col2 FROM tblThreads " + whereClause
Now, my question is: How do I do a dynamic where clause in MySQL similar to this? Or rather, if they don't enter anything for those parameters, how would I tell MySQL in the Stored Procedure to skip those? IE:
SELECT col1, col2 FROM tblThreads
Would something like this work, if those parameters were null?
SELECT col1, col2 FROM tblThreads WHERE (IS NULL #keywords OR description like '%#keywords%'
??
Thanks guys.

You can use CASE statement to check for the value of #keywords, eg.
SELECT col1, col2
FROM tblThreads
WHERE description LIKE CASE WHEN #keywords IS NULL
THEN description
ELSE CONCAT('%', #keywords, '%')
END
AND
price LIKE CASE WHEN #price IS NULL
THEN price
ELSE CONCAT('%', #price, '%')
END

The easiest way if you're allowing them to query the entire database is to just add a 1 = 1 to your statement Something like
whereClause = "WHERE 1 = 1"
if(keywords is not null)
{
whereClause += "AND description LIKE '%keywords%'"
}
if(price is not null)
{
whereClause += "AND price = '%price%'"
}

SELECT col1, col2
FROM tblThreads
WHERE case when #keywords is not null then description like '%' + #keywords + '%' when #price is not null then price like'%' + #price + '%' end

DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `sp_Name4`(
IN a int(255),
IN b int(255),
IN dept_id_in int(255)
)
BEGIN
SELECT
emp.emp_id, emp.emp_name,
emp.emp_job,
emp.dept,
emp.percent_doctor,
emp.percent_center,
patient_exam.exam_id,
patient_exam.p_id,
ABS(SUM(patient_exam.exam_price)) as SUM_price,
ABS((SUM(patient_exam.exam_price)* emp.percent_center )/100 ) as total_doc,
ABS((SUM(patient_exam.exam_price)* emp.percent_doctor )/100 ) as total_center
FROM emp
left join patient_exam
ON emp.emp_id = patient_exam.doctor
WHERE emp.emp_is_delete=0 and patient_exam.ex_is_delete=0 and 1=1
CASE WHEN dept_id_in IS not NULL
THEN
and patient_exam.dept_id=dept_id_in
END
group by emp.emp_id, patient_exam.exam_id order by emp.emp_id, patient_exam.exam_id desc limit a,b;
END$$
DELIMITER ;

Related

Using And & OR condition in MySQl With Same Query

How to use the And, OR condition in the same MySQL where query.
SELECT * FROM Table_name
WHERE filed_name = 0 AND (field1 != '' AND field2 ='')
OR (field1 = '' AND field2 != '') AND filed3 = 1;
I want to more than 2 fileds in brackets.
You can include as many conditions as you need within parentheses, but you do need to be careful with OR and you may find it necessary to combine multiple sets of conditions with parentheses. When this happens consistent formatting and use of indents can help you maintain the required logic.
SELECT *
FROM Table_name
WHERE (field_name = 0
AND (field1 != '' AND field2 ='')
)
OR (field3 = 1
AND (field1 = '' AND field2 != '')
)
;
Do note that the query above is a guess; I have assumed you need 2 sets of conditions.
SQL refer to columns (not at fields)
anyway you can use all the columns you need in each where condition
SELECT *
FROM Table_name
WHERE col0 = 0
AND col1 != ''
AND col2 =''
OR (col1 = '' AND col2 != '' AND col3 ='YOUR_VALUE')
AND col3 = 1
OR (col4 = 'your_value4' AND col5> 100 );
the parentheses are needed for change the priority in evalaution of the condition ...

Concatenating fields in select clause JOOQ

I'm working in a query using JOOQ and I'm trying to output a column as a
concatenation (space separated) of other fields extracted in the same query.
Getting into detail, with the next code I try to create a select statement with a column called fullAdress by grouping all the address lines contained in the address table. So, for each field, if it's not null or empty it will be concatenated to the result (actually no space is being added).
#Override
protected List<Field<?>> selectCustomFields() {
List<Field<?>> customSelect = new ArrayList<Field<?>>();
// Fields to use in the concatenation
Field<?> field1 = field("addr.AddressLine1"), field2 = field("addr.AddressLine2"),field3 = field("addr.AddressLine3"),
field4 = field("addr.AddressLine4"), field5 = field("addr.PostalCode"), field6 = field("addr.City"),
field7 = field("addr.State"), field8 = field("addr.County"), field9 = field("addr.Country");
// Create non null/empty conditions
Condition condLine1 = field1.isNotNull().and(field1.length().ne(0));
Condition condLine2 = field2.isNotNull().and(field2.length().ne(0));
Condition condLine3 = field3.isNotNull().and(field3.length().ne(0));
Condition condLine4 = field4.isNotNull().and(field4.length().ne(0));
Condition condLine5 = field5.isNotNull().and(field5.length().ne(0));
Condition condLine6 = field6.isNotNull().and(field6.length().ne(0));
Condition condLine7 = field7.isNotNull().and(field7.length().ne(0));
Condition condLine8 = field8.isNotNull().and(field8.length().ne(0));
Condition condLine9 = field9.isNotNull().and(field9.length().ne(0));
// Concat address lines when meets condition
customSelect.add(concat(DSL.when(condLine1, field1),
DSL.when(condLine2, field2),
DSL.when(condLine3, field3),
DSL.when(condLine4, field4),
DSL.when(condLine5, field5),
DSL.when(condLine6, field6),
DSL.when(condLine7, field7),
DSL.when(condLine8, field8),
DSL.when(condLine9, field9))
.as("fullAddress"));
return customSelect;
}
JOOQ will generate the next from the previous select statement, which is giving a null value and not concatenating the fields correctly.
select
concat(
cast(case when (
addr.AddressLine1 is not null
and char_length(cast(addr.AddressLine1 as char)) <> 0
) then addr.AddressLine1 end as char),
cast(case when (
addr.AddressLine2 is not null
and char_length(cast(addr.AddressLine2 as char)) <> 0
) then addr.AddressLine2 end as char),
cast(case when (
addr.AddressLine3 is not null
and char_length(cast(addr.AddressLine3 as char)) <> 0
) then addr.AddressLine3 end as char),
cast(case when (
addr.AddressLine4 is not null
and char_length(cast(addr.AddressLine4 as char)) <> 0
) then addr.AddressLine4 end as char),
cast(case when (
addr.PostalCode is not null
and char_length(cast(addr.PostalCode as char)) <> 0
) then addr.PostalCode end as char),
cast(case when (
addr.City is not null
and char_length(cast(addr.City as char)) <> 0
) then addr.City end as char),
cast(case when (
addr.State is not null
and char_length(cast(addr.State as char)) <> 0
) then addr.State end as char),
cast(case when (
addr.County is not null
and char_length(cast(addr.County as char)) <> 0
) then addr.County end as char),
cast(case when (
addr.Country is not null
and char_length(cast(addr.Country as char)) <> 0
) then addr.Country end as char)) as `fullAddress`
from Address as `addr`
....
My questions are,
how should I create my select statement correctly?
how can I best add the space separator?
is there any better alternative to JOOQ ( when = case ) condition clause?
how should I create my select statement correctly?
You forgot the CASE .. ELSE part, or otherwise() in jOOQ:
// Concat address lines when meets condition
customSelect.add(concat(DSL.when(condLine1, field1).otherwise(""),
DSL.when(condLine2, field2).otherwise(""),
DSL.when(condLine3, field3).otherwise(""),
DSL.when(condLine4, field4).otherwise(""),
DSL.when(condLine5, field5).otherwise(""),
DSL.when(condLine6, field6).otherwise(""),
DSL.when(condLine7, field7).otherwise(""),
DSL.when(condLine8, field8).otherwise(""),
DSL.when(condLine9, field9).otherwise(""))
.as("fullAddress"));
how can I best add the space separator?
If you want an additional space separator between your address parts, you could write:
// Concat address lines when meets condition
customSelect.add(concat(DSL.when(condLine1, field1.concat(" ")).otherwise(""),
DSL.when(condLine2, field2.concat(" ")).otherwise(""),
DSL.when(condLine3, field3.concat(" ")).otherwise(""),
DSL.when(condLine4, field4.concat(" ")).otherwise(""),
DSL.when(condLine5, field5.concat(" ")).otherwise(""),
DSL.when(condLine6, field6.concat(" ")).otherwise(""),
DSL.when(condLine7, field7.concat(" ")).otherwise(""),
DSL.when(condLine8, field8.concat(" ")).otherwise(""),
DSL.when(condLine9, field9.concat(" ")).otherwise("")).trim()
.as("fullAddress"));
is there any better alternative to JOOQ ( when = case ) condition clause?
I think the approach is sound. Of course, you probably shouldn't repeat all that logic all the time, but create a loop of the sort:
List<Field<String>> list = new ArrayList<>();
for (int i = 0; i < fields.size(); i++) {
list.add(DSL.when(conditions.get(i), (Field) fields.get(i)).otherwise(""));
}
customSelect.add(concat(list.toArray(new Field[0])).trim().as("fullAddress"));

Update multiple rows in a single MySQL query

I am trying to run this:
UPDATE test
SET col2=1 WHERE col1='test1',
SET col2=3 WHERE col1='test2';
The error I am getting:
[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '
My table:
CREATE TABLE `test` (
`col1` varchar(30) NOT NULL,
`col2` int(5) DEFAULT NULL,
PRIMARY KEY (`col1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It’s something about , at the end of the first row. When I changed it to ;, it didn’t recognize col2. How can I do this in one query?
This is most clear way
UPDATE test
SET col2 = CASE col1
WHEN 'test1' THEN 1
WHEN 'test2' THEN 3
WHEN 'test3' THEN 5
END,
colx = CASE col1
WHEN 'test1' THEN 'xx'
WHEN 'test2' THEN 'yy'
WHEN 'test3' THEN 'zz'
END
WHERE col1 IN ('test1','test2','test3')
Consider using INSERT-ODKU (ON DUPLICATE KEY UPDATE), because that supports to update multiple rows.
Make sure that the values of all PK columns are in the VALUES().
Where feasible, generate the SQL with data from a slave.
you can use CASE on this
UPDATE test
SET col2 = CASE WHEN col1 = 'test1' THEN 1 ELSE 3 END
WHERE col1 IN ('test1', 'test2')
or IF (for MySQL only)
UPDATE test
SET col2 = IF(col1 = 'test1', 1, 3)
WHERE col1 IN ('test1', 'test2')
alternatively when the construct with cases gets too unreadable, you could/should start a transaction and just do the updates sequentially.
this usually results in more straightforward sql, except if the first statements creates rows that then are matched by the second statement when they should not. however this is not the case in your example.
This is how I did it:
UPDATE col1 (static value), col2 (static value), and col3 (different values) WHERE col4 has different values AND col5 is static.
$someArray = ["a","b","c"];
$anotherArray = [1,2,3];
$sql = "UPDATE table SET col1 = '$staticValue1', col2 = '$staticValue2', col3 = CASE col4";
$sqlEnd = " END WHERE col4 IN (";
$seperator = ",";
for ( $c = 0; $c < count($someArray); $c++ ) {
$sql .= " WHEN " . "'" . $someArray[$c] . "'" . " THEN " . $anotherArray[$c];
if ( $c === count($someArray) - 1 ) {
$separator = ") AND col5 = '$staticValue5'";
}
$sqlEnd .= "'" . $someArray[$c] . "'" . $seperator;
}
$sql .= $sqlEnd;
$retval = mysqli_query( $conn, $sql);
if(! $retval ) {
/* handle error here */
}
And the output string for MySql query would be something like this:
UPDATE table SET col1 = '1', col2 = '2', col3 = CASE col4 WHEN 'a' THEN 1 WHEN 'b' THEN 2 WHEN 'c' THEN 3 END WHERE col4 IN ('a','b','c') AND col5 = 'col5'
With MySQL8 it can be done smarter,
but also consider creating a temporary result set, inside the SQL,
to JOIN with:
UPDATE MyTable t JOIN (
SELECT 'v1a' AS c1, 'v1b' AS c2
UNION ALL SELECT 'v2a', 'v2b'
UNION ALL SELECT 'v3a', 'v3b'
) AS u USING (c1)
SET t.c2 = u.c2

How to check if field is null or empty in MySQL?

I am trying to figure out how to check if a field is NULL or empty. I have this:
SELECT IFNULL(field1, 'empty') as field1 from tablename
I need to add an additional check field1 != "" something like:
SELECT IFNULL(field1, 'empty') OR field1 != "" as field1 from tablename
Any idea how to accomplish this?
Either use
SELECT IF(field1 IS NULL or field1 = '', 'empty', field1) as field1
from tablename
or
SELECT case when field1 IS NULL or field1 = ''
then 'empty'
else field1
end as field1
from tablename
If you only want to check for null and not for empty strings then you can also use ifnull() or coalesce(field1, 'empty'). But that is not suitable for empty strings.
Using nullif does the trick:
SELECT ifnull(nullif(field1,''),'empty') AS field1
FROM tablename;
How it works: nullif is returning NULL if field is an empty string, otherwise returns the field itself. This has both the cases covered (the case when field is NULL and the case when it's an empty string).
Alternatively you can also use CASE for the same:
SELECT CASE WHEN field1 IS NULL OR field1 = ''
THEN 'empty'
ELSE field1 END AS field1
FROM tablename.
You can use the IFNULL function inside the IF. This will be a little shorter, and there will be fewer repetitions of the field name.
SELECT IF(IFNULL(field1, '') = '', 'empty', field1) AS field1
FROM tablename
You can create a function to make this easy.
create function IFEMPTY(s text, defaultValue text)
returns text deterministic
return if(s is null or s = '', defaultValue, s);
Using:
SELECT IFEMPTY(field1, 'empty') as field1
from tablename
By trimming and comparing, we ensure we also take care of empty or tab or space character content in the field.
SELECT
CASE
WHEN LTRIM(RTRIM(col_1))='' or col_1 IS NULL THEN 'Not available'
ELSE col_1
END AS col_alias
FROM
my_table
SELECT * FROM (
SELECT 2 AS RTYPE,V.ID AS VTYPE, DATE_FORMAT(ENTDT, ''%d-%m-%Y'') AS ENTDT,V.NAME AS VOUCHERTYPE,VOUCHERNO,ROUND(IF((DR_CR)>0,(DR_CR),0),0) AS DR ,ROUND(IF((DR_CR)<0,(DR_CR)*-1,0),2) AS CR ,ROUND((dr_cr),2) AS BALAMT, IF(d.narr IS NULL OR d.narr='''',t.narration,d.narr) AS NARRATION
FROM trans_m AS t JOIN trans_dtl AS d ON(t.ID=d.TRANSID)
JOIN acc_head L ON(D.ACC_ID=L.ID)
JOIN VOUCHERTYPE_M AS V ON(T.VOUCHERTYPE=V.ID)
WHERE T.CMPID=',COMPANYID,' AND d.ACC_ID=',LEDGERID ,' AND t.entdt>=''',FROMDATE ,''' AND t.entdt<=''',TODATE ,''' ',VTYPE,'
ORDER BY CAST(ENTDT AS DATE)) AS ta
If you would like to check in PHP , then you should do something like :
$query_s =mysql_query("SELECT YOURROWNAME from `YOURTABLENAME` where name = $name");
$ertom=mysql_fetch_array($query_s);
if ('' !== $ertom['YOURROWNAME']) {
//do your action
echo "It was filled";
} else {
echo "it was empty!";
}

JPQL / SQL query: where like '%' include null values

I have a simple JPQL query. (But this applies also to an sql query..)
FROM DomainObj d where d.field1 like 'TEST%' and d.field2 like '%';
If the DB contains the following row:
1) field1 -> 'TEST'; field2 -> null
the query return nothing!
If the DB contains the following values:
2) filed1 -> 'TEST'; field2 -> ''
the query return the row!
How can I include also null values while searching for like '%' keeping the query as simple as possible (avoiding and/or clause?)
I'm implementing searching funcionality of an entity in the db.. and I also search by many fields at the same time..
Thank you
Marco
You can't directly use nulls in equality tests, because null is un-equal to everything, including itself. That's why there's the is null test, e.g:
select null = null -> null
select null <> null -> null
select 1 = null -> null
select 1 <> null -> null
select 1 + null -> null
essentially null is contagious, and will nullify anything it's compared to, or added in to.
So yes, you'll have to do
SELECT ... WHERE somefield LIKE '%...%' or somefield IS NULL
Try this:
...
and IFNULL(d.field2, '') like '%'
...
where ...
and (field2 = '' or field2 is null)
Note that the condition field2 like '%' is nonsensical because it matches any text except null. If you added or field2 is mull to it you would match everything, so logically you should just remove the condition on field2
Use IS NULL:
where d.field1 like 'TEST%' OR d.field2 IS NULL;
FROM DomainObj d where (d.field1 like 'TEST%' or d.field1 IS NULL) and (d.field2 like '%' or d.field2 IS NULL)