How to fetch one - one row from table - plsql

I have a table called stud_ans_sheet.
I want to run a loop
which would every time fetch next values from table.
It's a PL/SQL program and I am doing it with a cursor.
This is my program,
but it has a lot of errors:
set serveroutput on;
declare
cursor c_stud is select stud_no,ans from stud_ans_sheet;
v_stud c_stud%rowtype;
v_no stud_ans_sheet.stud_no%type;
answer varchar(10);
i number(3);
v_corr stud_ans_sheet.corr_ans%type;
v_wrong stud_ans_sheet.wrong_ans%type;
v_unattempt stud_ans_sheet.unattempt_ans%type;
score number(5,2);
v_ans varchar(10);
str1 varchar(40);
str2 varchar(40);
nval stud_ans_sheet.stud_no%type;
total number(5,2);
begin
answer:='AACCABAABD';
open c_stud;
loop
fetch c_stud into v_stud;
exit when c_stud%notfound;
for i in 1..10
loop
nval:= select seq.nextval from stud_ans_sheet.stud_no;
select stud_no,ans into v_no,v_ans from stud_ans_sheet where stud_no=nval;
str2:=substr(v_ans,i,1);
str1:=substr(answer,i,1);
if(str2=str1) then
update stud_ans_sheet
set corr_ans=v_corr+1;
elsif(str2='E') then
update stud_ans_sheet
set unattempt_ans=v_unattempt+1;
else
update stud_ans_sheet
set wrong_ans=v_wrong+1;
end if;
end loop;
update stud_ans_sheet
set score=corr_ans-wrong_ans*0.25+unattempt_ans;
end loop;
close c_stud;
end;
/

This line doesn't really make sense:
nval:= select seq.nextval from stud_ans_sheet.stud_no;
There is no variable := select ... construction in PL/SQL, and even if there was, stud_ans_sheet.stud_no isn't a table so you can't select from it, and if you could it's unclear what you want the sequence for anyway.
If you just want to copy the record attribute v_stud.stud_no into the local variable nval then you can just use:
nval := v_stud.stud_no;
but then the question is why copy it at all, when you can just use v_stud.stud_no directly?
It is generally best to avoid the verbose declare-open-fetch construction for cursors when all you need to do is loop through them. Instead, you can just use:
for r in (
select stud_no, ans from stud_ans_sheet
)
loop
I can't see why you are re-querying stud_ans_sheet in the loop just to get back the same row you already have. If it's something to do with your update logic, I couldn't tell what that was supposed to do.
The update statements in your code will update every row in the table every time, because they don't have any where clause.
In PL/SQL, if conditions are terminated by then instead of being enclosed in brackets as in some other languages, so for example,
if (str2 = str1) then
can be decluttered into:
if str2 = str1 then
The construction for i in 1..10 implicitly declares i with its scope as the loop, so the other i you declared at the top is a different variable and not used.
You are allowed to use spaces for readability, so
update stud_ans_sheet
set score=corr_ans-wrong_ans*0.25+unattempt_ans
where ...
can be written more clearly as
update stud_ans_sheet
set score = corr_ans - wrong_ans * 0.25 + unattempt_ans
where ...;
Probably you should focus on one error at a time rather than dumping the whole thing here for review.

I have changed some of your code, try this:
SET SERVEROUTPUT ON;
DECLARE
ANSWER VARCHAR (10);
V_CORR STUD_ANS_SHEET.CORR_ANS%TYPE;
V_WRONG STUD_ANS_SHEET.WRONG_ANS%TYPE;
V_UNATTEMPT STUD_ANS_SHEET.UNATTEMPT_ANS%TYPE;
STR1 VARCHAR (40);
STR2 VARCHAR (40);
BEGIN
ANSWER := 'AACCABAABD';
FOR R_STUD IN (SELECT STUD_NO, ANS
FROM STUD_ANS_SHEET)
LOOP
V_CORR := 0;--It's better to have only one update
V_WRONG := 0;
V_UNATTEMPT := 0;
FOR I IN 1 .. 10
LOOP
STR2 := SUBSTR (R_STUD.ANS, I, 1);
STR1 := SUBSTR (ANSWER, I, 1);
IF (STR2 = STR1)
THEN
V_CORR := V_CORR + 1;
ELSIF (STR2 = 'E')
THEN
V_UNATTEMPT := V_UNATTEMPT + 1;
ELSE
V_WRONG := V_WRONG + 1;
END IF;
END LOOP;
UPDATE STUD_ANS_SHEET
SET SCORE = V_CORR- V_WRONG* 0.25 + V_UNATTEMPT,
CORR_ANS = V_CORR,
WRONG_ANS = V_WRONG,
UNATTEMPT_ANS = V_UNATTEMPT
WHERE R_STUD.STUD_NO = STUD_NO;
END LOOP;
END;
/

