using variable with set of values inside pl/sql cursor - oracle

I am trying to use variable v_values with set of values inside cursor in the Where clause using IN operator but it returns no record.
create or replace PROCEDURE MyProc IS
/* Cursor decleration */
CURSOR CUR_DUMMY (v_values as varchar2)
IS
SELECT COL1,COL2,COL3
FROM TABLE
WHERE COL1 IN v_values;
l_values varchar2();
BEGIN
l_values:='(''one'',''two'',''three'')';
FOR REC IN CUR_DUMMY (l_values)
LOOP
dbms.output.put_line(REC.col1 || ' ' || REC.col2 || ' ' || REC.col3);
END LOOP;
END;
Any suggestion how to resolve this issue?

IN operator requires a list of values, not the values as comma delimited string.
One simple solution is using nested tables:
create table tab (col1,col2,col3) as
select 'row'||rownum, 2, 3 from dual connect by level<=10
/
create or replace procedure proc is
cursor cur (vl sys.odciVarchar2List) is
select col1,col2,col3
from tab
where col1 in (select column_value val from table (vl));
begin
for rec in cur (sys.odciVarchar2List ('row1','row3','row9')) loop
dbms_output.put_line (rec.col1||' '||rec.col2||' '||rec.col3);
end loop;
end;
/
SQL> exec proc
row1 2 3
row3 2 3
row9 2 3

