PL/SQL Procedure error ORA-00900: invalid SQL statement - oracle

I am new to PL/SQL and I am trying to make a procedure with 2 cursors and I have no ideea why am I having this error:
ORA-00900: invalid SQL statement
PROCEDURE filme_pret IS
CURSOR planificari_pret_redus (pret_propus NUMBER) IS
SELECT * FROM planificare WHERE pret < pret_propus ;
obiect planificari_pret_redus%rowtype;
CURSOR planificari_pret_normal IS
SELECT * FROM planificare;
obiect2 planificari_pret_normal%rowtype;
BEGIN
dbms_output.put_line('Filme cu pret redus');
for obiect in planificari_pret_redus(100)
LOOP
dbms_output.put_line(obiect.idplanificare || ' ' || obiect.idfilm || ' ' || obiect.pret);
END LOOP;
for obiect2 in planificari_pret_normal
LOOP
dbms_output.put_line(obiect2.idplanificare || ' ' || obiect2.idfilm || ' ' || obiect2.pret);
END LOOP;
END;
Thank you.

The main part of your code is ok, you simply have to decide how to use it; if you want to create a procedure without storing it, you need a complete DECLARE...BEGIN...END block:
DECLARE
/* declare your procedure */
PROCEDURE filme_pret IS
CURSOR planificari_pret_redus(pret_propus NUMBER) IS
SELECT *
FROM planificare
WHERE pret < pret_propus;
obiect planificari_pret_redus%ROWTYPE;
CURSOR planificari_pret_normal IS
SELECT * FROM planificare;
obiect2 planificari_pret_normal%ROWTYPE;
BEGIN
DBMS_OUTPUT.put_line('Filme cu pret redus');
FOR obiect IN planificari_pret_redus(100) LOOP
DBMS_OUTPUT.put_line(obiect.idplanificare || ' ' || obiect.idfilm || ' ' || obiect.pret);
END LOOP;
FOR obiect2 IN planificari_pret_normal LOOP
DBMS_OUTPUT.put_line(obiect2.idplanificare || ' ' || obiect2.idfilm || ' ' || obiect2.pret);
END LOOP;
END;
BEGIN
/* CALL YOU PROCEDURE */
filme_pret;
END;
/
This way your procedure is not stored in DB, and you always need to use the entire block; if you want to create a stored procedure, you need this syntax:
CREATE OR REPLACE PROCEDURE filme_pret IS
CURSOR planificari_pret_redus(pret_propus NUMBER) IS
SELECT *
FROM planificare
WHERE pret < pret_propus;
obiect planificari_pret_redus%ROWTYPE;
CURSOR planificari_pret_normal IS
SELECT * FROM planificare;
obiect2 planificari_pret_normal%ROWTYPE;
BEGIN
DBMS_OUTPUT.put_line('Filme cu pret redus');
FOR obiect IN planificari_pret_redus(100) LOOP
DBMS_OUTPUT.put_line(obiect.idplanificare || ' ' || obiect.idfilm || ' ' || obiect.pret);
END LOOP;
FOR obiect2 IN planificari_pret_normal LOOP
DBMS_OUTPUT.put_line(obiect2.idplanificare || ' ' || obiect2.idfilm || ' ' || obiect2.pret);
END LOOP;
END;
/
After this, you can simply call your procedure in a PL/SQL block:
begin
filme_pret;
end;
/

is that a typo ?
obiect planificari%rowtype;
it seems that planificari doesn't exists.

Related

Oracle Dynamic Cursor - ORA-00936 missing expression

I need to use a dynamic cursor in my procedure which receive values from another cursor.
When I run this procedure I got ORA-00936 missing expression.
I put this select from cursor into dbms_output to see it is correct and it was.
This is the code :
BEGIN
OPEN dsa_tables;
LOOP
FETCH dsa_tables INTO
v_owner,
v_table_name,
v_column_name,
v_comments,
v_tech_date;
EXIT WHEN dsa_tables%notfound;
v_table_all := dbms_assert.sql_object_name(v_owner
|| '.'
|| v_table_name);
-- with this cursor is the problem
OPEN count_date FOR ' SELECT '
|| v_column_name
|| ','
|| ' COUNT('
|| v_column_name
|| ') FROM '
||v_table_all
|| ' GROUP BY '
|| v_column_name;
LOOP
FETCH count_date INTO
v_date,
v_count;
EXIT WHEN count_date%notfound;
END LOOP;
CLOSE count_date;
END LOOP;
CLOSE dsa_tables;
END;
/
You likely have v_column_name set to NULL.
I've already checked it and there is no NULL im this column.

Insert into by chunks