SET SERVEROUTPUT ON;
DECLARE
aswer varchar (10);
v_corr number(3);
v_wrong number (3);
v_unattempt number (3);
str1 VARCHAR (10);
str2 VARCHAR (10);
BEGIN
answer:= 'AACCABAABD';
FOR v_stud in c_stud
LOOP
v_corr:= 0;
v_wrong:= 0;
v_unattempt := 0;
FOR I IN 1 .. 10
LOOP
str2 := SUBSTR (v_stud.ans, i, 1);
str1 := SUBSTR (answer, i, 1);
IF (str2 = str1)
THEN
v_corr := v_corr + 1;
ELSIF (str2 = 'E')
THEN
v_unattempt := v_unattempt + 1;
else
v_wrong:= v_wrong + 1;
END IF;
END LOOP;
UPDATE stud_ans_sheet
SET
corr_ans= v_corr,
wrong_ans = v_wrong,
unattempt_ans=v_unattempt , score = v_corr- v_wrong* 0.25,
WHERE stud_no= v_stud.stud_no;
END LOOP;
END;
/

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;

Procedure with refcursor .refcursor should be out parameter

Please help me writing a program procedure with refcursor. Refcursor should be out parameter.
If i give input deptno it shows employee details in that department,also write unit testing block :
I tried like:
CREATE OR REPLACE PROCEDURE poph (i IN NUMBER, p OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p FOR 'select * from emp where deptno=' || i;
FOR i IN p
LOOP
DBMS_OUTPUT.put_line (i.ename || '**' || i.JOB);
END LOOP;
CLOSE p;
END;
/
///////unit testing/////
DECLARE
M NUMBER := '&n';
n SYS_REFCURSOR;
BEGIN
poph (M, n);
END;
You are making 2 mistakes.
1) Openin a refcursor for dynamic select statement which will not work without execute immediate statement.
OPEN p FOR 'select * from emp where deptno=' || i;
2) Looping through a ref cursor which is not valid;
FOR i IN p
Do it this way:
CREATE OR REPLACE PROCEDURE poph (i IN NUMBER, p OUT SYS_REFCURSOR)
IS
v_sql varchar2(100);
BEGIN
v_sql := 'select employee_id,salary from employee where employee_id=' || i;
execute immediate v_sql;
OPEN p FOR v_sql;
END;
/
///////unit testing/////
DECLARE
M NUMBER := '&n';
n SYS_REFCURSOR;
v_emp_id NUMBER;
v_sal NUMBER;
BEGIN
poph (M, n);
LOOP
FETCH n INTO v_emp_id, v_sal;
EXIT WHEN n%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (v_emp_id);
END LOOP;
END;

decoding clob in oracle and then encoding this blob in classic asp does not give the same clob