Here's an example based on Scott's EMP table (as I don't have yours, whose name is invalid anyway). Besides, you should pay attention to fix obvious errors, such as dbms.output (there's no dot but underline), varchar2() variable with no size, v_values as while declaring the cursor (there's no as) and similar stuff which are easy to fix and show that you're actually paying attention to what you're doing, and not typing just because you must.
Read comments within code.
SQL> set serveroutput on;
SQL> create or replace procedure myproc is
2 cursor cur_dummy (v_values varchar2) is
3 -- split V_VALUES into rows
4 select empno, ename, job
5 from emp
6 where job in (select trim(regexp_substr(v_values, '[^,]+', 1, level))
7 from dual
8 connect by level <= regexp_count(v_values, ',') + 1
9 );
10 l_values varchar2(100);
11 begin
12 -- no need to complicate with single quotes and stuff; just name those values
13 l_values:='CLERK, MANAGER';
14
15 for rec in cur_dummy (l_values)
16 loop
17 dbms_output.put_line(rec.empno || ' ' || rec.ename || ' ' || rec.job);
18 end loop;
19 end;
20 /
Procedure created.
SQL> exec myproc;
7369 SMITH CLERK
7566 JONES MANAGER
7698 BLAKE MANAGER
7876 ADAMS CLERK
7900 JAMES CLERK
PL/SQL procedure successfully completed.
SQL>

Related

create a procedure to create a table in Pl/sql from a select statement

I have a select query
select s.site, s.date, s.loaction, s.modified, sysdate p_run_date
from table s
where s.site = 123 --p_site
and s.date >= sysdate -p_date.
i want to create a pl/sql procedure to create a table where p_date and p_site need to be input to the procedure
Why would you want to do that? We normally do NOT create tables dynamically (which is what you'd use in PL/SQL). That procedure would try to create a table with the same name every time you call it (but with different parameters) and fail because table with such a name already exists (as it was created the first time you ran the procedure). Therefore, having a one-time procedure is pretty much useless.
If it must be done, oh well ...
SQL> create or replace procedure p_test (par_deptno in number, par_job in varchar2)
2 is
3 l_str varchar2(200);
4 begin
5 l_str := 'create table my_test as ' ||
6 'select deptno, ename, job, sal ' ||
7 'from emp ' ||
8 'where deptno = ' || dbms_assert.enquote_literal(par_deptno) ||
9 ' and job = ' || dbms_assert.enquote_literal(par_job);
10 execute immediate l_str;
11 end;
12 /
Procedure created.
Testing:
SQL> exec p_test(10, 'CLERK');
PL/SQL procedure successfully completed.
SQL> select * from my_test;
DEPTNO ENAME JOB SAL
---------- ---------- --------- ----------
10 MILLER CLERK 1300
Let's try it again, with different parameters:
SQL> exec p_test(20, 'MANAGER');
BEGIN p_test(20, 'MANAGER'); END;
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
ORA-06512: at "SCOTT.P_TEST", line 10
ORA-06512: at line 1
SQL>
As I said, it'll fail. What you're trying to do is just wrong. You'd rather create a view.

Dynamic SQL for duplicates check - Oracle PL/SQL

As my permissions are limited, the following can not be created as procedure.
I need help on developing a Dynamic SQL that checks a table for duplicate unique IDs.
Also, is it possible to have more than one table to be checked for duplicates with the same query?
declare
table_name is table:= table_1
unique_id varchar2(100):= unique_1
begin
select unique_id,
count(unique_id) as count_unique
from table_name
having count(unique_id)>1
group by unique_id
end;
/
If you can't create a stored procedure (or a function), you're doomed to an anonymous PL/SQL block. Here's one that works in SQL*Plus (probably in SQL Developer as well). Read comments within code.
For Scott's EMP table, number of jobs is
SQL> select job, count(*) from emp group by job;
JOB COUNT(*)
--------- ----------
CLERK 4
SALESMAN 4
PRESIDENT 1
MANAGER 3
ANALYST 2
SQL>
You'd then
SQL> declare
2 l_table varchar2(30) := '&PAR_TABLE_NAME';
3 l_column varchar2(30) := '&PAR_COLUMN_NAME';
4 l_str varchar2(500);
5 l_rc sys_refcursor;
6 --
7 l_ret_column varchar2(30);
8 l_ret_cnt number;
9 begin
10 -- compose a SELECT statement
11 l_str := 'select ' || l_column || ', count(*) cnt ' ||
12 ' from ' || l_table ||
13 ' group by ' || l_column ||
14 ' having count(*) > 1';
15
16 -- use L_STR as a "source" for the L_RC (ref)cursor
17 open l_rc for l_str;
18
19 -- loop, fetch data, display what you've found
20 loop
21 fetch l_rc into l_ret_column, l_ret_cnt;
22 exit when l_rc%notfound;
23
24 dbms_output.put_line(l_table ||'.'|| l_column ||' = ' ||
25 l_ret_column ||', ' || l_ret_cnt || ' row(s)');
26 end loop;
27
28 close l_rc;
29 end;
30 /
Enter value for par_table_name: emp
Enter value for par_column_name: job
emp.job = CLERK, 4 row(s)
emp.job = SALESMAN, 4 row(s)
emp.job = MANAGER, 3 row(s)
emp.job = ANALYST, 2 row(s)
PL/SQL procedure successfully completed.
SQL>

How do I assign number of counted ID's from sub-query to plsql declared variable "v_count"

I'm trying create a pl/sql block that retrieves manager’s information .
List item
The program must prompt the user to enter manager’s number and later displays the total number of employees working under that manager.
SERVER OUTPUT ON
DECLARE
v_last_name s_emp.last_name%TYPE;
v_first_name s_emp.first_name%TYPE;
v_count NUMBER (10);
BEGIN
SELECT DISTINCT last_name,first_name
INTO v_surname,v_name,v_count
FROM s_emp
WHERE ID IN (SELECT manager_id, COUNT(ID)
FROM s_emp
WHERE manager_id = &ID
GROUP BY manager_id);
DBMS_OUTPUT.PUT_LINE('Manager '||v_last_name||'
'||SUBSTR(v_first_name,1,1)||' , has '||v_count||' surbodinates');
END;
I've also tried SQL%ROWCOUNT. And i'm not allowed to use loops and Explicit Cursors yet
This is the error i get when i try to run the code:
PL/SQL: ORA-00913: too many values
Errors you made:
number of columns returned by a select statement in PL/SQL must match number of variables you're putting their values into. You can't select 3 values and put them into 2 variables
where clause: ID can't be in two values returned by a subquery (manager_id, count(id)); must be only one
sql%rowcount won't help here, as its value remains 1 (if select returns a row; if it returns more than a single row, that code will raise too-many-rows; if it returns no rows, it'll raise no-data-found)
An example of how you might have done it (based on Scott's sample schema):
SQL> set verify off
SQL> set serveroutput on
SQL> declare
2 v_ename emp.ename%type;
3 v_count number;
4 begin
5 select ename
6 into v_ename
7 from emp
8 where empno = &&manager_id;
9
10 select count(*)
11 into v_count
12 from emp
13 where mgr = &&manager_id;
14
15 dbms_output.put_line('Manager ' || v_ename || ' has ' || v_count ||
16 ' subordinates');
17 end;
18 /
Enter value for manager_id: 7698
Manager BLAKE has 5 subordinates
PL/SQL procedure successfully completed.
SQL>

How to run a query on different schemes at once

I want to run a query on different schemes to get data and export it. I use the following code
DECLARE
sql_statment VARCHAR2(2000);
BEGIN
FOR c IN (SELECT brchcode FROM brchs) LOOP
sql_statment := 'select distinct ''' || c.brchcode ||''', t.risuid from ' || c.brchcode ||
'.reg_individualacnt_detail t
where t.historytypecode = 60';
EXECUTE IMMEDIATE sql_statment;
END LOOP;
END;
where brchcode is the name of different schemes
I can't see any output. what can I do?
Code you wrote can't work as you have to return the result into something; it is PL/SQL and requires an INTO clause. As you chose to return two values (columns) and multiple rows, that can't be a scalar variable; you could pick ref cursor or a collection, for example.
Here's an example which shows one option.
I'll be using two schemas: SCOTT (current schema) and HR. Both will be having the DEPT table.
As Scott already has it, I'll create one in HR schema and grant access to Scott (otherwise, Scott won't even see it and the procedure (i.e. the function) will fail):
SQL> connect hr/hr
Connected.
SQL> create table dept (deptno number, dname varchar2(10), loc varchar2(10));
Table created.
SQL> insert into dept values (55, 'IT', 'Zagreb');
1 row created.
SQL> grant select on dept to scott;
Grant succeeded.
SQL> commit;
Commit complete.
Back to Scott, to create a table (which contains schema names I'll be selecting from) and a function. I chose to return REF CURSOR; you could return something else, if you want.
SQL> connect scott/tiger
Connected.
SQL> create table brchs (brchcode varchar2(10));
Table created.
SQL> insert into brchs (brchcode)
2 select 'scott' from dual union all
3 select 'hr' from dual;
2 rows created.
SQL> create or replace function f_br
2 return sys_refcursor
3 is
4 l_str varchar2(4000);
5 l_rc sys_refcursor;
6 begin
7 for cur_r in (select brchcode from brchs) loop
8 l_str := l_str ||
9 'union all
10 select ' || chr(39)|| cur_r.brchcode ||chr(39) || ', d.dname
11 from ' || cur_r.brchcode ||'.dept d
12 where d.deptno > 0';
13 end loop;
14
15 l_str := ltrim(l_str, 'union all');
16
17 open l_rc for l_str;
18 return l_rc;
19 end;
20 /
Function created.
SQL>
Finally, testing:
SQL> select f_br from dual;
F_BR
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
'SCOT DNAME
----- --------------
scott ACCOUNTING
scott RESEARCH
scott SALES
scott OPERATIONS
hr IT
SQL>

Searching specific row for a particular data by the use of cursor in PL/SQL in Oracle

I am new to PL/SQL and I am trying to search a specific data from schema. I want to use nested cursors and make the query dynamic. Please help me out with the approach.
Here's an example which uses a loop (though, not nested loops, as you want - I'm not sure why) and dynamic SQL (execute immediate).
It is based on Scott's schema; I'm looking for number of appearances of the employee name "KING" in all tables in current schema (querying USER_TABLES), within the ENAME column (querying USER_TAB_COLUMNS).
This is just to give you an idea; feel free to develop it further.
Some sample data:
SQL> set serveroutput on
SQL> select ename from emp order by ename;
ENAME
----------
ALLEN
BLAKE
CLARK
FORD
JAMES
JONES
KING
MARTIN
MILLER
SMITH
TURNER
WARD
12 rows selected.
SQL> select ename from bonus;
ENAME
----------
KING
Let's search for that KING person:
SQL> declare
2 l_str varchar2(500);
3 l_cnt number := 0;
4 begin
5 for cur_r in (select u.table_name, u.column_name
6 from user_tab_columns u, user_tables t
7 where u.table_name = t.table_name
8 and u.column_name = 'ENAME'
9 )
10 loop
11 l_str := 'SELECT COUNT(*) FROM ' || cur_r.table_name ||
12 ' WHERE ' || cur_r.column_name || ' like (''%KING%'')';
13
14 execute immediate (l_str) into l_cnt;
15
16 if l_cnt > 0 then
17 dbms_output.put_line(l_cnt ||' : ' || cur_r.table_name);
18 end if;
19 end loop;
20 end;
21 /
1 : EMP
1 : BONUS
PL/SQL procedure successfully completed.
SQL>
The result says that KING appears once in EMP and BONUS tables.
try this..
SET SERVEROUTPUT ON SIZE 100000
----Final OP----------------------
CREATE OR REPLACE PROCEDURE StringQuery(names VARCHAR2)
IS
match_count INTEGER;
v_data_type VARCHAR2(255) :='VARCHAR2';
v_search_string VARCHAR2(4000) :=names;
BEGIN
FOR t IN (SELECT table_name, column_name FROM user_tab_columns where data_type = v_data_type) LOOP
EXECUTE IMMEDIATE
'SELECT COUNT(*) FROM '||t.table_name||' WHERE '||t.column_name||' = :1'
INTO match_count
USING v_search_string;
IF match_count > 0 THEN
dbms_output.put_line( 'Table Name: '||t.table_name ||', Column Name: '||t.column_name||', Found This Many Times: '||match_count );
--EXECUTE IMMEDIATE 'SELECT * FROM '||t.table_name||'WHERE '||t.column_name||'='||v_search_string||' ';
END IF;
END LOOP;
END;
/
CALL StringQuery('&Enter_String_Value');

Resources