I am trying to use insert into statement, but getting the error:
ORA-01628: max # extents (32765) reached for rollback segment _SYSSMU134_1882489978$
Increasing the UNDO tablespace is not an option, so I would like a way to insert those data by chunks (for example with 1 million rows at a time). Can someone help to rewrite this procedure in that way?
CREATE OR REPLACE PROCEDURE create_chunks (
p_source_table IN VARCHAR2,
p_table_name_chunk IN VARCHAR2,
p_chunks IN VARCHAR2
) AS
v_insert_sql CLOB;
BEGIN
v_insert_sql := 'INSERT INTO ' || p_table_name_chunk ||
' (rid, chunk_number) ' ||
'SELECT /*+ parallel(64) */ rowid rid,' ||
'mod( ora_hash(rowid), :p_chunks ) as chunk_number '
'FROM ' || p_source_table;
EXECUTE IMMEDIATE v_insert_sql USING p_chunks;
COMMIT;
END;
This v_insert_sql is failing with above mentioned error. I have working solution using the cursor fetching like that:
DECLARE
CURSOR v_cur IS SELECT /*+ parallel(64) */
rowid rid, mod( ora_hash(rowid), 20000 ) AS chunk_number
-- I need this table to be parametric name
FROM some_table;
TYPE t_sample IS TABLE OF v_cur%ROWTYPE;
v_sample t_sample;
v_row_limit CONSTANT NUMBER := 1000000;
BEGIN
OPEN v_cur;
LOOP
FETCH v_cur BULK COLLECT INTO v_sample LIMIT v_row_limit;
FORALL i IN v_sample.first .. v_sample.last
INSERT INTO chunk_table VALUES v_sample(i);
COMMIT;
EXIT WHEN v_cur%NOTFOUND;
END LOOP;
CLOSE v_cur;
END;
I can't move this cursor straight into the procedure as the table name is varying and I need it to be parametric as with cursor approach I have to repeat the same code for different tables. So the question is how to deal with this?
Basically, I was able to just past the whole chunks approach inside procedure as dynamic query, like that:
CREATE OR REPLACE PROCEDURE create_chunks (
p_source_table IN VARCHAR2,
p_table_name_chunk IN VARCHAR2,
p_chunks IN VARCHAR2
) AS
v_insert_sql CLOB;
BEGIN
v_insert_sql := '' ||
' DECLARE ' || CHR(10) ||
' CURSOR cur1 IS SELECT ' || CHR(10) ||
' /*+ parallel(64) full(tbn)*/ rowid rid,' || CHR(10) ||
' mod( ora_hash(rowid), :p_chunks ) AS chunk_number' || CHR(10) ||
' FROM ' || p_source_table || ' tbn;' || CHR(10) ||
' TYPE t_sample IS TABLE OF cur1%ROWTYPE;' || CHR(10) ||
' v_sample t_sample;' || CHR(10) ||
' v_row_limit CONSTANT NUMBER := 1000000;' || CHR(10) ||
' BEGIN' || CHR(10) ||
' OPEN cur1;' || CHR(10) ||
' LOOP' || CHR(10) ||
' FETCH cur1 BULK COLLECT INTO v_sample LIMIT v_row_limit;' || CHR(10) ||
' FORALL i IN v_sample.first .. v_sample.last' || CHR(10) ||
' INSERT INTO ' || p_table_name_chunk || ' VALUES v_sample(i);' || CHR(10) ||
' COMMIT;' || CHR(10) ||
' EXIT WHEN cur1%NOTFOUND;' || CHR(10) ||
' END LOOP;' || CHR(10) ||
' CLOSE cur1;' || CHR(10) ||
' END;';
EXECUTE IMMEDIATE v_insert_sql USING p_chunks;
COMMIT;
END;

Gettig error PLS-00364

