If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > DB2 > If logic in WHERE condition inside SQL statement

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 02-21-07, 05:38
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
If logic in WHERE condition inside SQL statement

Hi,

I would like to change where condition in SQL statement according to input value entered in application.

Sample data:
The logic is:
- if there is no 'region_variable' (variable value is '') the SQL should be without REGION condition - so retrieving all data of all regions:
SELECT * FROM DB2ADMIN.TAB WHERE STATUS = 'Y'

- if REGION is 000 or 100 then SQL should be:
SELECT * FROM DB2ADMIN.TAB WHERE STATUS = 'Y' AND REGION IN (:region_variable)

Code:
ID          REGION STATUS
----------- ------ ------
          1 000    Y
          2 100    Y
          3 100    Y
How to write such an SQL to have an if logic in WHERE condition? Can I use CASE in WHERE condition?


Code to create sample:
Code:
CREATE TABLE DB2ADMIN.TAB (ID INT NOT NULL PRIMARY KEY,
 REGION CHAR(3), STATUS CHAR(1));
INSERT INTO DB2ADMIN.TAB VALUES (1,'000','Y'),(2,'100','Y'),(3,'100','Y');
Thanks,
Grofaty

Last edited by grofaty; 02-21-07 at 08:52.
Reply With Quote
  #2 (permalink)  
Old 02-21-07, 06:05
umayer umayer is offline
Registered User
 
Join Date: Dec 2005
Posts: 273
This might work:

SELECT *
FROM DB2ADMIN.TAB
WHERE STATUS = 'Y'
AND REGION =
CASE WHEN :region_variable = '' THEN REGION
ELSE :region_variable
END
;


if region_variable is blanc then the column REGION is compared with itself which is always true unless it is <NULL>.
if there is a value in region_variable then the column is compared to that value.
Reply With Quote
  #3 (permalink)  
Old 02-21-07, 08:56
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
umayer, thanks a lot this works fine if :region_variable has only one value.

One more question: I also have to write such an SQL that more than one value can exist inside :region_variable.

Sample:
SELECT * FROM DB2ADMIN.TAB WHERE STATUS = 'Y' AND REGION IN (:region_variable)

:region_variable is '100', '000' (into application region field user writes: '100', '000' ) so SQL should be:
SELECT * FROM DB2ADMIN.TAB WHERE STATUS = 'Y' AND REGION IN ('100', '000')

How to write such an SQL that :region_variable could have more than one value plus the functionality to have no region at all like in previous sample?

Thanks,
Grofaty
Reply With Quote
  #4 (permalink)  
Old 02-21-07, 09:33
umayer umayer is offline
Registered User
 
Join Date: Dec 2005
Posts: 273
you cant use the IN :region_value in the intended way ( besides using dynamic sql ).

TRANSLATE might be helpful.
...
WHERE STATUS = 'Y'
AND ( :region_variable = '' OR TRANSLATE(:region_variable,'',REGION) ^= :region_variable )


if more than one region is specified, the values must be separated by any character like dash or komma or blanc.
Reply With Quote
  #5 (permalink)  
Old 02-21-07, 11:12
vini_srcna vini_srcna is offline
Registered User
 
Join Date: May 2006
Posts: 82
It can be done using programming logic as well.
If region_variable = ' ' then call without_region and some more logic like that.
In the corresponding Subroutines you can code the respective SQL statements.
Reply With Quote
  #6 (permalink)  
Old 02-21-07, 12:45
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
Quote:
Originally Posted by umayer
you cant use the IN :region_value in the intended way ( besides using dynamic sql ).

TRANSLATE might be helpful.
...
WHERE STATUS = 'Y'
AND ( :region_variable = '' OR TRANSLATE(:region_variable,'',REGION) ^= :region_variable )


if more than one region is specified, the values must be separated by any character like dash or komma or blanc.
Umayer, thank you very much for helping me out.

I have tried your suggestion but I think it is not working well:
If :region_variable is '100,000' then SQL looks like:
Code:
SELECT * FROM DB2ADMIN.TAB
WHERE STATUS = 'Y'
AND ( '100,000' = '' OR TRANSLATE('100,000','',REGION) ^= '100,000');
the result of this SQL is correct.

But any other value alway returns all records which is not correct result.
For example if :region_variable is '100' the SQL looks like:
Code:
SELECT * FROM DB2ADMIN.TAB
WHERE STATUS = 'Y'
AND ( '100' = '' OR TRANSLATE('100','',REGION) ^= '100');
but it does not display only 100 rows, instead all rows from table are returned, which is not what I want.

The same problem is if only '000' is used as :region_variable. But it looks fine if empty variable is used (so '').

