Oracle SQL ternary operator or function? - sql

Is there a simple Oracle syntax like a ternary operator or function?
These work:
with
function qry(v in varchar2) return varchar2 is
begin
return owa_util.ite(v like ('%' || lower('something') || '%'),'Y','N');
end;
select * from my_table where qry(my_col) = 'Y'
with
function qry(v in varchar2) return varchar2 is
begin
return case when v like('%' || lower('something') || '%') then 'Y' else 'N' end;
end;
select * from my_table where qry(my_col) = 'Y'
If there's a simpler, shorter syntax I would like to know.

You can use a CASE expression with LIKE:
SELECT *
FROM my_table
WHERE CASE WHEN my_col LIKE '%something%' THEN 'Y' ELSE 'N' END = 'Y';
or DECODE and INSTR:
SELECT *
FROM my_table
WHERE DECODE( INSTR( my_col, 'something' ), 0, 'N', 'Y' ) = 'Y';
or just simply use LIKE:
SELECT *
FROM my_table
WHERE my_col LIKE '%something%';
INSTR:
SELECT *
FROM my_table
WHERE INSTR( my_col, 'something' ) > 0;
or REGEXP_LIKE:
SELECT *
FROM my_table
WHERE REGEXP_LIKE( my_col, 'something' );
db<>fiddle here

Related

How to take where clause conditions from table column in oracle SQL or plsql

How to take where clause conditions from table column in oracle plsql.
E.g. data in table
Condition
1.sourceSystemId = 'SN'
2.AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
e.g query:
select * from xyz where rule='abc' and "sourceSystemId = 'SN'"
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
Not entirely sure what you're asking here, but I would imagine that
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
would become
select * from xyz
where rule='abc'
AND coverageType='AD'
and amountType1='PREMIUM'
and premiumFrequency='REGULAR'
and yearOfPremium='1'
I suppose you want something like :
DECLARE
l_query VARCHAR2(2000) := 'select * from xyz where rule=''abc''';
l_result xyz%ROWTYPE;
l_cursor SYS_REFCURSOR;
BEGIN
dbms_output.put_line(l_query);
FOR clause IN (SELECT condition
FROM conditions)
LOOP
l_query := l_query||' AND '||clause.condition;
END LOOP;
OPEN l_cursor FOR l_query;
LOOP
FETCH l_cursor INTO l_result;
EXIT WHEN l_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE l_cursor;
END;
Here is example of SQL solution. I used justt first and last condition but you can get them all...
WITH
xyz As
(
Select 1 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
UNION
Select 2 "ID", 'abc' "RULE", 'BF' "COVERAGETYPE", 'ORDINARY' "AMOUNTTYPE1", 'EXTRA' "PREMIUMFREQUENCY", '2' "YEAROFPREMIUM" From Dual
UNION
Select 3 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
),
conditions As
(
SELECT UPPER('coverageType=AD,amountType1=PREMIUM,premiumFrequency=REGULAR,yearOfPremium=1') "CND" From Dual
)
SELECT
x.ID, x.RULE, x.COVERAGETYPE, x.AMOUNTTYPE1, x.PREMIUMFREQUENCY, x.YEAROFPREMIUM
FROM
xyz x
INNER JOIN
conditions c ON(1=1)
WHERE
x.RULE = 'abc' And
x.COVERAGETYPE = CASE WHEN InStr(c.CND || ',', 'COVERAGETYPE=') = 0 THEN x.COVERAGETYPE
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=') + 1), ',')) END And
x.YEAROFPREMIUM = CASE WHEN InStr(c.CND || ',', 'YEAROFPREMIUM=') = 0 THEN x.YEAROFPREMIUM
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=') + 1), ',')) END
Result:
ID RULE COVERAGETYPE AMOUNTTYPE1 PREMIUMFREQUENCY YEAROFPREMIUM
1 abc AD PREMIUM REGULAR 1
3 abc AD PREMIUM REGULAR 1

One query or another depending on the schema the code is in

I have the below 2 queries:
SELECT * from mytable;
SELECT * from mytable where rownum < 100;
I would like to execute the first one whenever my schema equals 'SCHEMA1' and the second one otherwise. Is there a way to do this without having to rewrite both queries like this:
DECLARE
myschema VARCHAR2(50);
BEGIN
SELECT
sys_context('userenv', 'current_schema')
|| 's'
INTO myschema
FROM
dual;
IF myschema = 'SCHEMA1' THEN
INSERT INTO myothertable
SELECT
*
FROM
mytable;
ELSE
INSERT INTO myothertable
SELECT
*
FROM
mytable
WHERE
ROWNUM < 100;
END IF;
END;
I would also like to avoid dynamic PLSQL.
I would write it this way:
DECLARE
MYSCHEMA VARCHAR2(128) := SYS_CONTEXT('userenv', 'current_schema');
BEGIN
INSERT INTO myothertable
SELECT *
FROM mytable
WHERE ROWNUM < CASE WHEN MYSCHEMA = 'SCHEMA1' THEN 100
ELSE ROWNUM + 1
END;
END;
/

SQL query with dynamic columns and dynamic data

