where condition based on bind variables - sql

I want a different set where condition to be executed on a query based on a bind variable in Oracle sql .
Here is what I have tried
Table a contains
a_id primary key
a_role varchar2(10)
SELECT *
FROM a
WHERE a_role IN ('approved','rejected' , 'needInfo') AND
:bind = 'new' OR
:bind != 'new AND
a_role IN ('complete') AND
:bind = 'approved' OR
:bind != 'approved'
In short i am trying to select roles based on current role which I will pass in bind variable. I want something like
if(:bind = 'new')
{select 'approved' , 'rejected' , 'needInfo' }
else if (:bind = 'approved')
{ select 'complete' }
Thanks ,
Puneet

You have both AND and OR conditions mixed in your statement, and they may not be interpreted as you wanted. Additionally, it looks like the two comparisons to a_role should be OR'd together rathen than AND'd. Try the following:
SELECT *
FROM a
WHERE (:bind = 'new' AND
(a_role IN ('approved','rejected' , 'needInfo')) OR
(:bind = 'approved' AND
a_role IN ('complete'))
Share and enjoy.

I can't be certain because I'm not clear what your original query is trying to do - but it should be something like this, assuming your running in sqlPlus:
variable bind varchar2
bind := 'new'
SELECT *
FROM a
WHERE (:bind = 'new' AND a_role IN ('approved','rejected' , 'needInfo'))
OR (:bind = 'approved' AND a_role IN ('complete'))
This article explains thins fairly neatly

Related

Display a formatted version of a returned query value

I am trying to figure out the best way to go about a problem I'm having with our Database. I don't have the option to go back and change the architecture, and so I am stuck trying to figure out a workaround.
Table 1:
User => Column MailingCountry = Either (en-Country(en-US), Country (US), or Null)
Table 3:
SMSCode => Column CountryCode = en-Country (en-US), Column SMSCode = Code (1 for US).
I'd like to know if there is a way that I could:
Get the User.MailingCountry and check if it is in the format of 'en-US', 'US' or 'NULL'
If it is in 'en-US' we are good, if it is in 'US', I'd like to replace it in the returned results to 'en-US', and if it is 'NULL', id like it to default to 'en-US'.
Inner JOIN with SMS.CountryCode where User.MailingCountry = SMS.CountryCode and then retrieve the SMSCode.
I guess the problem is, I am not sure how I can do something like
Select m.MailingCountry, a.SMSCode FROM User m->
IF (m.MailingCountry = 'US' or m.MailingCountry is null) Then m.MailingCountry = 'en-US'
Inner Join SMSCode a on a.CountryCode = m.MailingCountry
You can go for below query:
SELECT SMS.SMSCode
FROM
(SELECT CASE WHEN MailingCountry like '%US%' OR MailingCountry IS NULL THEN 'en-US'
ELSE MailingCountry END AS MailingCountry
FROM User) AS u
INNER JOIN SMSCode AS SMS
ON SMS.CountryCode = u.MailingCountry

Query column created in CASE statement just before - "column does not exist"

I have this code:
CASE WHEN url LIKE 'utm_medium'
THEN
SPLIT_PART( -- slice UTM from URL
SPLIT_PART(pageviews.url,'utm_medium=',2)
,'&',1
)
ELSE NULL END AS utm_medium,
CASE
WHEN utm_medium = 'paidsocial'
THEN channel = 'Paid Social'
WHEN utm_medium = 'email'
THEN channel = 'Email'
END
In the first CASE, I extract utm_medium param from URL as utm_medium column, and in second CASE I'd like to create another column channel based on utm_medium value.
I'm getting error:
column "utm_medium" does not exist
LINE 153: WHEN utm_medium = 'paidsocial'
Is it possible to query utm_medium column just after it is created?
split_part() suggests Postgres, which supports lateral joins. These allow you to define aliases in the FROM clause without using subqueries or CTEs. That would be:
SELECT pv.*, v.utm_medium,
(CASE WHEN utm_medium = 'paidsocial' THEN channel = 'Paid Social'
WHEN utm_medium = 'email' THEN channel = 'Email'
END)
FROM pageviews pv CROSS JOIN LATERAL
(VALUES (CASE WHEN url LIKE 'utm_medium'
THEN SPLIT_PART(SPLIT_PART(pv.url, 'utm_medium=', 2
), '&', 1
)
)
) v(utm_medium)
Is it possible to query utm_medium column just after it is created?
Most likely not.
Some engines may support this non standard SQL feature you want. You don't mention which database you are using, so it's not clear.
The general solution for this is to produce a bona fide column with the name you want using a table expression or a CTE.
For example:
select
col1,
col2,
CASE
WHEN utm_medium = 'paidsocial'
THEN channel = 'Paid Social'
WHEN utm_medium = 'email'
THEN channel = 'Email'
END
from (
select
col1,
col2,
CASE WHEN url LIKE 'utm_medium'
THEN
SPLIT_PART( -- slice UTM from URL
SPLIT_PART(pageviews.url,'utm_medium=',2)
,'&',1
)
ELSE NULL
END AS utm_medium
from my_table
) x
This example will run on virtually all databases. As you see a table expression x was used in the FROM clause, effectively defining a column called utm_medium in it. Then, the main query can simply use this column right away.

How to use IF statement inside WITH?

Wasn't able to find a proper example of this (or maybe I am simply looking in wrong direction).
Depending on incoming parameter value I need to change WHERE condition for SELECT.
For example, I got parameter #bookType with value 'All' and I need to make something like this:
IF #bookType = 'All'
SELECT * FROM tBooks
WHERE BookType != 'Template' AND BookGroup='Library'
ELSE
SELECT * FROM tBooks
WHERE BookType = #bookType AND BookStatus=#bookStatus
Seems simple, but I need this IF inside WITH:
WITH Books AS (
IF...
...
), bookIds AS (
...
...
)
And this is not working because I am starting to receive 'Incorrect syntax near IF'. What exactly I am doing wrong? Or maybe it is possible to hide this IF inside WHERE statement (change where depending on parameter value)?
;
WITH Books AS (
SELECT * FROM tBooks
WHERE
(#BookType = 'All' AND BookType != 'Template' AND BookGroup='Library')
OR
(#BookType <> 'All' AND BookType = #bookType AND BookStatus=#bookStatus)
)

SQL Subquery to replace all values

I have a query which returns a bunch of different data, however I want to have it replace all the values upon a certain condition.
What I have written below kind of gives me the result I want but not really. It creates a new column instead of replacing the other one:
SELECT
CASE
WHEN T4.[U_DestType] = '6'
THEN (SELECT
'Company Limited' AS [ShipToCode]
)
END AS [ShipToCode],
T2.[ShipToCode],
T6.[StreetS],
T6.[StreetNoS],
T6.[CityS],
T6.[ZipCodeS],
T6.[CountryS],
T5.[LicTradNum],
T2.[CardCode],
T4.[Phone1],
T4.[E_Mail],
T4.[U_DestType],
CASE
WHEN T4.[Country] = 'GB'
THEN 'EN'
ELSE T4.[Country]
END AS [Country],
T4.[U_ShortName]
FROM[...]
The end goal is to replace all of the columns with some preset values instead of just ShipToCode as above.
I tried putting an EXIST subquery after FROM too but that didn't work either.
Is this possible? I'm probably missing something very obvious.
Many thanks!
You can use an ELSE in your CASE expression to combine the two "columns":
CASE
WHEN T4.[U_DestType] = '6'
THEN (SELECT
'Company Limited' AS [ShipToCode]
)
ELSE T2.[ShipToCode]
END AS [ShipToCode],
And by the way, you didn't need to use a Sub-Select. This would work just as well and is easier to read:
CASE
WHEN T4.[U_DestType] = '6' THEN 'Company Limited'
ELSE T2.[ShipToCode]
END AS [ShipToCode],

change where condition based on column value

I faced the following requirement. The following query is called by a procedure. The value p_pac_code is the input parameter of the procedure.
The requirement is the query should have an additional condition sp_sbsp.SUBSPCLTY_CODE!='C430 if the p_pac_code value is '008'.
For any other p_pac_code value, it should run as it is below. Is there way to do this by adding an additional condition in the WHERE clause?
As for now, I have done this using IF.....ELSE using the query two times separately depending on p_pac_code value. But I am required to find a way to do with just adding a condition to this single query.
SELECT ptg.group_cid
FROM PRVDR_TYPE_X_SPCLTY_SUBSPCLTY ptxss,
PT_X_SP_SSP_STATUS pxsst ,
pt_sp_ssp_x_group ptg,
group_x_group_store gg,
specialty_subspecialty sp_sbsp,
treatment_type tt,
provider_type pt
WHERE
pt.PRVDR_TYPE_CODE = ptxss.PRVDR_TYPE_CODE
AND tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE
AND ptxss.PRVDR_TYPE_X_SPCLTY_SID = pxsst.PRVDR_TYPE_X_SPCLTY_SID
AND tt.TRTMNT_TYPE_CODE = p_pac_code
AND TRUNC(SYSDATE) BETWEEN TRUNC(PXSST.FROM_DATE) AND TRUNC(PXSST.TO_DATE)
AND ptg.prvdr_type_code =ptxss.prvdr_type_code
AND ptg.spclty_subspclty_sid = ptxss.spclty_subspclty_sid
AND ptxss.spclty_subspclty_sid = sp_sbsp.spclty_subspclty_sid
AND ptg.spclty_subspclty_sid = sp_sbsp.spclty_subspclty_sid
AND ptg.status_cid = 2
AND ptg.group_cid = gg.group_cid
AND gg.group_store_cid = 16
AND gg.status_cid = 2;
Thanks in advance.
You can simply add a condition like this:
... and (
( sp_sbsp.SUBSPCLTY_CODE!='C430' and p_pac_code = '008')
OR
NVL(p_pac_code, '-') != '008'
)
This can be re-written in different ways, this one is quite self-explanatory
Just add:
AND NOT ( NVL( sp_sbsp.SUBSPCLTY_CODE, 'x' ) = 'C430'
AND NVL( p_pac_code value, 'x' ) = '008' )
to the where clause.
The NVL function is used so that it will match NULL values (if they exist in your data); otherwise, even though NULL does not match C430 you will still find that NULL = 'C430' and NULL <> 'C430' and NOT( NULL = 'C430' ) will all return false.
Quite easy. Add the following condition:
AND (sp_sbsp.SUBSPCLTY_CODE != 'C430' OR p_pac_code value != '008')
(don't forget the parenthesis)
Just sharing
SELECT ptg.group_cid
FROM PRVDR_TYPE_X_SPCLTY_SUBSPCLTY ptxss
WHERE
pt.PRVDR_TYPE_CODE = ptxss.PRVDR_TYPE_CODE
&&((tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE)
or (tt.TRTMNT_TYPE_CODE = pxsst.TRTMNT_TYPE_CODE))
just use the parenthesis to specify where the conditionmust implement.