how to set a null value to default in oracle sql - 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;

Related

SELECT INTO do not store null in to the variables

I was trying to check the values from the two tables, and I only want to proceed to the next query only if the value is found in TableA. There is something wrong in the below logic, also when there is not data, it goes to exception instead of storing NULL into the variables.
SET SERVEROUTPUT ON;
SET FEEDBACK OFF;
SPOOL temp.txt;
DECLARE
v_ATM TableA.CODE%TYPE := NULL;
v_TBL TableB.CODE%TYPE := NULL;
BEGIN
SELECT TableA.CODE, TableB.CODE INTO v_ATM,v_TBL FROM TableA LEFT JOIN TableB ON TableA.CODE = TableB.CODE WHERE TableA.CODE = 'ABC';
IF (v_ATM IS NULL) AND (v_TBL IS NULL) THEN
DBMS_OUTPUT.PUT_LINE('No value found');
ELSIF (v_ATM IS NOT NULL) AND (v_TBL IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE('Found in both');
ELSIF (v_ATM IS NULL) AND (v_TBL IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE('Found in Table B');
ELSIF (v_ATM IS NOT NULL) AND (v_TBL IS NULL) THEN
DBMS_OUTPUT.PUT_LINE('Found in Table A');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Exception');
END;
Alternately I was trying:
SELECT TableA.CODE INTO v_ATM FROM TableA WHERE TableA.CODE = 'ABC';
SELECT TableB.CODE INTO v_TBL FROM TableB WHERE TableB.CODE = 'ABC';
but still, v_ATM does not store NULL if ABC is not found, and goes to exception.
--instead of selcting code col to get null/not null, select count(1) to get either 0/1 as output w/o errors
with
TableA as (
--select 'ABC' as code from dual
--union all
select 'DEF' as code from dual
),
TableB as (
--select 'ABC' as code from dual
--union all
select 'DEF' as code from dual
),
q1 as (
SELECT 1 as id, count(1) as cnt FROM TableA WHERE TableA.CODE = 'ABC'
),
q2 as (
SELECT 1 as id, count(1) as cnt FROM TableB WHERE TableB.CODE = 'ABC'
)
select
cast(
case
when q1.cnt = 0 and q2.cnt = 0 then 'Both missing'
when q1.cnt = 1 and q2.cnt = 0 then 'TableA present, TableB missing'
when q1.cnt = 0 and q2.cnt = 1 then 'TableA missing, TableB present'
when q1.cnt = 1 and q2.cnt = 1 then 'Both present'
else 'NA'
end as varchar2(40)) as output_txt
from q1 inner join q2 on (q1.id = q2.id)
;
Play with the sql by hiding ABC and DEF and union all lines of code as desired to get different outputs for different conditions.
You're selecting from a row, not a scalar value so if there is no row there is no value.
If you SELECT MAX(TableA.CODE) ... WHERE ...
You will get a value to use

Oracle SQL ternary operator or function?

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

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 can I have multiple CASE in select statements in PL/SQL function?

I'm trying to write a function that has 2 case statements. For background, a user can have either an A, B, or both A and B (but on separate lines, which is why I can't use a single case statement, unless I use LISTAGG, which I was told not to do for this.
Sample Data:
User State
1 A
1 B
2 A
3 B
SQL
CREATE OR REPLACE Function F_Calc_State(code Varchar2, id Number, time varchar2) Return Varchar2 AS
Calc_State(10) := null;
l_A varchar2(10) := null;
l_B varchar2(10) := null;
BEGIN
SELECT CASE WHEN state = 'A' THEN 'A'
ELSE null
END into l_A,
CASE WHEN state = 'B' THEN 'B'
ELSE null
END into l_B
FROM TABLE1
WHERE state in ('A', 'B')
AND TABLE1_CODE = code
AND TABLE1_ID = id
AND TABLE1_TIME = time;
CASE WHEN l_A = 'A' and l_B = 'B' then 'AB'
WHEN l_A = 'A' THEN 'A'
WHEN 1_B = 'B' THEN 'B'
ELSE stafford_recip_ind :='NEITHER';
END CASE;
RETURN Calc_State;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'NO DATA';
WHEN OTHERS THEN
RETURN SQLERRM ;
END F_Calc_State;`
For wanted results, when I enter user 1, I want AB to be returned, for user 2 = A, and user 3 = B. I also tried having two different select statement blocks but couldn't get that to work either, it would just hit the exception handler for some reason. Thanks!
The following code would return NULL if no data is found:
CREATE OR REPLACE Function F_Calc_State (
in_code Varchar2,
in_id Number,
in_time varchar2 -- "time" as a string is highly suspicious
) Return Varchar2
AS
v_ab varchar2(10) := null;
BEGIN
SELECT MAX(CASE WHEN t1.state = 'A' THEN 'A' END) ||
MAX(CASE WHEN t1.state = 'B' THEN 'B' END)
INTO v_AB
FROM TABLE1 t1
WHERE t1.state in ('A', 'B') AND
t1.TABLE1_CODE = in_code AND
t1.TABLE1_ID = in_id AND
t1.TABLE1_TIME = in_time;
RETURN(v_ab);
END; -- F_Calc_State
However, this does not return return an error if no data is found.
CREATE OR REPLACE Function F_Calc_State (
in_code Varchar2,
in_id Number,
in_time varchar2 -- "time" as a string is highly suspicious
) Return Varchar2
AS
v_ab varchar2(10) := null;
BEGIN
SELECT MAX(CASE WHEN t1.state = 'A' THEN 'A' END) ||
MAX(CASE WHEN t1.state = 'B' THEN 'B' END)
INTO v_AB
FROM TABLE1 t1
WHERE t1.state in ('A', 'B') AND
t1.TABLE1_CODE = in_code AND
t1.TABLE1_ID = in_id AND
t1.TABLE1_TIME = in_time;
GROUP BY t1.TABLE1_CODE; -- this will return no rows if there are no matches
RETURN(v_ab);
EXCEPTION
WHEN NO_DATA_FOUND THEN RETURN 'NO DATA';
WHEN OTHERS THEN RETURN SQLERRM ;
END; -- F_Calc_State
A very trivial approach could be this:
It's not clear if you want to check for existance of records or not, as in your exception block you return "NO DATA" while in your case statement you have the value "NEITHER".. anyway, you can adjust this accordingly:
CREATE OR REPLACE Function F_Calc_State( code varchar2
, id number
, time varchar2
) return varchar2
as
l_count_a number;
l_count_b number;
l_result varchar2(10);
begin
select count(*)
into l_count_a
from table1
where state = 'A'
and table1_code = id
and table1_time = time;
select count(*)
into l_count_b
from table1
where state = 'B'
and table1_code = id
and table1_time = time;
if l_count_a = 0 and l_count_b = 0 then l_result := 'NEITHER';
elsif l_count_a > 0 and l_count_b = 0 then l_result := 'A';
elsif l_count_a = 0 and l_count_b > 0 then l_result := 'B';
elsif l_count_a > 0 and l_count_b > 0 then l_result := 'AB';
else l_result := '';
end if;
return l_result;
end F_Calc_State;
Use below code, Now you will get only a single row of result.
SELECT MAX(CASE WHEN state = 'A' THEN 'A'
ELSE null END),
MAX(CASE WHEN state = 'B' THEN 'B'
ELSE null END)
INTO l_A, l_B
FROM TABLE1
WHERE state in ('A', 'B')
AND TABLE1_CODE = code
AND TABLE1_ID = id
AND TABLE1_TIME = time;

Oracle sql return true if exists question

How do I check if a particular element exists in a table - how can I return true or false?
I have a table that has
user_id
user_password
user_secretQ
Verbally, I want to do this: If a particular user_id exists in the user_id column, then return true -- otherwise return false.
There is no Boolean type in Oracle SQL. You will need to return a 1 or 0, or some such and act accordingly:
SELECT CASE WHEN MAX(user_id) IS NULL THEN 'NO' ELSE 'YES' END User_exists
FROM user_id_table
WHERE user_id = 'some_user';
In PL/SQL you can do this:
function user_exists (p_user_id users.user_id%type) return boolean
is
l_count integer;
begin
select count(*)
into l_count
from users
where user_id = p_user_id;
return (l_count > 0);
end;
This would then be used in calling PL/SQL like this:
if user_exists('john') then
dbms_output.put_Line('John exists');
end if;
NOTE: I used count(*) in the query in the knowledge that this will only return 1 or 0 in the case of a primary key search. If there could be more than one row then I would add "and rownum = 1" to the query to prevent unnecessarily counting many records just to find out if any exists:
function user_has_messages (p_user_id users.user_id%type) return boolean
is
l_count integer;
begin
select count(*)
into l_count
from messages
where user_id = p_user_id
AND ROWNUM = 1;
return (l_count > 0);
end;
Oracle RDBMS does not have boolean data type, you can only use boolean variables in PL/SQL.
If you simply want to return strings 'TRUE' and 'FALSE'
you can do this..
SELECT 'TRUE' FROM DUAL WHERE EXISTS (SELECT 'x' FROM table WHERE user_id = 'id')
UNION
SELECT 'FALSE' FROM DUAL WHERE NOT EXISTS (SELECT 'x' FROM table WHERE user_id = 'id')
I like #DCookie's query though.
select count(*) from table where userid = :userid and rownum <= 1); -- If exists then 1 else 0
Or you could do this:
select decode(max(USER_ID), null, 'FALSE', 'TRUE') BOOL_VAL
from USER_TABLE where USER_ID = [some USER_ID here]