So I need some kind of solution that :regional_variable can be:
- empty string, tha is: ''
- value: 100
- value: 000
- value 000, 100 or 100, 000
- or any other more then two values combination.

Any idea?

Thanks,
Grofaty

Last edited by grofaty; 02-21-07 at 12:57.
Reply With Quote
  #7 (permalink)  
Old 02-21-07, 12:49
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
Quote:
Originally Posted by vini_srcna
It can be done using programming logic as well.
The problem is that the program is already written. Our company bought "SQL reporting application" witch only accepts SQL as input and host variables definitions as input fields in web application. So I can't change program, only SQL is allowed to be changed. So I am desperately looking for SQL solution. Thanks for help anyway.
Reply With Quote
  #8 (permalink)  
Old 02-21-07, 13:22
sathyaram_s sathyaram_s is offline
Super Moderator
 
Join Date: Aug 2001
Location: UK
Posts: 4,534
An alternative is to use COALESCE .. Noit much different though ..

Code:
with temp(seqno,ctry,regn) as 
(
values(1,'GB','EU'),
(2,'US','NA'),
(3,'CA','NA')
)
select * 
from temp
where 
 
regn=coalesce(case when :invar='' then cast(null as char(10)) else :invar),regn)
Here when the input variable invar is ''
then the sql will be equivalent of

Code:
with temp(seqno,ctry,regn) as 
(
values(1,'GB','EU'),
(2,'US','NA'),
(3,'CA','NA')
 )
 
 where 
 
 regn=coalesce(cast(null as char(10)),regn)

Here all records will be selected as regn=regn

If you give a value, say NA

then
the SQL will be equivalent of

Code:
 with temp(seqno,ctry,regn) as 
 (
 values(1,'GB','EU'),
 (2,'US','NA'),
 (3,'CA','NA')
  )
 
  where 
 
 regn=coalesce('NA',regn)
Here only NA records will be selected.

I guess this will solve your problem.


If you want ctry also be part of the where clause (ie, you get values for two columns) then the where clause should be :

Code:
ctry=coalesce(case when :invar1='' then cast(null as char(10)) else :invar1),ctry) and
regn=coalesce(case when :invar2='' then cast(null as char(10)) else :invar2),regn)
It doesn't matter if the user enters only one or both values.

If the input value comes from the same source, and this value can be either regn or country then use OR in the where clause.

Code:
ctry=coalesce(case when :invar='' then cast(null as char(10)) else :invar),ctry) OR 
regn=coalesce(case when :invar ='' then cast(null as char(10)) else :invar ),regn)
HTH
Sathyaram
__________________
Visit the new-look IDUG Website , register to gain access to the excellent content.

Last edited by sathyaram_s; 02-21-07 at 13:33.
Reply With Quote
  #9 (permalink)  
Old 02-21-07, 13:52
sathyaram_s sathyaram_s is offline
Super Moderator
 
Join Date: Aug 2001
Location: UK
Posts: 4,534
Sorry grofaty, the following may be an acceptable solution if multiple regions could come in ..

For this solution, you will need a table UDF .. This UDF assumes a comma seperated input list :

