How can I pass comma separated value in cursor's select statement where clause - sql

I have following Block which has a cursor and a select query. I want to pass the output of select, which is comma separated into
the cursor's select statement, into the where clause.
I know below code will throw an error because of SQL query in Declare section but how I achieve this using array or collection.
here, id column is number
code snippet:
declare
test varchar2(30);
SELECT LISTAGG(value, ', ') WITHIN GROUP (ORDER BY value2) into test from table3 where value2=12;
cursor c1 (select * from table where id in (test))
begin
for i in c1 loop
null;
end loop;
end;

Why would you ever do this?
You can simple write you select as:
Select * from table where id in (select value from table3 where value2=12)
Edit:
Also you need to open your cursor c1, for it to work AFAIK.

You can use a collection and the MEMBER OF operator:
Oracle Setup:
CREATE TYPE IntegerList AS TABLE OF NUMBER(8,0);
/
CREATE TABLE table1 ( value, value2 ) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 3, 4 FROM DUAL UNION ALL
SELECT 5, 3 FROM DUAL UNION ALL
SELECT 7, 2 FROM DUAL;
CREATE TABLE table2 ( id, value ) AS
SELECT 1, 11 FROM DUAL UNION ALL
SELECT 2, 22 FROM DUAL UNION ALL
SELECT 3, 33 FROM DUAL UNION ALL
SELECT 7, 77 FROM DUAL;
PL/SQL:
DECLARE
test IntegerList;
c1 SYS_REFCURSOR;
BEGIN
SELECT value
BULK COLLECT INTO test
FROM table1;
FOR r IN ( SELECT * FROM table2 WHERE id MEMBER OF test ) LOOP
DBMS_OUTPUT.PUT_LINE( r.id || ', ' || r.value );
END LOOP;
END;
/
Output:
1, 11
3, 33
7, 77
db<>fiddle here

Related

I want to Create a function that returns the number of employees in a department

The query I tried is this,
CREATE OR REPLACE FUNCTION get_dno (d_no IN Employee.DepartmentNo%TYPE)
RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO d_cnt
FROM employee GROUP BY DeptNo=d_no;
RETURN d_cnt;
END get_dno;
and use this query below to get value from user.
DECLARE
get_dptno NUMBER;
BEGIN
get_dptno := get_dno(:d_no);
DBMS_OUTPUT.PUT_LINE('No of employees in searched DeptNo : ' ||get_dptno);
END;
But I couldn't even get the Function part to run.
The error I got was where I used GROUP BY, I think
This is the error message I got
Is there any workaround for the same logic ???
When you group by column there is no condition accept please remove code after column name DeptNo.
CREATE OR REPLACE FUNCTION get_dno (d_no IN Employee.DepartmentNo%TYPE)
RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO d_cnt
FROM employee GROUP BY DeptNo;
RETURN d_cnt;
END get_dno;
You are almost there, you want WHERE rather than GROUP BY and you need to work out if the column name is DepartmentNo or DeptNo and use the correct column name in the signature and in the SELECT query:
CREATE FUNCTION get_dno (
d_no IN Employee.DepartmentNo%TYPE
) RETURN NUMBER
IS
d_cnt NUMBER;
BEGIN
SELECT COUNT(*)
INTO d_cnt
FROM employee
WHERE DepartmentNo=d_no;
RETURN d_cnt;
END get_dno;
/
Then:
DECLARE
get_dptno NUMBER;
BEGIN
get_dptno := get_dno(:d_no);
DBMS_OUTPUT.PUT_LINE('No of employees in searched DeptNo : ' ||get_dptno);
END;
/
Works and, for the sample data:
CREATE TABLE employee (id, departmentno) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 1 FROM DUAL UNION ALL
SELECT 3, 1 FROM DUAL UNION ALL
SELECT 4, 1 FROM DUAL UNION ALL
SELECT 5, 2 FROM DUAL UNION ALL
SELECT 6, 2 FROM DUAL UNION ALL
SELECT 7, 3 FROM DUAL UNION ALL
SELECT 8, 3 FROM DUAL UNION ALL
SELECT 9, 3 FROM DUAL UNION ALL
SELECT 10, 4 FROM DUAL;
If :dno is 1 then outputs:
No of employees in searched DeptNo : 4
db<>fiddle here