I have two column in a table whose datatype are clob and blob . I insert a clob data in clob column and insert this data to blob data by decoding this clob in oracle by the following code :
function decode_base64(p_clob_in in clob) return blob is
v_blob blob;
v_result blob;
v_offset integer;
v_buffer_size binary_integer := 48;
v_buffer_varchar varchar2(48);
v_buffer_raw raw(48);
begin
if p_clob_in is null then
return null;
end if;
dbms_lob.createtemporary(v_blob, true);
v_offset := 1;
for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) loop
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
v_offset := v_offset + v_buffer_size;
end loop;
v_result := v_blob;
dbms_lob.freetemporary(v_blob);
return v_result;
end decode_base64;
Then I get this blob data in asp.net by the following code :
strSQL ="SELECT BIO_DATA FingerData , DATA_LENGTH len_of_data , SERIAL_NO sl_no FROM FP_BIOMETRIC_DATA WHERE CUST_NO =" & trim(Request("name")) & " "
Set objExec = Conn.Execute(strSQL)
fingerData1 = objExec("FingerData")
Then I am encoding this data into base64 by the following code :
Function Base64Encode(sText)
Dim oXML, oNode
Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
Set oNode = oXML.CreateElement("base64")
oNode.dataType = "bin.base64"
oNode.nodeTypedValue =sText
Base64Encode = oNode.text
Set oNode = Nothing
Set oXML = Nothing
End Function
Then I am trying to compare this data and clob data in oracle database by this website . This website tells that the two data are different . Why ? Where is the error ? How can I get blob data by decoding a clob data in oracle ?
I think the problem is at this line
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_size is fixed at 48 characters, however your BASE64 string may contain NEW_LINE characters which are ignored for decoding but they are counted for v_buffer_size.
You have to remove all NEW_LINE characters before you read your buffer or increase value of v_buffer_size by number of NEW_LINE characters in substring.
Try this one:
CREATE OR REPLACE FUNCTION DecodeBASE64(InBase64Char IN OUT NOCOPY CLOB) RETURN BLOB IS
res BLOB;
clob_trim CLOB;
dest_offset INTEGER := 1;
src_offset INTEGER := 1;
read_offset INTEGER := 1;
ClobLen INTEGER;
amount INTEGER := 1440; -- must be a whole multiple of 4
buffer RAW(1440);
stringBuffer VARCHAR2(1440);
BEGIN
IF DBMS_LOB.GETLENGTH(InBase64Char) IS NULL THEN
RETURN NULL;
END IF;
-- Remove all NEW_LINE from base64 string
ClobLen := DBMS_LOB.GETLENGTH(InBase64Char);
DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL);
DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer);
read_offset := read_offset + amount;
END LOOP;
read_offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(clob_trim);
DBMS_LOB.CREATETEMPORARY(res, TRUE);
LOOP
EXIT WHEN read_offset > ClobLen;
buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset)));
DBMS_LOB.WRITEAPPEND(res, DBMS_LOB.GETLENGTH(buffer), buffer);
read_offset := read_offset + amount;
END LOOP;
RETURN res;
END DecodeBASE64;

an INTO clause is expected in this SELECT statement when working with PLSQL

I am getting the following error. Getting the error at SELECT CASE statement.
PLS-00428: an INTO clause is expected in this SELECT statement
FOR REMS IN cur_names LOOP
SELECT CASE
WHEN EXISTS (SELECT 1
FROM SupplyTable
WHERE FirstName = REMS.Names)
THEN 'Y'
ELSE 'N'
END AS rec_exists
FROM dual;
IF rec_exists = 'Y' THEN
FName := REMS.Names;
ELSE
FName := 'Gen';
END IF;
END LOOP;
you canĀ“t have a random select inside your pl sql code. It must be in a loop, cursor, with an into clause. Just include an into clause here.
declare
v_value varchar2(1);
begin
...
FOR REMS IN cur_names LOOP
SELECT CASE
WHEN EXISTS (SELECT 1
FROM SupplyTable
WHERE FirstName = REMS.Names)
THEN 'Y'
ELSE 'N'
END AS rec_exists
INTO v_value
FROM dual;
IF v_value = 'Y' THEN
FName := REMS.Names;
ELSE
FName := 'Gen';
END IF;
END LOOP;
...
or a loop
FOR REMS IN cur_names LOOP
for i in
(
SELECT CASE
WHEN EXISTS (SELECT 1
FROM SupplyTable
WHERE FirstName = REMS.Names)
THEN 'Y'
ELSE 'N'
END AS rec_exists
FROM dual
)
loop
IF i.rec_exists = 'Y' THEN
FName := REMS.Names;
ELSE
FName := 'Gen';
END IF;
end loop;
END LOOP;
You need to store the output somewhere , like a variable. REC_EXISTS is a column, so right after the select it no longer exists.
Try this:
declare rec_exists varchar2(1);;
FOR REMS IN cur_names LOOP
SELECT CASE
WHEN EXISTS (SELECT 1
FROM SupplyTable
WHERE FirstName = REMS.Names)
THEN 'Y'
ELSE 'N'
END into rec_exists
FROM dual;
IF rec_exists = 'Y' THEN
FName := REMS.Names;
ELSE
FName := 'Gen';
END IF;
END LOOP;

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 ;

Resources