I'm trying to create a stored procedure where I'm passing select statement to for loop and i'm using dynamic table which is passing at runtime and getting below error:
LINE 23 PLS-00364: loop index variable 'I' use is invalid
LINE 19 PL/SQL: ORA-00942: table or view does not exist
CREATE OR REPLACE PROCEDURE CREATE_TEST(TBL_NM IN VARCHAR2)
IS
SRC_ID NUMBER(38);
SQL_Q VARCHAR2(250);
DEL_F VARCHAR2(250);
BEGIN
FOR I in (SELECT DEL_IND FROM TBL_NM)
LOOP
SRC_ID := SRC_FILE_ID_SEQ.NEXTVAL;
IF I.DEL_IND = 0
THEN
execute immediate 'INSERT INTO TEST_HIST ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 0 || ' || ' FROM ' || TBL_NM;
ELSIF I.DEL_IND = 1
THEN
execute immediate 'INSERT INTO JESTX_IGNR ' || ' (a,b,c,d,e,DEL_IND,SRC_ID_NO) ' ||
' SELECT a,b,c,d,e, '|| 2 ||' , '|| SRC_ID || ' FROM ' || TBL_NM;
END IF ;
END LOOP;
COMMIT;
END;
I call the procedure using:
EXEC CREATE_TEST('abc');
What you want is a REF CURSOR as you cannot use cursor for loop with dynamic sql.
I dont know the exact datatype for your column DEL_IND. Please declare accordingly.
Here is some more information on Oracle REF CURSORS.
Try below
CREATE OR REPLACE PROCEDURE CREATE_TEST(TBL_NM IN VARCHAR2)
IS
TYPE c1ref is REF CURSOR;
SRC_ID NUMBER(38);
SQL_Q VARCHAR2(250);
DEL_F VARCHAR2(250);
DEL_IND NUMBER(5);
BEGIN
vsql_text := 'select DEL_IND from ' || TBL_NM;
open c1ref for vsql_text;
LOOP
SRC_ID := SRC_FILE_ID_SEQ.NEXTVAL;
fetch c1ref into DEL_IND;
exit when c1ref%NOTFOUND;
IF (DEL_IND = 0)
THEN
execute immediate 'INSERT INTO TEST_HIST ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 0 || ' || FROM ' || TBL_NM;
ELSIF (DEL_IND = 1)
THEN
execute immediate 'INSERT INTO JESTX_IGNR ' || ' (a,b,c,d,e,DEL_IND) ' ||
' SELECT a,b,c,d,e, '|| 2 ||' , '|| SRC_ID || ' FROM ' || TBL_NM;
END IF ;
END LOOP;
CLOSE c1ref;
COMMIT;
END;

Execute Immediate in oracle

I have below query which gives an error as encounter an symbol ( in the line where loop is used. I am trying to develop a function which takes dynamic paramater as table_name,column_name,table_id and used for other tables as well.
FUNCTION get_encryp_pass( table_name IN varchar2,column_name IN varchar2,table_id IN varchar2) RETURN VARCHAR2
IS
BEGIN
EXECUTE IMMEDIATE 'for c1 in (select * from' || table_name ||) loop
EXECUTE IMMEDIATE 'update ' || table_name || ' set ' || column_name = encrypt_val(c1.column_name) || ' where ' || table_id || ' = ' || c1.table_id and column_name is not null;
end loop;
END get_encrypt_pass;
this should work:
CREATE PROCEDURE get_encryp_pass(table_name IN varchar2,
column_name IN varchar2,
table_id IN varchar2) IS
BEGIN
EXECUTE IMMEDIATE 'begin for c1 in (select * from ' || table_name ||
') loop update ' || table_name || ' set ' ||
column_name || ' = encrypt_val(c1.' || column_name ||
') where ' || table_id || ' = c1.'||table_id||' and ' || column_name ||
' is not null; end loop; end;'
;
END;
But why not simply call update FTP_SFTP_SERVER set PASSWORD=encrypt_val(PASSWORD) where PASSWORD is not null ?
keep care of what is a variable and what is a string-literal and must be single-quoted therefore ... and string-variables mus be double-quoted:
EXECUTE IMMEDIATE 'update ' || table_name || ' set ' || column_name || ' = ''' || encrypt_val(c1.column_name) || ''' where ' || table_id || ' = ' || c1.table_id || ' and column_name is not null';
Best practice is to concatenate the statement in a varchar2-variable first and inspect this. If the content of the variable is syntactical correct and executable, the EXECUTE IMMEDIATE should work as well
declare
stmt varchar2(4000);
begin
stmt := 'update ' || table_name || ' set ' || column_name || ' = ''' || encrypt_val(c1.column_name) || ''' where ' || table_id || ' = ' || c1.table_id || ' and column_name is not null';
EXECUTE IMMEDIATE stmt;
end;
I think i have one alternative for your question. MERGE can be used in this case. Please try it i dont have workspaceso dint test it but it should work Let me know if it helps.
FUNCTION get_encryp_pass(
table_name IN VARCHAR2,
column_name IN VARCHAR2,
table_id IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
EXECUTE IMMEDIATE 'MERGE INTO '||table_name||' t1 USING
(
SELECT * FROM '||table_name|| ')t2
ON
(
t1.table_id = t2.table_id
)
WHEN MATCHED THEN
UPDATE SET t1.'||column_name||' = encrypt_val(t2.'||column_name||')'
||' WHERE and t1.'||column_name||' IS NOT NULL';
END;

procedure issue(error in syntax)

I have the procedure block:
begin
for i in (select grantee
,table_name
,privilege
from user_tab_privs_made
where grantee='TEST')
loop
revoke i.privilege on i.table_name from i.grantee;
end loop;
end;
and the error occurs:
You need to issue the revoke as EXECUTE IMMEDIATE, building a dynamic string with the command you want to be executed:
execute immediate 'revoke ' || i.privilege || ' on ' || i.table_name
|| ' from ' || i.grantee;

Resources