How to write multiple SQL query statement and PL/SQL statement inside one PL/SQL statement

In 1 PL/SQL block have to use multiple SELECT query and one block statement. In this block statement we have to take counts before insert query and once insert statement run then after have to take its after_counts of the id value that mentioned below.
set heading off
set colsep '|'
set feedback off
set sqlformat csv
set trimspool on
spool output.txt
declare
ln_rec tab1%rowtype;
lv varchar(20);
sid tab.id%type;
b_cnts number;
a_cnts number;
type sh_id is varray(10) of tab.col1%type;
id sh_id := sh_id(1, 3, 5, 7, 9, 11, 13, 15, 17, 19);
begin
select a.id, count(b.sub_id) into sid, b_cnts as "before_counts" from tab a, tab1 b;
for i in (select distinct b.sub_id from tab a, tab1 b where a.id in (1, 3, 5, 7, 9, 11, 13, 15, 17, 19))
loop
select * into ln_rec from tab1 where sub_id = i.sub_id;
insert into new_tab values(id, i.sub_id, lv);
commit;
end loop;
select a.id, count(b.sub_id) into sid, a_cnts as "after_counts" from tab a, tab b;
end;
spool off
But when i execute it then got error because of above SET system variable summary and in the insert statement due to id. I want output in the csv format or output format like where 3 columns should be generated as id, before_counts, after_counts & its proper value. Like this:-
<id> <before_counts> <after_counts> -- This heading should not appear because above used heading off
1 135 138
3 246 250
5 298 302
7 389 399
.........
Something like this:
DECLARE
type sh_id is varray(10) of tab.col1%type;
a_cnts number;
b_cnts number;
lv varchar2(20) := NULL; -- This is never modified in your code.
ids sh_id := sh_id(1, 3, 5, 7, 9, 11, 13, 15, 17, 19);
BEGIN
FOR i IN 1 .. ids.COUNT LOOP
SELECT count(b.sub_id)
INTO b_cnts
FROM tab a
INNER JOIN tab1 b
ON ( <some join conditions> ) -- you need to specify the join
WHERE a.id = ids(i);
INSERT INTO new_tab
SELECT DISTINCT
ids(i),
b.sub_id,
lv
FROM tab a
INNER JOIN tab1 b
ON ( <some join conditions> ) -- you need to specify the join
WHERE a.id = ids(i);
-- Assuming you have a trigger to populate tab or tab1 from new_tab then
a_cnts := b_cnts + SQL%ROWCOUNT;
-- Otherwise:
SELECT count(b.sub_id)
INTO a_cnts
FROM tab a
INNER JOIN tab1 b
ON ( <some join conditions> ) -- you need to specify the join
WHERE a.id = ids(i);
DBMS_OUTPUT.PUT_LINE( ids(i) || CHR(9) || b_cnts || CHR(9) || a_cnts );
END LOOP;
-- Commit outside the loop
COMMIT;
END;
/

Postgres array value must starts

