I have to insert almost 40 000 rows to a table and every time I try to execute it in SQL developer, I couldn't find any rows in the table it seems like it didn't executed the begin block at all, because i put a msg to be printed in the output and there is nothing after the execution, I have tried to execute the block with only a few insertion statements and it works,
why SQL developer can't handle a lot of insertion statement in PLSQL block?
bellow is my script:
set serveroutput on
set linesize 200
set timing on
whenever sqlerror exit failure rollback;
whenever oserror exit failure rollback;
ALTER SESSION SET current_schema = carp;
ALTER SESSION SET nls_length_semantics = char;
DECLARE
v_rows_count VARCHAR2(10 CHAR);
PROCEDURE trace (p_message IN VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.put_line (TO_CHAR (SYSDATE, 'YYYYMMDD HH24:MI:SS') || ' - INFO - ' || p_message);
END trace;
BEGIN
dbms_output.ENABLE(1000000);
TRACE ('=========== Exécution du script: START ===========');
Insert into my_table (PK_SEQ,CODE) values (1260389,'00AI');
Insert into my_table (PK_SEQ,CODE) values (1321244,'00AI');
select COUNT(*) into v_rows_count FROM carp.param_site_groupe_site;
dbms_output.put_line('Nombre de lignes insérées: ' || v_rows_count);
TRACE (q'[=========== Exécution du script: FIN ===========]');
COMMIT;
END;
/
exit;
please note that there is more than 40 000 insert statements inside the begin block not two as shown above
I reduce the script size just for readebility porpuse
Related
all I have to DO block which I am planning to run to do vacuum on tables which has dead rows from n to n
however, facing error ERROR: VACUUM cannot be executed from a function or multi-command string
Question how to run it, I have more than 200 Schemas and more than 800 tables I need to vacuum, I can't do it on full DB or one by one that's why I was planning to do it with the cursor.
here is code
DO
$$
--declaretion of varibles
DECLARE d_date timestamp :=NOW(); -- tday date
t_sql text; -- main SQL stetent updae
t_simulation_Before text ; -- hold select for simulation before
t_value TEXT ; -- value used to update
i_min_n_dead_tup integer := 0;
i_max_n_dead_tup integer := 1000 ;
-----------------------EXECUTE FLAG------------------
----- do not set to = Y if not ready to deploy-------
v_exec char(1) :='N';
-----------------------------------------------------
DECLARE cur_upd_text refcursor;
BEGIN
OPEN Cur_upd_text FOR -- cursor. to go over all schemas and create proper dynamic SQl statment
SELECT 'VACUUM FULL ANALYZE '||schemaname ||'.'|| relname , n_dead_tup
FROM pg_stat_user_tables
where n_dead_tup >0 and n_dead_tup< 1000
;
LOOP
FETCH Cur_upd_text INTO t_simulation_Before, t_value ;-- assignin results from select to variables
EXIT WHEN NOT FOUND;
IF v_exec = 'Y' THEN -- executing statments
RAISE NOTICE 'Statment to EXECUTE %, n_dead_tup %',t_simulation_Before, t_value;
EXECUTE t_simulation_Before; -- Execute dynamic SQL
ELSE
RAISE NOTICE 'Statment to EXECUTE %, n_dead_tup %',t_simulation_Before, t_value; -- use this is want to check what variable holds
END IF;
END LOOP;
CLOSE Cur_upd_text; -- close and deallocate cursor
END
$$;```
I am trying to run a pl/sql procedure which I have attatched below, and am getting the following error when running my script
DBMS_OUTPUT.ENABLE;
create or replace procedure grade_point212
is
cursor c1 is
----Cursor declaration--
SELECT student.student_id, student.first_name, student.last_name, course.course_id, course.course_name, class.grade
FROM CLASS
JOIN STUDENT
ON student.student_id = class.student_id
JOIN course
ON course.course_id = class.course_id
order by 1;
----Variable declation--
v_student_id student.student_id%type;
v_first_name student.first_name%type;
v_last_name student.last_name%type;
v_course_id course.course_id%type;
v_course_name course.course_name%type;
v_grade class.grade%type;
--3 additional varriables--
prev_student student.student_id%type;
course_count number(3);
grade_point_total number(3);
----mainline--
begin
open c1;
loop
--Get the first row in the cursor--
fetch c1
into v_student_id,v_first_name ,v_last_name,v_course_id,v_course_name,v_grade;
exit when c1%notfound;
--Set the prev_student to the cursor’s student id--
prev_student:=v_student_id;
--Set the grade_point _total to 0--
grade_point_total:=0;
--Set the course_count to 0--
course_count:=0;
--If the prev_studentis NOT equal to cursor’s student id--
IF prev_student!=v_student_id THEN
--Print out the grade point average which is grade_point_total divided by course_count--
DBMS_OUTPUT.PUT_LINE(grade_point_total/course_count);
--Set prev_student to the cursor’s student id--
prev_student:=v_student_id;
--Set the grade_point_total to 0--
grade_point_total:=0;
--Set the course_count to 0--
course_count:=0;
END IF;
--Add the grade point of the cursor’s grade to grade_point_total--
grade_point_total:=grade_point_total+GradePoint(v_grade);
--Add 1 to the course_count--
course_count:=course_count+1;
--Print out the current row--
DBMS_OUTPUT.PUT_LINE(v_student_id||' '||v_first_name||' '||v_last_name||' '||v_course_id||' '||v_course_name||' '||v_grade);
--Fetch a new row--
fetch c1
into v_student_id,v_first_name ,v_last_name,v_course_id,v_course_name,v_grade;
end loop;
--Close the cursor--
close c1;
--Print out the grade point average which is grade_point_total divided by course_count--
DBMS_OUTPUT.PUT_LINE(grade_point_total/course_count);
end;
set serveroutput on;
begin
grade_point212;
end;
"Error starting at line : 1 in command -
DBMS_OUTPUT.ENABLE
Error report -
Unknown Command
Procedure GRADE_POINT212 compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
65/1 PLS-00103: Encountered the symbol "SET"
Errors: check compiler log
"
The "/" is correct. As a follow up, what tool you are using to send your scripts to the database?
SQL*Plus uses the standalone "/" line as the indicator that the sequence of strings is complete and therefore can be sent to the database for compilation and execution. If you don't provide the "/" you will get errors that on closer read will indicate that some compilation has failed because the sequence you send will actually be composed of multiple SQL, SQL*Plus, and PLSQL blocks.
The execute keyword, BTW, as in:
exec dbms_output.enable;
is SQLPlus syntactic sugar that gets converted by SQLPlus into:
begin dbms_output.enable; end;
Try exec in front of your dbms..
exec dbms_output.enable;
Remove the first line (DBMS_OUTPUT.ENABLE;) entirely. set serveroutput on (before you're about to execute the procedure) will enable it.
Or, encapsulate it into the procedure or the anonymous PL/SQL block itself, e.g.
SQL> begin
2 dbms_output.enable;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL>
You missed the trailing "/" to execute the "CREATE OR REPLACE" statement. The ";" As explained here, the semi-colon ends your pl/sql statement but you need the slash to execute it.
The error "Encountered the symbol "SET" Errors: check compiler log " refers to the "SET" string from the "set serveroutput on" statement.
...
DBMS_OUTPUT.PUT_LINE(grade_point_total/course_count);
end;
/ <<< Add this
set serveroutput on;
begin
grade_point212;
end;
/ <<< Add this
I am trying to update salary of employees using forall. Whenever any error occurs while updating I need to save for which employee id error has occurred.
But it gives following error while compiling
Error(14,24): PLS-00201: identifier 'INDX' must be declared
Below is my code
PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'UPDATE EMPLOYEES SET SALARY=SALARY+10000 WHERE EMP_ID=:1'
USING V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(INDX);
END LOOP;
END;
Use this: The error is that in exception block you are trying to access a loop variable that is being used in begin block.
So your || ' for'||V_EMP_ID(INDX); should be || ' for'||V_EMP_ID(J);
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'UPDATE EMPLOYEES SET SALARY=SALARY+10000 WHERE EMP_ID=:1'
USING V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(J);
END LOOP;
END;
Not sure why you use Execute Immediate when you can easily do as below:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
SET SALARY=SALARY+10000
WHERE EMP_ID= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR J IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
lv_error_string:=lv_error_string
||sqlerrm (-sql%bulk_exceptions(j).error_code)
|| ' for'||V_EMP_ID(J);
END LOOP;
END;
I would suggest to go with a single DML statement. And yes DML error loggins is possible.Hope this helps
--Creating a error log table
BEGIN
DBMS_ERRLOG.create_error_log (dml_table_name => 'EMPLOYEES');
END;
/
--ERR$_EMPLOYEES --> Errro table created
--Insertion with erroreous record
UPDATE EMPLOYEES
SET SALARY = SALARY + 10000
where EMP_ID in (<EMP_ID COLLECTION array
OR simple EMP_IDs>) LOG ERRORS
INTO ERR$_EMPLOYEES ('UPDATE') REJECT LIMIT UNLIMITED;
--Error will be logged into ERR$_EMPLOYEES table
My query,when run takes about 7 seconds to do what is supposed to.But,since its inserting about 30 records,I think it is too slow.Now,either I am running the query that is not written well or it does actually takes this much time. But that would be strange. The underlying database is SQLite and the query looks like this :
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do begin
Close;
SQL.Clear;
UNIQuery1.First;
while Uniquery1.EOF = false do begin
SQL.Text:= 'INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)';
ParamByName('a1').asString := AdvOfficeStatusBar1.Panels[0].Text;
ParamByName('a2').asString := UniTable1.FieldByName('FIELD2').asString;
ParamByName('a3').asString := Uniquery1.FieldByName(',FIELD3').asString;
ParamByName('a4').Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
end;
end;
So can someone tell me if this is OK or am I missing something ?
All fields are text except the 'a4' which is boolean (true/false).
The answer,modified (based on suuggestion from LS_dev):
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)');
SQL.Prepare;
UniTransaction.AddConnection(UniConnection2);
UniTransaction.StartTransaction;
try
UNIQuery1.First;
while Uniquery1.EOF = false do begin
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
Params[1].asString := UniTable1.FieldByName('FIELD2').asString;
Params[2].asString := Uniquery1.FieldByName(',FIELD3').asString;
Params[3].Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
UniTransaction.Commit;
finally
if UNIquery2.Connection.InTransaction then
UNIquery2.Connection.Rollback;
end;
end;
end;
Don't know Delphi, but will suggest some improvements:
You are not using a transaction. You should have something like something like auto-commit disabled and COMMIT command after all insertions;
Your SQL.Text:=... should probably be out of while. If this property set compiles SQL statement, putting it out of while will prevent unnecessary VDBE compilations;
If your intent is copying rows from one table to another (with a static field), you may doing using a single SQL command like INSERT INTO MYTABLE SELECT :a1, FIELD2, FIEDL3, FIELD4 FROM source_table, setting ParamByName('a1').asString := AdvOfficeStatusBar1.Panels[0].Text
This is generic DB usage improvement, hope gives you some direction.
Suggestion using unique SQL:
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do
begin
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) SELECT ?,FIELD2,FIELD3,FIELD4 FROM UNIquery1_source_table');
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
ExecSQL;
end;
end;
Suggestion using improved DB handling:
procedure TForm1.cxButton1Click(Sender: TObject);
begin
with UNIquery2 do
begin
Close;
SQL.Clear;
SQL.Add('INSERT INTO MYTABLE (FIELD1,FIELD2,FIELD3,FIELD4) VALUES (:a1,:a2,:a3,:a4)');
SQL.Prepare;
UniTransaction.AddConnection(UniConnection2);
UniTransaction.StartTransaction;
UNIQuery1.First;
while Uniquery1.EOF = false do
begin
Params[0].asString := AdvOfficeStatusBar1.Panels[0].Text;
Params[1].asString := UniTable1.FieldByName('FIELD2').asString;
Params[2].asString := Uniquery1.FieldByName(',FIELD3').asString;
Params[3].Value := Uniquery1.FieldByName('FIELD4').Value;//boolean field true/false
Uniquery1.Next;
ExecSQL;
end;
UniTransaction.Commit;
end;
end;
If the SQL INSERT itself is slow, I recommend to test its execution speed in an interactive client first. Or write a simple test application which performs one hard-coded INSERT and measures its execution time.
Also you can use the debugger, logging or a profiler to find out the operation in your code which consumes time - it could be the Uniquery1.Next or the ExecSQL for example.
I am having some troubles with this trigger. I created a procedure to check and see if salary is within a certain boundary. If it fails to fall within a certain range, raise the exception. The problem is even though the procedure compiles with no errors, the trigger can not find the procedure.
set serveroutput on;
create or replace procedure check_salary (
tmp_id in varchar2,
tmp_sal in number
)
IS
v_sal number(6,0) := tmp_sal;
v_min number(6,0);
v_max number(6,0);
ex_fail exception;
cursor cur_select is
select min_salary, job_id, max_salary
from jobs where job_id = tmp_id;
BEGIN
for rec_something in cur_select loop
v_min := rec_something.min_salary;
v_max := rec_something.max_salary;
if v_sal >= v_min and v_sal <= v_max then
raise ex_fail;
end if;
end loop;
exception
when ex_fail then
dbms_output.put_line('Invalid salary ' || v_sal || ' must be between ' || v_min || ' and ' || v_max ||'.');
END;
/
show errors;
create or replace trigger check_salary_trg
after insert or update on employees
for each row
declare
begin
IF UPDATING or INSERTING THEN
execute check_salary(:NEW.job_id, :NEW.salary);
end if;
end;
/
show errors;
The Error Message:
PROCEDURE check_salary compiled
No Errors.
TRIGGER check_salary_trg compiled
Warning: execution completed with warning
5/13 PLS-00103: Encountered the symbol "CHECK_SALARY" when expecting one of the following:
:= . ( # % ; immediate
The symbol ":=" was substituted for "CHECK_SALARY" to continue.
Change it to:
create or replace trigger check_salary_trg
after insert or update on employees
for each row
begin
IF UPDATING or INSERTING THEN
check_salary(:NEW.job_id, :NEW.salary);
end if;
end;
/
When you are executing a procedure within a PL/SQL block, you do not use the
EXECUTE syntax
More information about execute you can check the below link
http://docstore.mik.ua/orelly/oracle/prog2/ch23_01.htm
The stack overflow exception is due to the use of dbms_output.put_line inside check_salary procedure.
SQL*Plus command set serveroutput on reserves little size as default, you must specify the buffer size or remove the dbms_output.put_line from check_salary procedure.
In order to increase default buffer size use this:
set serveroutput on size 1000000