This are few records that I want to have sum of but excluding columns with NULL values:
ID val1 val2 val3
1 1 2
2 0 3
3 2 4
select
sum(val1),
sum(val2),
sum(val3)
from table
will result in:
val1 val2 val3
3 9
but I would prefer to see:
val2 val3
3 9
Is there anyway to achive that in SQL or PL/SQL?
kind regards
Sample data:
SQL> select * from test;
ID VAL1 VAL2 VAL3
---------- ---------- ---------- ----------
1 1 2
2 0 3
3 2 4
In my opinion, this is just fine:
SQL> select sum(val1), sum(val2), sum(val3) from test;
SUM(VAL1) SUM(VAL2) SUM(VAL3)
---------- ---------- ----------
3 9
SQL>
Why? Because what you prefer requires some programming and that doesn't have to be simple. Your example is simple, so something like this is easy as there are 6 possible combinations:
SQL> create or replace function f_test return sys_refcursor
2 is
3 l_sum1 number;
4 l_sum2 number;
5 l_sum3 number;
6 rc sys_refcursor;
7 begin
8 select sum(val1), sum(val2), sum(val3)
9 into l_sum1 , l_sum2 , l_sum3
10 from test;
11
12 if l_sum1 is null and l_sum2 is null and l_sum3 is null then
13 open rc for select null from dual;
14 elsif l_sum1 is null and l_sum2 is null then
15 open rc for select l_sum3 from dual;
16 elsif l_sum1 is null and l_sum3 is null then
17 open rc for select l_sum2 from dual;
18 elsif l_sum2 is null and l_sum3 is null then
19 open rc for select l_sum1 from dual;
20 elsif l_sum1 is null then
21 open rc for select l_sum2, l_sum3 from dual;
22 elsif l_sum2 is null then
23 open rc for select l_sum1, l_sum3 from dual;
24 elsif l_sum3 is null then
25 open rc for select l_sum1, l_sum2 from dual;
26 end if;
27 return rc;
28 end;
29 /
Function created.
SQL>
Testing:
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
:B2 :B1
---------- ----------
3 9
SQL> update test set val3 = null;
3 rows updated.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
:B1
----------
3
In a more complex situation, with more columns, such an approach would be close to suicide so you'd have to do that differently, use dynamic SQL which makes things not that easy, so the question is: is it worth it? I don't think so.
Related
Column
aaa-xyz-bbb
xyz-mmm-ooo
aaa-ttt-eee
How to achieve this in Oracle sql
Out put
xyz
xyz
Null
One option is to use instr function:
Sample data:
SQL> with test (col) as
2 (select 'aaa-xyz-bbb' from dual union all
3 select 'xyz-mmm-ooo' from dual union all
4 select 'aaa-ttt-eee' from dual
5 )
Query:
6 select col,
7 case when instr('-' || col || '-', '-xyz-') > 0 then 'xyz'
8 else 'Null'
9 end result
10 from test;
COL RESULT
----------- ----------
aaa-xyz-bbb xyz
xyz-mmm-ooo xyz
aaa-ttt-eee Null
SQL>
I will try to explain this the best that I can, I have an array of products ['VALUE1','VALUE2']
my table has this data as an example
lets say the values are
product_id
order_qty
VALUE1
5
VALUE2
3
How can I build a select statement to check the table if product_id equals VALUE1 and VALUE2 but if the array contains VALUE3 it returns false else it's true I know using a function would be better.
This is how I understood it.
SQL> set serveroutput on;
Sample table:
SQL> select * from product;
PRODUC ORDER_QTY
------ ----------
VALUE1 5
VALUE2 3
PL/SQL code; it intersects values from the table with contents of collection. If that result is equal to number of values in collection, result is TRUE:
SQL> declare
2 l_arr sys.odcivarchar2list := sys.odcivarchar2list();
3 l_cnt number;
4 begin
5 l_arr.extend;
6 l_arr(1) := 'VALUE1';
7 l_arr.extend;
8 l_arr(2) := 'VALUE2';
9
10 select count(*)
11 into l_cnt
12 from (select product_id from product
13 intersect
14 select column_value
15 from table(l_arr)
16 );
17 dbms_output.put_line(l_cnt);
18 if l_cnt = l_arr.count then
19 dbms_output.put_line('Result is TRUE');
20 else
21 dbms_output.put_line('Result is FALSE');
22 end if;
23 end;
24 /
2
Result is TRUE
PL/SQL procedure successfully completed.
What if we add VALUE3 to collection? Result is then FALSE.
SQL> declare
2 l_arr sys.odcivarchar2list := sys.odcivarchar2list();
3 l_cnt number;
4 begin
5 l_arr.extend;
6 l_arr(1) := 'VALUE1';
7 l_arr.extend;
8 l_arr(2) := 'VALUE2';
9 l_arr.extend;
10 l_arr(3) := 'VALUE3';
11
12 select count(*)
13 into l_cnt
14 from (select product_id from product
15 intersect
16 select column_value
17 from table(l_arr)
18 );
19 if l_cnt = l_arr.count then
20 dbms_output.put_line('Result is TRUE');
21 else
22 dbms_output.put_line('Result is FALSE');
23 end if;
24 end;
25 /
Result is FALSE
PL/SQL procedure successfully completed.
SQL>
SELECT
CASE WHEN
COUNT(CASE WHEN PRODUCT_ID IN ('VALUE1','VALUE2') THEN 1 END) = COUNT(*)
THEN 'TRUE' ELSE 'FALSE'
END CHK
FROM T;
or you can just compare collections (NESTED TABLE):
create table t_product as
select 'VALUE1' product_id from dual union all
select 'VALUE2' product_id from dual union all
select 'VALUE3' product_id from dual;
declare
type string_table is table of t_product.product_id%type;
arr_input string_table:=string_table('VALUE1','VALUE2');
tab_data string_table;
begin
select product_id bulk collect into tab_data from t_product;
if tab_data = arr_input
then
dbms_output.put_line('yes');
else
dbms_output.put_line('no');
end if;
end;
/
Or:
select
case
when sys.ku$_vcnt('VALUE1','VALUE2') = X
then 'true'
else 'false'
end chk
from (select cast(collect(cast(product_id as varchar2(4000))) as sys.ku$_vcnt) x from t_product);
NB: it's better to create and use own type instead of sys.ku$_vcnt, for example:
create or replace type varchar2_table as table of varchar2(4000);
I don't know what is best solution for my problem. I need function with one parameter which resault is
VAL
-----
1
2
3
In function I need put union all to get all value.
Select column_1 as VAL from my_table where id = P_FUNCTION_PARAMETER --return 1
union all
Select column_2 as VAL from my_table where id = P_FUNCTION_PARAMETER --return 2
union all
Select column_3 as VAL from my_table where id = P_FUNCTION_PARAMETER; --return 3
What is the best solution for this?
"Best" just depends. Return a ref cursor or a collection, whichever you prefer.
For example:
SQL> create or replace function f_test_rc
2 return sys_refcursor
3 is
4 rc sys_refcursor;
5 begin
6 open rc for
7 select 1 from dual union all
8 select 2 from dual union all
9 select 3 from dual;
10
11 return rc;
12 end;
13 /
Function created.
SQL> select f_test_rc from dual;
F_TEST_RC
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
1
----------
1
2
3
SQL> create or replace function f_test_coll
2 return sys.odcinumberlist
3 as
4 l_coll sys.odcinumberlist;
5 begin
6 select * bulk collect into l_coll
7 from (select 1 from dual union all
8 select 2 from dual union all
9 select 3 from dual
10 );
11
12 return l_coll;
13 end;
14 /
Function created.
SQL> select * from table(f_test_coll);
COLUMN_VALUE
------------
1
2
3
SQL>
First let's set up a small table for testing:
create table my_table
( id number primary key
, column_1 number
, column_2 number
, column_3 number
);
insert into my_table
select 1008, 3, -8, 0.2 from dual union all
select 1002, 6, null, -1.2 from dual
;
commit;
The function can look like this. Note that I don't use union all - that will require reading the table three times, when only one time is enough.
create or replace function my_function (p_function_parameter number)
return sys.odcinumberlist
as
arr sys.odcinumberlist;
begin
select case ord when 1 then column_1
when 2 then column_2
when 3 then column_3 end
bulk collect into arr
from my_table cross join
(select level as ord from dual connect by level <= 3)
where id = p_function_parameter
order by ord
;
return arr;
end;
/
The function could be used, for example, like this: (in older versions you may need to wrap the function call within the table operator)
select * from my_function(1002);
COLUMN_VALUE
------------
6
-1.2
I have values like below
1,a,b,c
2,d,e
3,f,g
Expected output
1 a
1 b
1 c
2 d
2 e
Can you please help me?
It is very much close to implementing the logic to Split comma delimited strings in a table. The only tricky thing is that you have the row number along with the string itself.
You could use ROWNUM as pseudo column, and then filter out those rows where the leading substr of the string is repeating with the ROWNUM.
For example,
Setup
SQL> CREATE TABLE t(text VARCHAR2(4000));
Table created.
SQL>
SQL> INSERT INTO t SELECT '1,a,b,c' text FROM dual;
1 row created.
SQL> INSERT INTO t SELECT '2,d,e' text FROM dual;
1 row created.
SQL> INSERT INTO t SELECT '3,f,g' text FROM dual;
1 row created.
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM t;
TEXT
----------
1,a,b,c
2,d,e
3,f,g
SQL>
Solution:
SQL> WITH DATA AS(
2 SELECT ROWNUM rn, text FROM t
3 )
4 SELECT *
5 FROM
6 (SELECT rn,
7 trim(regexp_substr(t.text, '[^,]+', 1, lines.COLUMN_VALUE)) text
8 FROM DATA t,
9 TABLE (CAST (MULTISET
10 (SELECT LEVEL FROM dual CONNECT BY LEVEL <= regexp_count(t.text, ',')+1
11 ) AS sys.odciNumberList ) ) lines
12 )
13 WHERE TO_CHAR(rn) <> text
14 ORDER BY rn
15 /
RN TEXT
---------- ----------
1 a
1 b
1 c
2 d
2 e
3 f
3 g
7 rows selected.
SQL>
Is any way to select all columns in a record where fields are not null or NVL the null fields to ''?
Im working on ORACLE
Something like this
SELECT * IS NOT NULL
FROM table
WHERE id_table ='001'
or like this
SELECT NVL(*,'')
FROM table
WHERE id_table ='001'
Just reverse the NULL logic in the demonstration about Find all columns having at least a NULL value from all tables in the schema.
For example,
FIND_NULL_COL is a simple user defined function(UDF) which will return 1 for the column which has at least one NULL value :
SQL> CREATE OR REPLACE
2 FUNCTION FIND_NULL_COL(
3 TABLE_NAME VARCHAR2,
4 COLUMN_NAME VARCHAR2)
5 RETURN NUMBER
6 IS
7 cnt NUMBER;
8 BEGIN
9 CNT :=1;
10 EXECUTE IMMEDIATE 'select count(1) from '
11 ||TABLE_NAME||' where ' ||COLUMN_NAME||' is not null
12 and deptno = 20' INTO cnt;
13 RETURN
14 CASE
15 WHEN CNT=0 THEN
16 1
17 ELSE
18 0
19 END;
20 END;
21 /
Function created.
Call the function in SQL to get the NULL status of all the column of any table :
SQL> SET pagesize 1000
SQL> column owner format A10;
SQL> column column_name format A20;
SQL> COLUMN TABLE_NAME FORMAT A20;
SQL> column n format A1;
SQL> SELECT c.OWNER,
2 c.TABLE_NAME,
3 c.COLUMN_NAME,
4 C.NULLABLE,
5 FIND_NULL_COL(c.TABLE_NAME,c.COLUMN_NAME) null_status
6 FROM all_tab_columns c
7 WHERE C.OWNER =USER
8 AND c.TABLE_NAME = 'EMP'
9 ORDER BY C.OWNER,
10 C.TABLE_NAME,
11 C.COLUMN_ID
12 /
OWNER TABLE_NAME COLUMN_NAME N NULL_STATUS
---------- -------------------- -------------------- - -----------
SCOTT EMP EMPNO N 0
SCOTT EMP ENAME Y 0
SCOTT EMP JOB Y 0
SCOTT EMP MGR Y 0
SCOTT EMP HIREDATE Y 0
SCOTT EMP SAL Y 0
SCOTT EMP COMM Y 1
SCOTT EMP DEPTNO Y 0
8 rows selected.
SQL>
So, NULL_STATUS "1" is the column which has NULL value(s).