I want to make an array and put into it two id's, but I got a mistake:
array value must start with “{” or dimension information
ids_list character varying[] := ' || (SELECT COALESCE(quote_literal((array_agg(DISTINCT house_guid)) || ''',''' || quote_literal(array_agg(DISTINCT guid))), 'NULL') FROM tb) || ';
use array_agg function
with t1 as
(
select * from
(
select 'test_SQL_01' as ID
union
select 'test_SQL_02_PQR_01'
union
select 'test_SQL_03_055'
union
select 'test_SQL_04_ABC_99'
) as t
) select array_agg(ID) from t1
You seem to be using this inside a PL/pgSQL function. You should be using SELECT ... INTO variable FROM... instead:
declare
ids_list character varying[];
begin
.....
select array_agg(id)
into ids_list
from (
select house_guid
from tab
union
select guid
from tab
) t;
.... work with the ids_list variable
end;
The UNION will automatically remove all duplicates (as you tried to do with DISTINCT.

Pl sql- reading mathematical formula and replacing with number

I have the following tables:
TABLE 1 TABLE 2
Col 1 Col2 A $100
Rpt1 (A + B(1-D))/C B $200
Rpt2 -A C $300
Rpt3 C+D D $400
I want to write a PL-SQL code that reads both the tables and give me the below dynamically.
Rpt 1 = (100 +200(1-400))/300
Rpt 2 = - 100
Rpt 3 = 300+400
Table 1 can have any type of formula. I need to read that formula and replace it with the amount present in table 2.
Any thoughts?
Since you asked for PL/SQL, here's a nested loop solution:
create table table1 (col1, col2) as
select 'Rpt1', '(A + B(1-D))/C' from dual union all
select 'Rpt2', '-A' from dual union all
select 'Rpt3', 'C+D' from dual;
create table table2 (col1, col2) as
select 'A', 100 from dual union all
select 'B', 200 from dual union all
select 'C', 300 from dual union all
select 'D', 400 from dual;
set serveroutput on
declare
result varchar2(100);
begin
for r1 in (select col1, col2 from table1)
loop
result := r1.col2;
for r2 in (select col1, col2 from table2 where result like '%' || col1 || '%')
loop
result := replace(result, r2.col1, r2.col2);
end loop;
dbms_output.put_line(r1.col1 || ' = ' || result);
end loop;
end;
/
Rpt1 = (100 + 200(1-400))/300
Rpt2 = -100
Rpt3 = 300+400
PL/SQL procedure successfully completed.
I've assumed that the dollar signs aren't actually present in table2; if they are then you'll need to trim them off if you don't want then in the output.

Oracle stored procedure help

HI am new to stored procedure.
Am using a dynamic sql with
select * from table into var
var is a variable.the var contains more than one value ,when i try to run the proc with inputs i get an error:
ORA-01422: exact fetch returns more than requested number of rows
Is there a way such that the variable can hold more than one row using dynamic sql.
Use collection variables:
DECLARE
TYPE tt_int IS TABLE OF INTEGER;
var tt_int;
BEGIN
SELECT id
BULK COLLECT
INTO var
FROM table;
END;
You have to bulk collect the result set into a table of type if you're going to select multiple rows.
declare
type record_type is table of <table_name>;
var_records record_type;
begin
select *
bulk collect into var_records
from <table_name>;
end;
/
See also my answer to PL SQL how to select all columns
you can also return the results to a ref cursor
set serveroutput on
DECLARE
REFEXAMPLE SYS_REFCURSOR;
VAR NUMBER ;
col varchar2(50);
BEGIN
OPEN REFEXAMPLE FOR --Here you open the cursor and fill it
SELECT *
FROM (
SELECT 1 VAR, 'a' COL FROM DUAL
UNION ALL
SELECT 2 VAR, 'b' COL FROM DUAL
UNION ALL
SELECT 3 VAR, 'c' COL FROM DUAL
UNION ALL
SELECT 4 VAR, 'd' COL FROM DUAL
UNION ALL
SELECT 5 VAR, 'e' COL FROM DUAL
) EXAMPLETABLE ;
DBMS_OUTPUT.PUT_LINE('var ' || 'col');
DBMS_OUTPUT.PUT_LINE('---------');
LOOP
FETCH REFEXAMPLE INTO VAR, col; --now loop through
EXIT WHEN REFEXAMPLE%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(var || ' ' || col || ' ');
END LOOP;
CLOSE REFEXAMPLE;
end ;
/
var col
---------
1 a
2 b
3 c
4 D
5 e
You can use a table variable, which provides you with an in-memory table of your results. You declare a table variable similar to a standard variable:
declare #MyVar table (col1 col1type, col2 col2type, etc.)