i have a PROCEDURE like this, whenever i execute the procedure it will give result in cursor according select type:
create or replace PROCEDURE EMAT_PROC_DROPDOWN_SELECTALL(SELECT_TYPE IN VARCHAR2, RESULT_SET OUT SYS_REFCURSOR)
AS
SELECT_TYPE_IN VARCHAR2(100);
TABLE_NAME VARCHAR2(100);
FIELD_NAME VARCHAR2(100);
C_ZONE SYS_REFCURSOR;
C_USER_ID SYS_REFCURSOR;
BEGIN
SELECT_TYPE_IN:=SELECT_TYPE;
IF(SELECT_TYPE_IN ='ZONE') THEN
BEGIN
TABLE_NAME:='MM_ZONEMASTER';
FIELD_NAME:='ZONE_NAME';
OPEN C_ZONE FOR
'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
LOOP
FETCH C_ZONE INTO RESULT_SET;
EXIT WHEN C_ZONE%NOTFOUND;
END LOOP;
CLOSE C_ZONE;
END;
ELSIF(SELECT_TYPE_IN ='USER') THEN
BEGIN
TABLE_NAME:='AD_USERMASTER';
FIELD_NAME:='USER_ID';
OPEN C_USER_ID FOR
'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
LOOP
FETCH C_USER_ID INTO RESULT_SET;
EXIT WHEN C_USER_ID%NOTFOUND;
END LOOP;
CLOSE C_ZONE;
END;
END IF;
END;
but the returns the error ***ORA-00972: identifier is too long
ORA-06512: at "EMAT.EMAT_PROC_DROPDOWN_SELECTALL", line 14
ORA-06512: at line 7
This is the issue: 'SELECT DISTINCT' ||FIELD_NAME|| 'FROM' ||TABLE_NAME||';';
It will see it as SELECT DISTINCTZONE_NAMEFROMMM_ZONEMASTER
The same goes for the other one.
Add spaces and write it as SELECT DISTINCT ' ||FIELD_NAME|| ' FROM ' ||TABLE_NAME||';';
There are missing space in the cursor around the field name and the table name. It reads SELECT DISTINCTZONE_NAMEFROMMM_ZONEMASTER; instead of SELECT DISTINCT ZONE_NAME FROM MM_ZONEMASTER;
Replace that line by this should help :
'SELECT DISTINCT ' ||FIELD_NAME|| ' FROM ' ||TABLE_NAME||';';
Additionally be careful with the use of nested blocks in your IF. I would avoid abusing from it if it's not needed.
Related
I am trying to query the dba_tables, if table "SPLIT_EXT_INFO" not present i am getting correct output, if table "SPLIT_EXT_INFO" exist i am getting below error,
SET serveroutput ON
DECLARE
t_cnt NUMBER;
v_schema_name VARCHAR2(40) := 'DBA';
v_table_name VARCHAR2(40) := 'SPLIT_EXT_INFO';
refcur SYS_REFCURSOR;
split_mapper VARCHAR2(40);
info_tab VARCHAR2(40);
tracker VARCHAR2(40);
BEGIN
SELECT Count(1)
INTO t_cnt
FROM dba_tables
WHERE owner = v_schema_name
AND table_name = v_table_name;
dbms_output.Put_line(t_cnt);
IF t_cnt = 0 THEN
dbms_output.Put_line('NO_SPLIT_TAB');
ELSE
OPEN refcur FOR 'SELECT split_mapper, info_tab, tracker FROM '
||v_schema_name
||'.'
||v_table_name
|| 'where nodename = ''host1.world.com''';
LOOP
FETCH refcur INTO split_mapper,info_tab,tracker;
EXIT WHEN refcur%NOTFOUND;
dbms_output.Put_line(split_mapper
||':'
||info_tab
||':'
||tracker);
END LOOP;
IF refcur%rowcount = 0 THEN
dbms_output.Put_line('NO_SPLIT_ENTRY');
END IF;
END IF;
CLOSE refcur;
END;
/
Error:
1
DECLARE
*
ERROR at line 1:
ORA-00933: SQL command not properly ended
ORA-06512: at line 21
can someone add help in this, thanks !
Regards
Kannan
The apostrophe symbol is on a wrong place before WHERE clause is being concatenated
your code: || 'where nodename = ''host1.world.com''';
right is : ||' where nodename = ''host1.world.com''';
In your version the sql will look like
select ... FROM tableWHERE nomename = ...
The missing space symbol between table name and WHERE causing this problem
I need to make two cursors or one cursor and a loop. But one must be inside other. I'm trying with two cursors and with a for but don't recognize me the variable value of name table of the outside cursor.
Could you help me? Could you suggest me the best way to do these? I'm newbie with pl/sql. Thanks. I put the code:
DECLARE
TABLENAME VARCHAR2(30);
LINK VARCHAR2(30);
CURSOR FIRST_SELECT IS
SELECT A.TABLE_NAME AS TABLENAME, B.LINK AS LINK
FROM ALL_TABLES A, TABLE_CONNECT_LINK B
WHERE A.TABLE_NAME=B.COMPARE_TABLE;
BEGIN
OPEN FIRST_SELECT;
LOOP
FETCH FIRST_SELECT INTO TABLENAME,LINK;
EXIT WHEN FIRST_SELECT%NOTFOUND;
DECLARE
PEPELU VARCHAR2(4000);
TABLE VARCHAR2(70);
stringconsult VARCHAR2(4000);
COMPONENTE NUMBER(5);
TABLE_INSERTAR VARCHAR2(30);
COLUMN VARCHAR2(30);
OWNER VARCHAR2(30);
CURSOR ALL IS
SELECT TABLE,COLUMN,OWNER FROM TABLENAME;
BEGIN
OPEN ALL;
LOOP
FETCH ALL INTO TABLE,COLUMN,OWNER;
EXIT WHEN ALL%NOTFOUND;
stringconsult:='select ' || owner||','|| TABLE||','|| COLUMN||' from ' || INSERTNAME || ' minus select owner, table_name, column_name from all_tab_columns#'|| LINK||'';
DBMS_OUTPUT.PUT_LINE(stringconsult || ';');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
COMMIT;
END LOOP;
CLOSE ALL;
END;
END LOOP;
CLOSE FIRST_SELECT;
END;
/
Need help with code and error. After executing this code:
CREATE OR REPLACE DIRECTORY dir_vezba AS '/home/oracle/vezba';
CREATE OR REPLACE PROCEDURE raise_salary
(p_deptno IN NUMBER, p_per IN NUMBER)
...
END raise_salary;
/
SET VERIFY OFF
DECLARE
v_deptno NUMBER;
v_per NUMBER;
v_oldsalary employees.salary%TYPE;
v_newsalary employees.salary%TYPE;
file_handle UTL_FILE.FILE_TYPE;
f_handle UTL_FILE.FILE_TYPE;
file_line VARCHAR2(200);
f_body VARCHAR2(200);
f_line VARCHAR2(200);
f_head VARCHAR2(200);
file_report VARCHAR2(150);
CURSOR emp_cursor IS
SELECT employee_id, salary
FROM employees
WHERE department_id=v_deptno;
BEGIN
f_handle:=UTL_FILE.FOPEN('DIR_VEZBA','POVECANJE_DEP.txt','r');
LOOP
BEGIN
UTL_FILE.GET_LINE(f_handle, file_line);
EXCEPTION
WHEN NO_DATA_FOUND THEN
EXIT;
END;
v_deptno:=TO_NUMBER(SUBSTR(file_line,1,3));
v_per:=TO_NUMBER(SUBSTR(file_line,4,3))/1000;
file_report:='IZVESTAJ'||TO_CHAR(SYSDATE, 'YY')||TO_CHAR(v_deptno)||'.log';
file_handle:=UTL_FILE.FOPEN('DIR_VEZBA', file_report, 'w');
UTL_FILE.PUTF(file_handle, 'Report generated on: '||SYSDATE||' for department: '||v_deptno);
UTL_FILE.NEW_LINE(file_handle);
UTL_FILE.NEW_LINE(file_handle);
f_head:='EMPNO OLD_SALARY NEW_SALARY';
UTL_FILE.PUTF(file_handle, f_head);
UTL_FILE.NEW_LINE(file_handle);
f_line:='=================================';
UTL_FILE.PUTF(file_handle, f_line);
UTL_FILE.NEW_LINE(file_handle);
FOR emp_rec IN emp_cursor
LOOP
v_oldsalary:=emp_rec.salary;
raise_salary(v_deptno, v_per);
SELECT salary
INTO v_newsalary
FROM employees
WHERE employee_id=emp_rec.employee_id;
f_body:=RPAD(emp_rec.employee_id,9,' ')||RPAD(v_oldsalary,14,' ')||RPAD(v_newsalary,10,' ');
UTL_FILE.PUTF(file_handle, f_body);
UTL_FILE.FCLOSE(file_handle);
END LOOP;
END LOOP;
UTL_FILE.FCLOSE(f_handle);
EXCEPTION
WHEN UTL_FILE.INVALID_OPERATION THEN
file_report:='IZVESTAJ'||TO_CHAR(SYSDATE, 'YY')||'.bad';
file_handle:=UTL_FILE.FOPEN('DIR_VEZBA', file_report, 'w');
UTL_FILE.PUTF(file_handle, 'NO FILE FOUND');
UTL_FILE.FCLOSE(file_handle);
END;
/
I get this error:
ORA-29282: invalid file ID
ORA-06512: at "SYS.UTL_FILE", line 1071
ORA-06512: at line 48
Don't know what's the problem with this and what does it means. Besides that, in output I get only one line txt file and nothing else. It should get me 3 text fles with different number of lines in them, depending on the data in tables.
This is your problem:
FOR emp_rec IN emp_cursor
LOOP
v_oldsalary:=emp_rec.salary;
raise_salary(v_deptno, v_per);
SELECT salary
INTO v_newsalary
FROM employees
WHERE employee_id=emp_rec.employee_id;
f_body:=RPAD(emp_rec.employee_id,9,' ')||RPAD(v_oldsalary,14,' ')||RPAD(v_newsalary,10,' ');
UTL_FILE.PUTF(file_handle, f_body);
----------> UTL_FILE.FCLOSE(file_handle); <-----------
END LOOP;
You close the file while in the loop, so at the next iteration the PUTF will fail.
It has been my experience that the directory name must be in ALL CAPS, but the filename must be all lower case. I know it sounds stupid, and it probably is, but if no other answer has solved your problem, what have you got to lose by trying this?
How I could print recorset result from the returning cursor, please.
Down below executes fine but I need to see result.
This is block in TOAD, calling package sp AMD_NEEDMSG:
DECLARE
RETURN_RECORDSET CTI_MATRIX.AMD.REF_CURSOR;
BEGIN
CTI_MATRIX.AMD.AMD_NEEDMSG ( '88888888885', RETURN_RECORDSET );
END;
This package spec:
CREATE OR REPLACE PACKAGE CTI_MATRIX.AMD AS
TYPE REF_CURSOR IS REF CURSOR;
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR);
END AMD;
This is package body:
CREATE OR REPLACE PACKAGE BODY CTI_MATRIX.AMD AS
PROCEDURE AMD_NEEDMSG (v_CRN IN VARCHAR2, return_recordset OUT REF_CURSOR) IS
return_flag INTEGER;
row_cnt INTEGER;
number_of_days INTEGER;
var_DATE DATE;
CURSOR ACCNTSEARCH (P_CRN IN VARCHAR2) IS
SELECT DISTINCT COUNT(*) , AMD.MSG_DATE
FROM TBL_AMD_NEEDMSG AMD
WHERE AMD.PHONE_NUMBER = P_CRN AND ROWNUM = 1;
BEGIN
OPEN ACCNTSEARCH(v_CRN);
FETCH ACCNTSEARCH INTO row_cnt, var_DATE;
CLOSE ACCNTSEARCH;
IF (row_cnt = 0)
THEN
INSERT INTO TBL_AMD_NEEDMSG (PHONE_NUMBER, MSG_DATE) VALUES (v_CRN , SYSDATE);
return_flag := 1;
ELSE
SELECT SYSDATE-var_DATE INTO number_of_days FROM dual;
IF (number_of_days>7)
THEN
UPDATE TBL_AMD_NEEDMSG SET MSG_DATE = SYSDATE WHERE PHONE_NUMBER = v_CRN;
return_flag := 1;
ELSE
return_flag := 0;
END IF;
END IF;
COMMIT;
OPEN return_recordset FOR
SELECT return_flag AS ReturnFLag FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END AMD_NEEDMSG;
END AMD;
/
Bottom line is to return to client a value of return_flag in the form of record set.
To return the return_flag, which is int=1 or 0 you need function that returns a single value, not recordset. Below are general recordset examples - hope this helps:
DECLARE
TYPE empcurtyp IS REF CURSOR;
emp_cv empcurtyp;
--
TYPE namelist IS TABLE OF scott.emp.ename%TYPE;
TYPE sallist IS TABLE OF scott.emp.sal%TYPE;
names namelist;
sals sallist;
BEGIN
OPEN emp_cv FOR
SELECT ename, sal FROM scott.emp
WHERE job = 'MANAGER' ORDER BY sal DESC;
--
FETCH emp_cv BULK COLLECT INTO names, sals;
CLOSE emp_cv;
-- loop through the names and sals collections
FOR i IN names.FIRST .. names.LAST LOOP
DBMS_OUTPUT.PUT_LINE
('Name = ' || names(i) || ', salary = ' || sals(i));
END LOOP;
END;
/
-- SYS_REFCURSOR example --
DECLARE
p_rc_type SYS_REFCURSOR;
emp_rec scott.emp%ROWTYPE;
--
PROCEDURE p_Emp_Info (p_cur_var OUT SYS_REFCURSOR)
IS
BEGIN
OPEN p_cur_var FOR
SELECT ename, job FROM scott.emp WHERE job = 'MANAGER';
LOOP
FETCH p_cur_var INTO emp_rec.ename, emp_rec.job;
EXIT WHEN p_cur_var%NOTFOUND;
dbms_output.put_line(emp_rec.ename ||' '|| emp_rec.job);
END LOOP;
CLOSE p_cur_var;
END p_Emp_Info;
--
BEGIN
p_Emp_Info(p_rc_type);
END;
/
I have a stored procedure that has following pl/sql block. This block was using select query in for statement but i need to change that static variable to dynamic query. As I changed that it has error. Is there any way to use variable with FOR LOOP in implicit cursor.
declare
sql_query varchar2(32767) := 'select ctlchar ';
kpiNameQuery varchar2(600);
isWg boolean := true;
begin
IF isWG then
kpiNameQuery := 'select distinct KPI_NAME from weeklykpi where kpi_name in (select kpi_wg from auxillary.kpi_types) order by 1';
Else
kpiNameQuery := 'select distinct KPI_NAME from weeklykpi where kpi_name in (select kpi_wg1 from auxillary.kpi_types) order by 1';
End IF;
for KPI_NAME in kpiNameQuery
loop
sql_query := sql_query || ' , min(case when KPI_NAME = '''||x.KPI_NAME||''' then KPI_VALUE end) as '||x.KPI_NAME;
dbms_output.put_line(sql_query);
end loop;
end;
You can achieve similar functionality with the following using cursor
declare
type t_cursor is ref cursor;
c_cursor t_cursor;
l_sql varchar2(512);
l_var number;
begin
l_sql := 'select count(*) from emp'; -- do dynamic check before here for
-- correct sql
open c_cursor for l_sql;
loop
fetch c_cursor
into l_var;
exit When c_cursor%notfound;
DBMS_OUTPUT.put_line ('val '||l_var);
end loop;
close c_cursor;
end;
Unfotunately no, the doc states:
If the dynamic SQL statement is a SELECT statement that returns multiple rows, native dynamic SQL gives you these choices:
Use the EXECUTE IMMEDIATE statement with the BULK COLLECT INTO clause.
Use the OPEN FOR, FETCH, and CLOSE statements.
So you will have to use a REF cursor (or EXECUTE IMMEDIATE and loop over the results).
Incidentally, in your case you could go for static SQL and have comparable performance:
BEGIN
FOR cc IN (SELECT DISTINCT KPI_NAME
FROM weeklykpi
WHERE kpi_name IN (SELECT CASE WHEN l_variable = 1
THEN kpi_wg
ELSE kpi_wg1
END
FROM auxillary.kpi_types) LOOP
ORDER BY 1
-- do something
END LOOP;
END;
You'll have to use some other type than boolean though since it's unknown to SQL.