I've written a procedure in PL SQL which works with tables and indexes. When I run my procedure for the first time I get this error, but at the second time everything is ok. Does anybody know how to fix this?
Error at line 2
ORA-00904: "SYS_NC00061 $": invalid identifier
ORA-00942: table or view does not exist
PROCEDURE create_archive_tables
IS
l_whoami run_signature_t := run_signature_t (g_package,
'CREATE_ARCHIVE_TABLES');
--define variable
v_table_name hot_utils_archive.table_name%TYPE;
v_db_user VARCHAR2 (70);
v_index_name VARCHAR2 (400);
v_table_name_i VARCHAR2 (400);
v_tablespace VARCHAR2 (400);
v_columns VARCHAR2 (1000);
v_sql_stmt_table_exist VARCHAR2(32767);
v_sql_stmt VARCHAR2 ( 32767 );
v_sql_stmt_index VARCHAR2 ( 32767 );
--EXCEPTION
table_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -00942);
-- CURSOR for table names
CURSOR c_archive_table_name IS
select table_name
from hot_utils_archive;
-- CURSOR for Indexes
CURSOR c_index_tables IS
select a.index_name, a.table_name, a.TABLESPACE_NAME, LISTAGG(b.COLUMN_NAME, ',') WITHIN GROUP (ORDER BY b.COLUMN_NAME) AS columns
from user_indexes a INNER JOIN user_ind_columns b
ON a.index_name = b.index_name
where a.table_name in (select table_name from hot_utils_archive)
group by a.INDEX_NAME, a.TABLE_NAME, a.TABLESPACE_NAME;
BEGIN
trace.log_proc_start ( l_whoami );
DBMS_OUTPUT.enable ( NULL );
SELECT USER INTO v_db_user FROM DUAL;
OPEN c_archive_table_name;
LOOP
FETCH c_archive_table_name
INTO v_table_name ;
EXIT WHEN c_archive_table_name%NOTFOUND;
BEGIN
v_sql_stmt_table_exist := 'select * from '
|| v_db_user || '_ARCHIVE.' || v_table_name || ' WHERE rownum=1';
EXECUTE IMMEDIATE(v_sql_stmt_table_exist);
EXCEPTION
WHEN table_does_not_exist THEN
--Create table in Archive DB
v_sql_stmt :=
'CREATE TABLE '
|| v_db_user || '_ARCHIVE.' || v_table_name
|| ' AS SELECT * FROM ' || v_table_name
||' WHERE client = ''noname'''
;
--DBMS_OUTPUT.put_line(v_sql_stmt);
EXECUTE IMMEDIATE ( v_sql_stmt );
--Create indexes
open c_index_tables;
LOOP
FETCH c_index_tables
INTO v_index_name, v_table_name_i, v_tablespace, v_columns;
EXIT WHEN c_index_tables%NOTFOUND;
IF v_table_name = v_table_name_i
THEN
v_sql_stmt_index :=
'CREATE INDEX ' || v_db_user || '_ARCHIVE.'
|| v_index_name || ' ON ' || v_db_user || '_ARCHIVE.' || v_table_name
|| ' (' || v_columns || ') TABLESPACE '
|| v_db_user || '_ARCHIVE_INDEX'
;
--DBMS_OUTPUT.put_line(v_sql_stmt_index);
EXECUTE IMMEDIATE ( v_sql_stmt_index );
END IF;
END LOOP;
CLOSE c_index_tables;
END;
END LOOP;
CLOSE c_archive_table_name;
EXCEPTION
WHEN OTHERS THEN
trace.log_proc_fail (l_whoami, error.getText (constants.c_unhandled_exception, trace.get_proc_name (l_whoami), SQLERRM));
RAISE;
END create_archive_tables;
Related
Scenario:
Write a PL/SQL block that takes a department number from a user and increases the salary of all the employees belonging to the department by 10%. The block should display on the screen how many records are updated.
My Program:
DECLARE
V_TOT_ROWS NUMBER(3);
CURSOR emp_cursor IS
SELECT EMPSAL FROM emp WHERE deptno=&DEPT_NO
FOR UPDATE OF EMPSAL NOWAIT;
BEGIN
FOR emp_record IN emp_cursor
LOOP
UPDATE emp
SET EMPSAL=EMPSAL+emp_record.EMPSAL*0.1
WHERE CURRENT OF emp_cursor;
-- V_TOT_ROWS := SQL%ROWCOUNT;
-- DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END LOOP;
COMMIT;
-- DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END;
It is giving 1 row updated every time the loop is executed but if I keep the dbms_output outside the loop, it gives 0.
Please help.
Thanks,
Please check below Script:
declare V_TOT_ROWS NUMBER(3) :=0;
CURSOR emp_cursor IS
SELECT EMPSAL FROM emp WHERE deptno=&DEPT_NO
FOR UPDATE OF EMPSAL NOWAIT;
begin FOR emp_record IN emp_cursor
LOOP
UPDATE emp
SET EMPSAL=EMPSAL+emp_record.EMPSAL*0.1
WHERE CURRENT OF emp_cursor;
V_TOT_ROWS := V_TOT_ROWS+SQL%ROWCOUNT;
-- DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
-- DBMS_OUTPUT.PUT_LINE('Updated ' || SQL%ROWCOUNT || ' salaries.');
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Updated ' || V_TOT_ROWS || ' salaries.'); end;
Use simple update instead of a cursor + forall.
If you use FORALL ... UPDATE, then only 1 record is updated in each loop cycle, so UPDATE returns SQL%ROWCOUNT always = 1.
DECLARE
V_TOT_ROWS NUMBER(3);
BEGIN
UPDATE emp
SET EMPSAL= EMPSAL+ EMPSAL*0.1
WHERE deptno=&DEPT_NO;
V_TOT_ROWS := SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE('TOTAL UPDATED RECORDS: ' || V_TOT_ROWS);
COMMIT;
END;
/
The problem statement: The user would specify a name based on which I have to pull names of two tables from a table and then extract values from those tables.I have created a pl/sql procedure for that and since the select query can return n number of rows I'm using Bulk Collect. I have created and object based on the fields I want to extract. Now the problem is that the columns are common in both the tables, so if I don't use alias I get ambiguous column error and if I use that I get the error of unimplemented feature.
here's my code:
create or replace type recon_obj_vib
is object (RECON_TABLE_KEY NUMBER(19)
,RECON_CHGLOGATTR_IDXLST VARCHAR2(1000 CHAR));
create or replace type recon_tab_vib
is table of recon_obj_vib;
create or replace PROCEDURE noMatchReport_proc(tableDesc IN VARCHAR2)
IS
l_recon_tab_vib recon_tab_vib := recon_tab_vib();
n Integer :=0;
out varchar2(2000);
tableName1 varchar2(25);
tableName2 varchar2(25);
tableDesc_without_space varchar2(25);
tableDesc_ra varchar2(25);
BEGIN
tableDesc_without_space:=Regexp_Replace(tableDesc,'\s');
tableDesc_ra:=UPPER('RA_' || tableDesc_without_space || ' %');
out:= 'Select recon_table_name from recon_tables where recon_table_desc = (:value) and rownum=1 and RECON_TABLE_name like (:userName)';
execute immediate out into tableName1 USING tableDesc,tableDesc_ra;
out:= 'Select recon_table_name from recon_tables where recon_table_desc = (:value) and rownum=1 and RECON_TABLE_name not like (:userName)';
execute immediate out into tableName2 USING tableDesc,tableDesc_ra;
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST BULK COLLECT INTO l_recon_tab_vib from ' || tableName1 || ' a , ' || tableName2 || ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate out into l_recon_tab_vib;
FOR i IN 1..l_recon_tab_vib.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE('RECON_TABLE_KEY '|| l_recon_tab_vib(i).RECON_TABLE_KEY ||' RECON_CHGLOGATTR_IDXLST ' || l_recon_tab_vib(i).RECON_CHGLOGATTR_IDXLST );
END LOOP;
END;
This part:
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST BULK COLLECT INTO l_recon_tab_vib from ' || tableName1 || ' a , ' || tableName2 || ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate out into l_recon_tab_vib;
Should be:
out:='Select a.RECON_TABLE_KEY,a.RECON_CHGLOGATTR_IDXLST from '
|| tableName1 || ' a , ' || tableName2
|| ' b where a.RE_KEY = b.RE_KEY and rownum=1';
execute immediate bulk collect into l_recon_tab_vib;
i.e. the BULK COLLECT INTO clause is part of the calling PL/SQL not part of the dynamic SQL.
Using Flyway 3.2.1. Calling from command line in windows.
This line seems to be causing an error due to a parsing issue by flyway. Will a fix be available in a future release?
Statement That fails:
INSERT INTO CODE_TYPE_DISPLAY_TEMP (OBJECT_ID, LANG_CD, CREATE_DT, CREATE_USER_CD, DISPLAY_TXT) (SELECT CD_TYP_ID,'AMERICAN',SYSDATE,'CONVERSION','From Term Period Type' FROM CODE_TYPE WHERE CD_GRP_CD = 'DDE_FIELD_NME_TYP' AND CD_TYP_CD='FROM_TERM_PERIOD_DT_TYP');
SOLUTION:
Added || in the 2 words FROM and now it works.
INSERT INTO CODE_TYPE_DISPLAY_TEMP (OBJECT_ID, LANG_CD, CREATE_DT, CREATE_USER_CD, DISPLAY_TXT) (SELECT CD_TYP_ID,'AMERICAN',SYSDATE,'CONVERSION','Fr' || 'om Term Period Type' FROM CODE_TYPE WHERE CD_GRP_CD = 'DDE_FIELD_NME_TYP' AND CD_TYP_CD='FR' || 'OM_TERM_PERIOD_DT_TYP');
Another example of insert that fails.
--##################################################################################
--## Table(s) UPDATED: LABEL and
--## LABEL_DISPLAY
--##
--##
--## NOTE: The user can now modify the Display_txt.
--## Rule: In Label_Display> If DT != ODT then the user has modifed.
--##
--## {-13} in txt is converted to a CR
--## {-10} in txt is converted to a LF
--##
--##################################################################################
--SET SERVEROUTPUT ON SIZE UNLIMITED;
begin
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>===========================');
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>= PROCESS LABELS <STARTS>');
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>===========================');
end;
/
-------------------------------------------------------
-- STEP 2
-- Create the table to hold the raw data from .dat files
-------------------------------------------------------
CREATE TABLE DB_GIT_LABEL
( -- < TGT TBL MAPPINGS >
LABEL_ID VARCHAR2(10 CHAR), -- Label_ID
LABEL_KEY VARCHAR2(100 CHAR), -- Label_Key
MAX_SHORT_LENGTH_NBR VARCHAR2(3 CHAR), -- Max_Short_Length_Nbr
DISPLAY_TXT VARCHAR2(4000 CHAR) -- [LABEL_DISPLAY] Display_Txt, Short_Display_Txt, Orig_Display_Txt
);
--######################################################################################
--# STEP 3
--# Inserts go here
--# SAMPLE: INSERT INTO DB_GIT_LABEL VALUES('LABEL_ID','LABEL_KEY','30','DISPLAY_TXT');
--######################################################################################
INSERT INTO DB_GIT_LABEL VALUES('0000','0518.fr' || 'om','30','Fr' || 'om');
INSERT INTO DB_GIT_LABEL VALUES('0001','0518.from','30','From');
--######################################################################################
--######################################################################################
COMMIT;
--######################################################################################
--######################################################################################
----------------------------------
-- DROP THE TEMP TABLE(S)
----------------------------------
DROP TABLE DB_GIT_LABEL cascade constraints purge;
begin
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>===========================');
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>= PROCESS LABELS <ENDS>');
DBMS_OUTPUT.PUT_LINE('SCRIPT' || '_FYI:> ' || TO_CHAR (SYSDATE, 'HH24:MI:SS') || '>===========================');
end;
/
I get all the time an problem with the following snipped from my PL/SQL procedure
I need the variables to create an dynamic SQL statement, but i also need the nested table.
l_code list_code := list_code();
l_code := PKG_DATA.GET_CODES(in_code) ;
v_sql := 'SELECT ' || in_var_name ||'
FROM view
WHERE supplier = '||in_supplier ||'
AND factory = '|| in_factory ||'
AND code IN ('|| ( SELECT * FROM TABLE(l_code) )||') ';
EXECUTE IMMEDIATE v_sql
INTO v_value;
v_value is an nested table
[Error] PLS-00103 (60: 46): PLS-00103: Encountered the symbol "SELECT"
when expecting one of the following:
( - + case mod new not null continue, [Error] PLS-00103
(60: 74): PLS-00103: Encountered the symbol ")" when expecting one of
the following:
, ; for
as group having intersect minus order start union wh
Does anyone have an idea or an snipped ?
thx
v_sql := 'SELECT ' || in_var_name
|| ' FROM view '
|| ' WHERE supplier = :supplier AND factory = :factory '
|| ' AND code IN (SELECT * FROM TABLE(PKG_DATA.GET_CODES(:code)))';
EXECUTE IMMEDIATE v_sql INTO v_value USING in_supplier, in_factory, in_code;
I suggest using bind variables
v_sql := 'SELECT :in_var_name
FROM view
WHERE supplier = :in_supplier
AND factory = :in_factory
AND code IN (SELECT * FROM TABLE(:l_code) )) ';
EXECUTE IMMEDIATE v_sql
INTO v_value
USING in_var_name, in_supplier, in_factory, l_code;
But chances are, that you don't need dynamic SQL at all:
SELECT in_var_name
INTO v_value
FROM view
WHERE supplier = in_supplier
AND factory = in_factory
AND code IN (SELECT * FROM TABLE(l_code));
How to use put function.my procedure is not compiling with put. but putline is working fine. i want to print in the same line
Here's an example of code which uses the UTL_FILE.PUT and UTL_FILE.PUT_LINE calls:
declare
fHandle UTL_FILE.FILE_TYPE;
begin
fHandle := UTL_FILE.FOPEN('my_directory', 'test_file', 'w');
UTL_FILE.PUT(fHandle, 'This is the first line');
UTL_FILE.PUT(fHandle, 'This is the second line');
UTL_FILE.PUT_LINE(fHandle, 'This is the third line');
UTL_FILE.FCLOSE(fHandle);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Exception: SQLCODE=' || SQLCODE || ' SQLERRM=' || SQLERRM);
RAISE;
end;
The output from this looks like:
This is the first lineThis is the second lineThis is the third line
Share and enjoy.
Here is a robust function for using UTL_File.putline that includes the necessary error handling. It also handles headers, footers and a few other exceptional cases.
PROCEDURE usp_OUTPUT_ToFileAscii(p_Path IN VARCHAR2, p_FileName IN VARCHAR2, p_Input IN refCursor, p_Header in VARCHAR2, p_Footer IN VARCHAR2, p_WriteMode VARCHAR2) IS
vLine VARCHAR2(30000);
vFile UTL_FILE.file_type;
vExists boolean;
vLength number;
vBlockSize number;
BEGIN
UTL_FILE.fgetattr(p_path, p_FileName, vExists, vLength, vBlockSize);
FETCH p_Input INTO vLine;
IF p_input%ROWCOUNT > 0
THEN
IF vExists THEN
vFile := UTL_FILE.FOPEN_NCHAR(p_Path, p_FileName, p_WriteMode);
ELSE
--even if the append flag is passed if the file doesn't exist open it with W.
vFile := UTL_FILE.FOPEN(p_Path, p_FileName, 'W');
END IF;
--GET HANDLE TO FILE
IF p_Header IS NOT NULL THEN
UTL_FILE.PUT_LINE(vFile, p_Header);
END IF;
UTL_FILE.PUT_LINE(vFile, vLine);
DBMS_OUTPUT.PUT_LINE('Record count > 0');
--LOOP THROUGH CURSOR VAR
LOOP
FETCH p_Input INTO vLine;
EXIT WHEN p_Input%NOTFOUND;
UTL_FILE.PUT_LINE(vFile, vLine);
END LOOP;
IF p_Footer IS NOT NULL THEN
UTL_FILE.PUT_LINE(vFile, p_Footer);
END IF;
CLOSE p_Input;
UTL_FILE.FCLOSE(vFile);
ELSE
DBMS_OUTPUT.PUT_LINE('Record count = 0');
END IF;
EXCEPTION
WHEN UTL_FILE.INVALID_PATH THEN
DBMS_OUTPUT.PUT_LINE ('invalid_path');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.INVALID_MODE THEN
DBMS_OUTPUT.PUT_LINE ('invalid_mode');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
DBMS_OUTPUT.PUT_LINE ('invalid_filehandle');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.INVALID_OPERATION THEN
DBMS_OUTPUT.PUT_LINE ('invalid_operation');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.READ_ERROR THEN
DBMS_OUTPUT.PUT_LINE ('read_error');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.WRITE_ERROR THEN
DBMS_OUTPUT.PUT_LINE ('write_error');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN UTL_FILE.INTERNAL_ERROR THEN
DBMS_OUTPUT.PUT_LINE ('internal_error');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('other write error');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
RAISE;
END;
You can check the below example of how to log/write using utl_file in PL/SQL.
DECLARE
fhandle utl_file.file_type;
BEGIN
fhandle := utl_file.fopen(
'UTL_DIR_STACKOVERFLOW'-- File location
, 'Check_Logging.txt' -- File name
, 'a' -- Open mode: a = append, w = write
);
utl_file.put(fhandle, 'Stackoverflow' );
utl_file.fclose(fhandle);
END;
Problems you can face-
Invalid directory object
Then you can create your own directory object and use the below query.
create or replace directory UTL_DIR_STACKOVERFLOW as '/tmp/';
CREATE OR REPLACE PROCEDURE SP_EXPORT_TO_CSV(P_OWNER VARCHAR2,
P_OBJECT_NAME VARCHAR2,
P_FILE_NAME VARCHAR2 --,
-- P_DELIMITED CHAR
) AS
-- declaration
TYPE C_DATA_CURSOR IS REF CURSOR;
C_DATA C_DATA_CURSOR;
v_file UTL_FILE.FILE_TYPE;
V_COLUMNS VARCHAR2(32767);
X VARCHAR2(32767);
V_FILE_NAME VARCHAR2(2000);
V_OWNER VARCHAR2(100);
V_OBJECT_NAME VARCHAR2(1000);
V_SQL VARCHAR2(32767);
V_DELIMITED VARCHAR2(10);
BEGIN
-- set value
V_FILE_NAME := P_FILE_NAME;
V_OBJECT_NAME := P_OBJECT_NAME;
V_OWNER := P_OWNER;
--V_DELIMITED:=P_DELIMITED;
SELECT REPLACE(LISTAGG(COLUMN_NAME, '|') WITHIN
GROUP(ORDER BY COLUMN_ID),
'|',
' || ' || '''|''' || ' || ')
INTO V_COLUMNS
FROM ALL_TAB_COLUMNS W
WHERE W.TABLE_NAME = V_OBJECT_NAME
AND W.OWNER = V_OWNER
ORDER BY COLUMN_ID;
-- SET OUTPUT PARAMETER --'EXPORTED_TO_TEXT_LOCATION'
v_file := UTL_FILE.FOPEN(location => 'MYLOCATION',
filename => V_FILE_NAME,
open_mode => 'w',
max_linesize => 32767);
UTL_FILE.PUT_LINE(v_file, REPLACE(V_COLUMNS, ' || ''|'' || ', '|'));
X := 'SELECT ' || V_COLUMNS || ' AS RECORD FROM ' || V_OWNER || '.' ||
V_OBJECT_NAME;
OPEN C_DATA FOR X;
LOOP
FETCH C_DATA
INTO V_SQL;
EXIT WHEN C_DATA%NOTFOUND;
UTL_FILE.PUT_LINE(v_file, V_SQL);
END LOOP;
CLOSE C_DATA;
UTL_FILE.FCLOSE(v_file);
END;