create a procedure with cursor as parameter - plsql

I wrote this code and it works ok:
declare
cursor c_emp is
select last_name, first_name from employees;
type c_list is table of employees.last_name%type index by binary_integer;
type c_list2 is table of employees.first_name%type index by binary_integer;
last_list c_list;
first_list c_list2;
counter integer := 0;
begin
for i in c_emp loop
counter := counter + 1;
last_list(counter) := i.last_name;
first_list(counter) := i.first_name;
dbms_output.put_line('Employee(' || counter || '): ' || last_list(counter) || ' ' || first_list(counter));
end loop;
end;
/
This time I am trying to make procedure with parameters that I can insert the table name and column into the cursor. And I have tried with this :
create or replace procedure show_data(tab_name in varchar2, data_list in varchar2)
is
str varchar2(100);
str2 varchar2(100);
column_name varchar2(100);
begin
str := 'select ' || data_list || ' from ' || tab_name;
for vRec in str loop
dbms_output.put_line(str);
end loop;
end;
/
It gave a error which the str is not a cursor. I am not sure that if cursor can be done in this way, but from the error it seems it can't.
Which part of my code is wrong, or because I didn't declare my cursor? But if i declare my cursor, I can't get the parameter by using dynamic sql way.

The below should produce the same result as your original PL/SQL block. Note that the table_name can be dynamic and so can the data_list but you need to know the column names in the data_list to be able to fetch from the cursor and then print them.
create or replace procedure show_data(tab_name in varchar2
, data_list in varchar2)
is
str varchar2(100);
str2 varchar2(100);
column_name varchar2(100);
TYPE cursor_ref IS REF CURSOR;
vRec_cursor cursor_ref;
counter integer = 0;
last_name employee.last_name%TYPE;
first_name employee.first_name%TYPE;
begin
str := 'select ' || data_list || ' from ' || tab_name;
open vRec_cursor for str;
loop
FETCH vRec_cursor INTO last_name, first_name;
EXIT WHEN vRec_cursor%NOTFOUND;
dbms_output.put_line('Employee(' || counter || '): ' || last_name || ' ' || first_name;
counter = counter + 1;
end loop;
end;
/
NOTE: Haven't run the above code yet

Related

SQL Loop Executing after intended

I am attempting to run this code, I know the elements of the Loop are working, and I know the update statement does update. When I run the script with some print statements, it prints the UPDATE information first, then the LOOP information, therefore the update has no information.
PROCEDURE UpdateGridStats(p_grid_name VARCHAR2, p_region_name VARCHAR2) IS
CURSOR c1 IS
SELECT grd.globalid grid_globalid, wp.globalid workpoint_globalid, wp.feature_class_name workpoint_fcname,
tt.work_order_task_type task_type_name
FROM workorderpoint_evw wp, rpt_grid grd, workordertasktype_evw tt
WHERE grd.grid_name = p_grid_name
AND wp.work_order_task_type_globalid = tt.globalid
AND grd.rpt_region = p_region_name
AND sde.st_relation_operators.st_within_f(wp.shape, grd.shape) = 1;
v_count NUMBER := 0;
v_pole_insp_count NUMBER := 0;
v_pole_damage_count NUMBER := 0;
v_cond_damage_count NUMBER := 0;
BEGIN
FOR work_rec IN c1
LOOP
BEGIN
v_count := v_count + 1;
IF work_rec.task_type_name = 'Pole Inspection'
THEN
v_pole_insp_count := v_pole_insp_count + 1;
END IF;
IF work_rec.task_type_name = 'Pole Damage'
THEN
v_pole_damage_count := v_pole_damage_count + 1;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('==> No data found for work record ');
END;
END LOOP;
dbms_output.put_line(v_pole_damage_count || ',' ||v_pole_insp_count);
UPDATE rpt_grid grd SET da_pole_count = v_pole_damage_count, ins_structure_count = v_pole_insp_count
WHERE grd.grid_name = p_grid_name
AND grd.rpt_region = p_region_name;
END UpdateGridStats;
Maybe you just forgot to commit your changes?
Here is a simpler version of your stored procedure.
CREATE OR REPLACE PROCEDURE update_grid_stats(p_grid_name VARCHAR2, p_region_name VARCHAR2)
IS
v_ins_structure_count rpt_grid.ins_structure_count%TYPE;
v_da_pole_count rpt_grid.da_pole_count%TYPE;
BEGIN
UPDATE rpt_grid grd
SET (ins_structure_count, da_pole_count) =
(
SELECT
COUNT(CASE WHEN tt.work_order_task_type = 'Pole Inspection' THEN 1 END),
COUNT(CASE WHEN tt.work_order_task_type = 'Pole Damage' THEN 1 END)
FROM workorderpoint_evw wp
JOIN workordertasktype_evw tt ON wp.work_order_task_type_globalid = tt.globalid
WHERE sde.st_relation_operators.st_within_f(wp.shape, grd.shape) = 1
)
WHERE grd.grid_name = p_grid_name
AND grd.rpt_region = p_region_name
RETURNING ins_structure_count, da_pole_count
INTO v_ins_structure_count, v_da_pole_count;
dbms_output.put_line(
SQL%ROWCOUNT || ' rows got updated. Values: ' ||
'ins_structure_count = ' || v_ins_structure_count ||
', da_pole_count = ' || v_da_pole_count
);
COMMIT;
END update_grid_stats;
The variables and the RETURNING clause are merely needed for the output. If you don't need the output, you can remove them.
if I understand correcatally, the proc works OK, but the print statemnts are not. I beleve the print operations are on a different thread. To overcome this issue, try to replace your pront statment with raiserror function :
declare #mag varchar(max) = 'Hllo world'
raiserror ( #ERR_MSG ,0, 1) with nowait;

CREATE OR REPLACE PROCEDURE proc_video_search

Create a procedure called proc_video_search to search for a video and display the name, copy ID, format, and status of the video’s copies. In addition, the checkout dates and due dates are also displayed for unreturned copies. The damaged copies (Status = 'D') are excluded in your output. Sort your output by the video name (Name) and then the copy ID (CopyID).
$ CREATE OR REPLACE PROCEDURE proc_video_search (
p_VideoName VARCHAR2,
p_FormatName VARCHAR2 DEFAULT NULL) as
v_Count NUMBER;
v_TotalCopies NUMBER; v_Avalb NUMBER;v_FormatName VARCHAR2(100);
v_VideoName VARCHAR2(100); v_CopyID VARCHAR2(100);v_DueDate DATE;
v_Status VARCHAR2(100); v_CheckoutDate DATE;
CURSOR asdf IS
SELECT T_VIDEO.Name, T_COPY.CopyID, Status,T_VIDEO_FORMAT.NAME
FROM T_VIDEO
INNER JOIN T_COPY ON T_VIDEO.VideoID = T_COPY.VideoID
INNER JOIN T_VIDEO_FORMAT ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status !='D' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) || '%'
OR UPPER(T_VIDEO_FORMAT.NAME)= UPPER(p_FormatName)
ORDER BY T_VIDEO.Name, T_COPY.CopyID;
BEGIN
SELECT COUNT(*)
INTO v_Count
FROM T_VIDEO
WHERE UPPER(T_VIDEO.Name) like '%' || UPPER(p_VideoName) || '%' ;
IF v_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('**** '||v_Count|| ' results found for ' ||
p_VideoName||'. *****');
RETURN;
END IF;
SELECT count(T_COPY.CopyID) INTO v_TotalCopies
FROM T_COPY INNER JOIN T_VIDEO ON T_COPY.VideoID = T_VIDEO.VideoID
INNER JOIN T_VIDEO_FORMA ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status !='D' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) ||'%'
OR UPPER(T_VIDEO_FORMAT.NAME)=UPPER(p_FormatName);
SELECT count(T_COPY.CopyID)INTO v_Avalb FROM T_COPY
INNER JOIN T_VIDEO ON T_COPY.VideoID = T_VIDEO.VideoID
INNER JOIN T_VIDEO_FORMAT ON T_VIDEO_FORMAT.FormatID =
T_VIDEO.FormatID
WHERE Status ='A' AND UPPER(T_VIDEO.Name) like '%' ||
UPPER(p_VideoName) ||'%'
OR UPPER(T_VIDEO_FORMAT.NAME)=UPPER(p_FormatName);
IF v_TotalCopies >=0 THEN
IF p_FormatName IS NULL THEN
DBMS_OUTPUT.PUT_LINE(v_TotalCopies||' results found for '||
p_VideoName||' . (Available copies:'|| v_Avalb|| ')' );
ELSE
DBMS_OUTPUT.PUT_LINE(v_TotalCopies||' results found for '||
p_VideoName||'('|| p_FormatName||') . (Available copies:'||
v_Avalb|| ')' );
end if;
OPEN asdf;
LOOP
FETCH asdf INTO v_VideoName, v_CopyID, v_Status,
v_FormatName ; exit when asdf%NOTFOUND ;
SELECT COUNT(CheckoutDate)
INTO v_Count FROM T_RENTAL WHERE CopyID = v_CopyID;
IF v_Count = 1 THEN
SELECT CheckoutDate,DueDate
INTO v_CheckoutDate,v_DueDate
FROM T_RENTAL
WHERE CopyID = v_CopyID;
end if;
DBMS_OUTPUT.PUT_LINE(RPAD('-', 53, '-'));
DBMS_OUTPUT.PUT_LINE(RPAD('Name:',30) || RPAD(v_VideoName,15));
DBMS_OUTPUT.PUT_LINE(RPAD('CopyID:',30) || RPAD(v_CopyID,15));
DBMS_OUTPUT.PUT_LINE(RPAD('Format:',30) ||
RPAD(v_FormatName,15));
IF v_Status = 'A' THEN v_Status := 'Available';END IF;
IF v_Status = 'R' THEN v_Status := 'Rented'; END IF;
DBMS_OUTPUT.PUT_LINE(RPAD('Status:',30) || RPAD(v_Status,15));
IF v_Status ='Available' THEN
DBMS_OUTPUT.PUT_LINE(RPAD('CheckoutDate:',30)
||'****************************');
DBMS_OUTPUT.PUT_LINE(RPAD('DueDate:',30)
||'****************************');
ELSE
DBMS_OUTPUT.PUT_LINE(RPAD('CheckoutDate:',30)
||RPAD(TO_CHAR(v_CheckoutDate, 'DD-MON-YYYY'),15));
DBMS_OUTPUT.PUT_LINE(RPAD('DueDate:',30) ||RPAD(TO_CHAR(
v_DueDate, 'DD-MON-YYYY'),15));
END IF; END LOOP; CLOSE asdf; END IF; END proc_video_search ;
EXEC proc_video_search('ANOTHER', 'DVD')`
enter image description here
The problem is with this line of your cursor asdf
OR UPPER(T_VIDEO_FORMAT.NAME)= UPPER(p_FormatName)
Because it says OR, the query can choose to ignore this criteria if it evaluates to false. That is why you are getting results with all the formats; it ignores the filtering.
You have to wrap the OR statement in another AND clause, like so
WHERE Status !='D'
AND UPPER(T_VIDEO.Name) like '%' || UPPER(p_VideoName) || '%'
AND ( /* OR clause here */ )
And then you can handle the case of p_formatName being null or not.

Need help solving Pl/sql issue

I am trying to fill a database with random data, but the primary key needs to still be unique. I can fill the database with random data, but now I am trying to solve the primary key issue.
When running this code I get errors.
set SERVEROUTPUT on
create or replace
PROCEDURE fillDatabase(TableIn IN varchar2, Amount IN NUMBER) IS
columnData varchar2(50);
columnNR number(10);
str varchar2(500);
sqlStatement varchar2(500);
l_ran_time TIMESTAMP;
intlol NUMBER(38);
prmname varchar2(50);
prmtab varchar2(50);
prmkey number(10);
temp number(30);
tempstr varchar2(50);
lolnr number(10);
strq varchar2(50);
BEGIN
lolnr := 1;
select count(*) into columnNR
from user_tab_columns where table_name=TableIn;
FOR counter IN 1..Amount
LOOP
sqlStatement := 'insert into '|| TableIn ||' values (';
FOR counter2 IN 1..columnNR
LOOP
SELECT cols.table_name, cols.column_name into prmtab, prmname
FROM all_constraints cons, all_cons_columns cols
WHERE cols.table_name = TableIn
AND cons.constraint_type = 'P'
AND cons.constraint_name = cols.constraint_name
AND cons.owner = cols.owner
ORDER BY cols.table_name, cols.position;
tempstr := 'select count(*) into temp from '|| prmtab;
dbms_output.put_line('test');
dbms_output.put_line(temp);
EXECUTE IMMEDIATE tempstr;
IF temp = 0
THEN
strq := 'SELECT max(' || prmname || ') into prmkey from '|| prmtab || ' order by '|| prmname;
dbms_output.put_line(strq);
EXECUTE IMMEDIATE strq;
END IF;
select dbms_random.value(0, 20) into intlol from dual;
select dbms_random.string('U', 20) into str from dual;
SELECT SYSDATE + dbms_random.value(0, SYSDATE - SYSDATE+1)
INTO l_ran_time
FROM dual;
Select DATA_TYPE INTO columnData
FROM user_tab_columns
WHERE table_name= TableIn
AND COLUMN_ID = counter2;
dbms_output.put_line(columnData);
CASE
WHEN columnData = 'VARCHAR2' THEN sqlStatement := sqlStatement ||''''|| str ||''', ';
WHEN columnData = 'NUMBER' THEN sqlStatement := sqlStatement || intlol ||', ';
WHEN columnData = 'TIMESTAMP(6)' THEN sqlStatement := sqlStatement ||''''|| l_ran_time ||''', ';
ELSE sqlStatement := sqlStatement || NULL || ', ';
END CASE;
END LOOP;
sqlStatement := SUBSTR(sqlStatement, 0, LENGTH(sqlStatement) -2);
sqlStatement := sqlStatement || ')';
dbms_output.put_line(sqlStatement);
EXECUTE IMMEDIATE sqlStatement;
END LOOP;
END fillDatabase;
Can you guys help me solve this?
use the pattern
str := 'select x from t where...';
execute immediate str into var;
instead of
str := 'select x into var from t where...';
execute immediate str;

Inserting data into Global temporary table by executing Stored Procedure in SQLPLUS

I creatd a stored procedure. And a global temporary table inside it.
Now i am inserting data into this table by fatching cursor into local variables.
create or replace PROCEDURE "DEMO"
(
PARM_YEAR IN NUMBER,
PARM_PERIOD IN NUMBER,
PARM_PERIOD_TYPE IN CHAR,
PARM_PERIOD_ROLL IN CHAR,
PARM_TYPE IN VARCHAR2,
P_CURSOR IN OUT types.cursorType
)
IS
LOC_EXISTS NUMBER;
LOC_TYPE_PERIOD CHAR(2);
LOC_CURSOR_YEAR INTEGER;
LOC_CURSOR_PERIOD INTEGER;
LOC_CURSOR_TYPE_PERIOD CHAR(2 BYTE);
LOC_CURSOR_DEV_COPCL NUMBER(10,1);
LOC_CURSOR_DIST_GRP NUMBER(3,0);
CURSOR DIST_CHART IS
SELECT X.YEAR , X.PERIOD, X.TYPE_PERIOD, X.COST AS DEV_COPCL
FROM
SMY_PRVDR_TYPE_PRVDR X;
BEGIN
/* Set Period type */
IF (PARM_PERIOD_TYPE = 'Q' AND PARM_PERIOD_ROLL = 'A') THEN
LOC_TYPE_PERIOD := 'Q';
ELSE IF (PARM_PERIOD_TYPE = 'Q' AND PARM_PERIOD_ROLL = 'R') THEN
LOC_TYPE_PERIOD := 'RQ';
ELSE IF (PARM_PERIOD_TYPE = 'M' AND PARM_PERIOD_ROLL = 'A') THEN
LOC_TYPE_PERIOD := 'M';
ELSE
LOC_TYPE_PERIOD := 'RM';
END IF;
END IF;
END IF;
LOC_EXISTS := 0;
SELECT 1 INTO LOC_EXISTS
FROM ALL_TABLES
WHERE TABLE_NAME LIKE '%DEMO1%';
IF LOC_EXISTS = 1 THEN
EXECUTE IMMEDIATE 'TRUNCATE TABLE DEMO1';
END IF;
OPEN DIST_CHART;
LOOP
FETCH DIST_CHART INTO LOC_CURSOR_YEAR, LOC_CURSOR_PERIOD, LOC_CURSOR_TYPE_PERIOD,
LOC_CURSOR_DEV_COPCL;
EXIT WHEN DIST_CHART%NOTFOUND;
SELECT DIST_GRP(LOC_CURSOR_DEV_COPCL) INTO LOC_CURSOR_DIST_GRP FROM DUAL;
EXECUTE IMMEDIATE 'INSERT INTO DEMO1 VALUES ('|| LOC_CURSOR_YEAR ||', '''||
LOC_CURSOR_PERIOD || ''', '''|| LOC_CURSOR_TYPE_PERIOD ||''', '|| LOC_CURSOR_DEV_COPCL
||', '|| LOC_CURSOR_DIST_GRP || ')';
END LOOP;
CLOSE DIST_CHART;
EXCEPTION
WHEN NO_DATA_FOUND THEN
LOC_EXISTS:=0;
END;
Problem is that..
When i am executing this stored procedure into sql developer data is inserted successfuly into the global temporary table.
But
When i run same execute command into SQLPLUS, procedure run successfully, but data is not inserted into the global temporary table.
Code of GTT is
CREATE GLOBAL TEMPORARY TABLE "ICUSER"."DEMO1"
( "YEAR" NUMBER(4,0),
"PERIOD" NUMBER(2,0),
"TYPE_PERIOD" CHAR(2 BYTE),
"DEV_COPCL" NUMBER(*,1),
"DIST_GRP" NUMBER(3,0)
) ON COMMIT PRESERVE ROWS ;

i have a function which returns multiple o/p i need to call this function to insert in a table

create or replace type branch_warehouse as object (wh_id number,wh_name varchar2(100));
create or replace type id_warehouse_list as table of branch_warehouse;
function get_ware_house_branch(p_BRANCH_IDS in out varchar2)
return id_warehouse_list is
l_warehouse_list id_warehouse_list := id_warehouse_list();
str varchar2(300);
begin
str := 'SELECT BRANCH_WAREHOUSE(w.wh_id, w.wh_name)
FROM POD_WAREHOUSE_MASTER W
where ( W.BRANCH_ID IN (' || p_BRANCH_IDS || '))';
execute immediate str bulk collect into l_warehouse_list;
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i).wh_id || ', ' || l_warehouse_list(i).wh_name);
end loop;
return l_warehouse_list;
end;
procedure insert_place_warehouse_map(p_PLACE_NAME in varchar2,
p_BRANCH_IDS in number,
p_status out varchar2,
p_status_dtl out varchar2) is
v_ID number;
l_warehouse_list id_warehouse_list := id_warehouse_list();
begin
v_ID := get_place_id (p_PLACE_NAME);
l_warehouse_list := get_ware_house_branch(p_BRANCH_IDS);
for i in l_warehouse_list.first..l_warehouse_list.last loop
insert into pod_place_warehouse_map(
id,
place_id,
wh_id,
wh_name)
values(
pod_unique_val_seq.nextval,
v_ID,
l_warehouse_list(i).wh_id,
l_warehouse_list(i).wh_name);
v_rec_cnt := sql%rowcount;
end loop;
commit;
p_status := 'SUCESS';
p_status_dtl := v_rec_cnt||' Record Inserted Successfully';
exception
when others then
rollback;
p_status_dtl := sqlcode||' - '||substr(sqlerrm,1,100);
p_status := 'ERROR';
end;
i am getting error p_BRANCH_IDS cannot be used as assignment operator in the 2nd code
first code is working,
please help
This is because the parameter is declared as in out in first code, but as in in second.

Resources