Code:
CREATE FUNCTION CSV_TABLE(INLIST VARCHAR(1000))
RETURNS TABLE(LISTVAL CHAR(10))
BEGIN ATOMIC
RETURN
WITH TEMP1(STR1) AS
(
VALUES(REPLACE(INLIST||',''''','''',''))
)
,
TEMP2(STR3,STR4) AS
(
SELECT LEFT(STR1,POSSTR(STR1,',')-1),SUBSTR(STR1,POSSTR(STR1,',')+1) FROM TEMP1
UNION ALL
SELECT LEFT(STR4,POSSTR(STR4,',')-1),SUBSTR(STR4,POSSTR(STR4,',')+1) FROM TEMP2 WHERE LENGTH(STR4)>0
)
SELECT STR3 FROM TEMP2 ;
END
Code:
with temp(seqno,ctry,regn) as 
(
values(1,'GB','EU'),
(2,'US','NA'),
(3,'CA','NA'),
(4,'IN','AP')
)
select * 
from temp
where 
regn in (values(case when :invar='' then regn end )) OR 
regn in (select rgnname from table(csv_table(:invar)) as rgnlist(rgnname))
Or, you can use a CTE instead of the Table UDF

Code:
WITH TEMP1(STR1) AS
(
VALUES(REPLACE(:invar||',''''','''',''))
)
,
TEMP2(rgnname,STR4) AS
(
SELECT LEFT(STR1,POSSTR(STR1,',')-1),SUBSTR(STR1,POSSTR(STR1,',')+1) FROM TEMP1
UNION ALL
SELECT LEFT(STR4,POSSTR(STR4,',')-1),SUBSTR(STR4,POSSTR(STR4,',')+1) FROM TEMP2 WHERE LENGTH(STR4)>0
),
temp(seqno,ctry,regn) as 
(
values(1,'GB','EU'),
(2,'US','NA'),
(3,'CA','NA'),
(4,'IN','AP')
)
select * 
from temp
where 
regn in (values(case when :invar='' then regn end  )) OR 
regn in (select rgnname from temp2 )
HTH

Sathyaram
__________________
Visit the new-look IDUG Website , register to gain access to the excellent content.

Last edited by sathyaram_s; 02-21-07 at 14:01.
Reply With Quote
  #10 (permalink)  
Old 02-21-07, 13:58
n_i n_i is offline
:-)
 
Join Date: Jun 2003
Location: Toronto, Canada
Posts: 4,449
Quote:
Originally Posted by grofaty
The problem is that the program is already written. Our company bought "SQL reporting application" witch only accepts SQL as input and host variables definitions as input fields in web application. So I can't change program, only SQL is allowed to be changed.
For what it's worth, we used a stored procedure that returned a result set in a similar situation. You can implement any complex logic in a stored procedure or use dynamic SQL.
Reply With Quote
  #11 (permalink)  
Old 02-21-07, 14:06
sathyaram_s sathyaram_s is offline
Super Moderator
 
Join Date: Aug 2001
Location: UK
Posts: 4,534
n_i, Will that not mean a change of application code ?

I mean, for example in Java, you use SQL Statement objects and execute them for SQL Statements whereas stored procs use callable stmts ...
Also, I guess the host language stmts for handling SQL resultsets may be different from handling Stored Proc resultsets ..

Cheers
Sathyaram
__________________
Visit the new-look IDUG Website , register to gain access to the excellent content.
Reply With Quote
  #12 (permalink)  
Old 02-21-07, 15:49
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
sathyaram_s, I haven't tested your suggestions yet it looks so complex...

I have one solution but it is not complete:

Code:
SELECT * FROM DB2ADMIN.TAB WHERE STATUS='Y' AND REGION IN (:replace_variable)
UNION ALL
SELECT * FROM DB2ADMIN.TAB WHERE NOT EXISTS
(
SELECT * FROM DB2ADMIN.TAB WHERE STATUS='Y' AND REGION IN (:replace_variable)
)
If :replace_variable is '000' the result is fine.
If :replace_variable is '100' the result is fine.
If :replace_variable is '000','100' the result is fine.
If :replace_variable is '100','000' the result is fine.
If :replace_variable is empty (so '') the result is fine.
The problem is if there is one or all values that does not exist in table. E.g. value '300' or '300','400', etc. If so all the rows from the table are returned instead of no row.

Any idea how to solve this problem? As I see there should be some kind of LENGTH function to solve the problem.

Thanks,
Grofaty

Last edited by grofaty; 02-21-07 at 16:02.
Reply With Quote
  #13 (permalink)  
Old 02-21-07, 16:27
sathyaram_s sathyaram_s is offline
Super Moderator
 
Join Date: Aug 2001
Location: UK
Posts: 4,534
The complexity is my solution is primarily to do with the multi-value requirement ...

I cannot think of a non-recursive solution because you do not know the number of values that come in ...

Also remember, if hostvar is '000','001' then when db2 processes "in (:hostvar) " , it does not consider the value as two separate strings but as one string only ... So effectively, you will be looking for a region with a value '000','001' and NOT region '000' or '001'


Back to the basics, please clarify - what is the replace_variable .. Is it a DB2 host variable or is it a Unix variable - where you just go and find/replace the string with your input values ?

I assume it is a db2 host variable ...

Cheers
Sathyaram
__________________
Visit the new-look IDUG Website , register to gain access to the excellent content.
Reply With Quote
  #14 (permalink)  
Old 02-22-07, 01:40
grofaty grofaty is offline
Registered User
 
Join Date: Jan 2003
Posts: 1,570
sathyaram_s, I have been talking to programmer of this reporting application and application works like this:
- application gets data from host variable and store this variable into memory
- then application concats SQL and result of host variable into one SQL
- SQL is executed

I have tried this out one simple sample and inserting '000','001' into application input field and it works like I have described above. So '000','100' in input field as host_variable it is working well.

Last edited by grofaty; 02-22-07 at 02:45.
Reply With Quote
  #15 (permalink)  
Old 02-22-07, 01:44
umayer umayer is offline
Registered User
 
Join Date: Dec 2005
Posts: 273
@ grofaty

you are right, I muddled up REPLACE and TRANSLATE.

please try:

WHERE STATUS = 'Y'
AND ( :region_variable = '' OR REPLACE(:region_variable,REGION,'') ^= :region_variable )


sorry for my mistake.
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On