My query.
INSERT INTO TARGET_TABLE (SELECT DATA FROM TABLE_DATA WHERE TYPE = 'HEADER') VALUES
(SELECT DATA FROM TABLE_DATA WHERE TYPE = 'ITEMS')
In this query I am trying to insert data into TARGET_TABLE.
TABLE_DATA will have data in the below format
SELECT DATA FROM TABLE_DATA WHERE TYPE = 'HEADER'
Result COUNTRY,ID,NAME
SELECT DATA FROM TABLE_DATA WHERE TYPE = 'ITEMS'
Result 'IN','123','xyz'
So I am expecting the below
INSERT INTO TARGET_TABLE (COUNTRY,ID,NAME) VALUES ('IN','123','xyz')
Any thoughts on this?
select case is what you need
INSERT INTO TARGET_TABLE
(SELECT case when type='HEADER' then COL1 else 'aa' END
,case when type='HEADER' then COL2 else 'bb' END
,case when type='HEADER' then COL3 else 'cc' END
,case when type='HEADER' then COL4 else 'dd' END
FROM TABLE_DATA )
You need to use a dynamic query like the following:
BEGIN
EXECUTE IMMEDIATE
'INSERT INTO TARGET_TABLE ( '
|| SELECT DATA FROM TABLE_DATA WHERE TYPE = 'HEADER'
|| ') VALUES ('
|| SELECT DATA FROM TABLE_DATA WHERE TYPE = 'ITEMS'
|| ')';
END;
/
Cheers!!

How to UPDATE by using REPLACE on different patterns within the same column value in Oracle?

Here is a sample data of what I have in my table FOO -
CREATE TABLE FOO
(
NUMBERS VARCHAR2(4000 CHAR)
);
INSERT INTO FOO VALUES ('One,Five,Seven');
INSERT INTO FOO VALUES ('One,Two,Three');
INSERT INTO FOO VALUES ('Five,Five,Seven');
INSERT INTO FOO VALUES ('Zero,Five,Seven');
/* .
.
.
and so on.. */
SELECT * FROM FOO;
I want to write an update statement to replace the text by their respective number. So the output should be like -
Here is one way. It's silly, but then so is the problem, so I don't feel too bad. It does work.
update foo
set numbers = (select listagg(decode(token,'Zero',0,'One',1,'Two',2,'Three',3,
'Four',4,'Five',5,'Six',6,'Seven',7,'Eight',8,'Nine',9)
, ',') within group (order by ord)
from json_table('["' || replace(numbers, ',', '","') || '"]',
'$[*]'
columns token varchar2 path '$',
ord for ordinality)
)
;
select * from foo;
NUMBERS
--------------------
1,5,7
1,2,3
5,5,7
0,5,7
Here is an even sillier hack (still correct - it should work in Oracle 12.1 and higher). It's more interesting as an illustration of what's possible.
update /*+ with_plsql */ foo
set numbers = (
with
function list_replace(str varchar2) return varchar2 as
p integer := instr(str,',');
function single_replace(token varchar2) return varchar2 as
begin
return case token when 'Zero' then '0' when 'One' then '1'
when 'Two' then '2' when 'Three' then '3'
when 'Four' then '4' when 'Five' then '5'
when 'Six' then '6' when 'Seven' then '7'
when 'Eight' then '8' when 'Nine' then '9' end;
end single_replace;
begin
return case p when 0 then single_replace(str)
else single_replace(substr(str,1,p-1)) || ',' ||
list_replace(substr(str,p+1)) end;
end list_replace;
select list_replace(numbers) from dual
)
/

how to set a null value to default in oracle sql

How do I set an empty set or null value to a default value like 1?
So far, I have this statement, but in case I get null values i want to handle that:
select case when count(*)=0
then 0
else 1
end OUTPUT
from TESTTBL
where timestamp = to_char(sysdate-1, 'yyyymmdd')||'0000';
Do you mean to check for Null value and set as some default, if so
select nvl(column_name,'DEFAULT') from TESTBL where timestamp = to_char(sysdate-1, 'yyyymmdd')||'0000';
SELECT CASE WHEN EXISTS
( SELECT *
FROM TESTTBL
WHERE timestamp = to_char(sysdate-1, 'yyyymmdd') || '0000'
)
THEN 1
ELSE 0
END AS OUTPUT
FROM dual
EDIT
Added FROM dual as Oracle does not allow SELECT without FROM clause.
Here you go
SELECT DECODE(count(*),0,0,
1) OUTPUT
FROM TESTTBL
WHERE TIMESTAMP = TO_CHAR(SYSDATE-1, 'yyyymmdd')||'0000';
Use Decode like
SELECT supplier_name,
decode(supplier_id, 10000, 'Google',
10001, 'Microsoft'
'Sony') result
FROM suppliers;
equivalent to
IF supplier_id = 10000 THEN
result := 'Google';
ELSIF supplier_id = 10001 THEN
result := 'Microsoft';
ELSE
result := 'Sony';
END IF;
Or Use coalesce
SELECT coalesce( address1, address2) result
FROM suppliers;
which is equivalent to
IF address1 is not null THEN
result := address1;
ELSIF address2 is not null THEN
result := address2;
ELSE
result := null;
END IF;