How do I reset a sequence in Oracle APEX or fill my PK automatically without sequence and trigger, starting from number 1 every time i delete my data? - oracle11g

i have this table
TABLE "KEYWORD_RSLT"
( "ID" NUMBER PRIMARY KEY,
"SESSION_MONTH" VARCHAR2(40) NOT NULL ENABLE,
"PATIENT_NAME" VARCHAR2(50)
and i have this procedure that imports data to my table KEYWORD_RSLT.
create or replace PROCEDURE "PR_KEYWORD_SEARCH" (v_patient_id NUMBER, v_keyWord varchar2)
IS
BEGIN
delete from KEYWORD_RSLT;
insert into KEYWORD_RSLT (SESSION_MONTH, PATIENT_NAME)
select distinct
to_char(s.SESSION_DATE, 'MM-YYYY') as SESSION_MONTH,
p.FIRST_NAME ||' '||p.LAST_NAME as PATIENT_NAME
from SESSIONS s,
CLIENTS p
where s.CLIENTS_ID = p.ID
and (s.CRITICAL_POINT like LOWER ('%'||v_keyWord||'%') and s.CLIENTS_ID = v_patient_id
or s.ACTIONS like LOWER ('%'||v_keyWord||'%') and s.CLIENTS_ID = v_patient_id);
END PR_KEYWORD_SEARCH;
I want my primary key "ID" to take automatically the next available number starting from 1, but when my procedure deletes all data from this table, i want to start again from 1.
I tried with sequence ("SQ_KEYWORD_RSLT_INCREAMENT") and trigger but i can not reset this sequence from a new procedure using this code:
alter sequence SQ_KEYWORD_RSLT_INCREAMENT restart start with 1;
How can i fill my ID automatically from the beginning every time i delete all the data?

You say i can not reset this sequence but you don't say why so I'm assuming that you got an error. It is not possible to execute ddl statements in pl/sql directly, but it can be done using EXECUTE IMMEDIATE.
CREATE SEQUENCE koen_s START WITH 1;
Sequence KOEN_S created.
SELECT koen_s.NEXTVAL FROM DUAL;
NEXTVAL
----------
1
BEGIN
EXECUTE IMMEDIATE 'ALTER SEQUENCE koen_s RESTART START WITH 1';
END;
/
PL/SQL procedure successfully completed.
SELECT koen_s.NEXTVAL FROM DUAL;
NEXTVAL
----------
1

Related

skip deleting records when a child record is found

i have a pl/sql procedure to modify/delete records based on a checkbox selection in my Apex application:
delete from s_objectif_operation where id_operation=:p124_id_operation;
for a in (select distinct id from s_objectif
where id in (
SELECT trim(regexp_substr(:P124_S_OBJECTIF, '[^:]+', 1, LEVEL)) str
FROM dual
CONNECT BY instr(:P124_S_OBJECTIF, ':', 1, LEVEL - 1) > 0
))
loop
insert into s_objectif_operation
(id_s_objectif, id_operation)
values
(a.id, :p124_id_operation);
end loop;
for every modification, this procedure deletes all the records and insert the correct ones back so i had to remove the "cascade on delete" option the foreign key constraint to suspend any child record removal but now the procedure is not working.
maybe "raise an exception" can work?
There is no need to delete all the records and re-inserting only the checked ones. That is a brute force approach and it works but it does not capture the real user action.
As an alternative you can just delete/insert the changes. To do that, create an additional page item P124_S_OBJECTIF_OLD and set it to the value P124_S_OBJECTIF with a computation after header (or any pre-rendering processing point after P124_S_OBJECTIF has been initialized). In your pl/sql code use APEX_STRING.SPLIT to process the checkbox values and the MULTISET operator to decide which values have been touched.
Then your pl/sql process code could look like this.
DECLARE
l_objectif_old apex_t_varchar2;
l_objectif_new apex_t_varchar2;
l_objectifs_added apex_t_varchar2;
l_objectifs_removed apex_t_varchar2;
BEGIN
l_objectif_old := apex_string.split(:P124_S_OBJECTIF_OLD,':');
l_objectif_new := apex_string.split(:P124_S_OBJECTIF,':');
l_objectifs_added := l_objectif_new MULTISET EXCEPT l_objectif_old;
l_objectifs_removed := l_objectif_old MULTISET EXCEPT l_objectif_new;
-- add new
FOR i IN 1 .. l_objectifs_added.COUNT LOOP
INSERT INTO s_objectif_operation (id_s_objectif, id_operation)
VALUES (l_objectifs_added(i), :P124_ID_OPERATION);
END LOOP;
-- delete old
FOR i IN 1 .. l_objectifs_removed.COUNT LOOP
BEGIN
DELETE FROM s_objectif_operation
WHERE id = l_objectifs_removed(i);
EXCEPTION WHEN OTHERS THEN
-- this will fire if there are child records. Add your own code.
NULL;
END;
END LOOP;
END;
Note that you might have to tweak the insert and delete statement to match your data structure.

PL/SQL not functioning

Im currently trying to implement a row trigger that fires when the new Employee number inserted into the table is not continuous.
"Continuous" in a relationship to the Employee number means the first record inserted will have the Employee number 1, the second record will have the employee number 2, and each next position must have a number greater by one that a number of the previous position.
I have successfully created the trigger, however when I inserted a new record that have an Employee number that is not continuous, my trigger is not fired.
Im unsure where I went wrong and hope I can get some explanation and corrections on my code.
CREATE OR REPLACE TRIGGER CONTENUM
AFTER INSERT ON TRKEMPLOYEE
FOR EACH ROW
DECLARE
continuous_value EXCEPTION;
PRAGMA exception_init(continuous_value, -20111);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF (:NEW.E# > :OLD.E# + 1) THEN
RAISE_APPLICATION_ERROR (-20111,'The value of Employee number must be continuous');
END IF;
END CONTENUM;
/
Here is the format of my sample TRKEMPLOYEE table
CREATE TABLE TRKEMPLOYEE(
E# NUMBER(12) NOT NULL,
NAME VARCHAR(50) NOT NULL,
DOB DATE ,
ADDRESS VARCHAR(300) NOT NULL,
HIREDATE DATE NOT NULL,
CONSTRAINT TRKEMPLOYEE_PKEY PRIMARY KEY(E#) );
Here is my insert statement.
Currently in my table TRKEMPLOYEE there is only 15 rows thus with my insert statement, the trigger should fire but it is not happening.
INSERT INTO TRKEMPLOYEE VALUES( 17, 'David', NULL, 'GB',sysdate );
Thank you.
First of all you are checking AFTER INSERT ON TRKEMPLOYEE which will be executed after the row is inserted.
Secondly, you cannot check :OLD.E# since you are not updating and you are not using a old value.
Also you should drop the trigger at all and use SEQUENCES and let Oracle take care of the auto-increment values every time you add a new employee.
If you want to continue with your current logic, fixes that can be applied:
Change AFTER INSERT ON TRKEMPLOYEE to BEFORE INSERT ON TRKEMPLOYEE
Logic should be changed as below:
CREATE OR REPLACE TRIGGER contenum BEFORE
INSERT ON trkemployee
FOR EACH ROW
DECLARE
continuous_value EXCEPTION;
PRAGMA exception_init ( continuous_value, -20111 );
PRAGMA autonomous_transaction;
max_e# INTEGER;
BEGIN
SELECT
nvl(MAX(e#), 0)
INTO max_e#
FROM
trkemployee;
IF ( :new.e# > max_e# + 1 ) THEN
raise_application_error(-20111, 'The value of Employee number must be continuous');
END IF;
END contenum;
/
I do not recommend this solution because it will start to become slower as your table starts to grow.

Sequential Insertion of data using multiple procedure being called in sequence

I have a requirement where in I need to insert one row for customer and next for address and than all his account in a particular table.
For this I have written 3 procedure 1 calling 2 other in FOR LOOP.
While I am running it is running in sequence but when I check the data inserted. some of the rows of calling procedure are inserted before the called procedure are oveR. How to resolve the same?
CREATE OR REPLACE PROCEDURE XYG(REP_DATE IN custom.C_CIBILRPT_TBL.RPT_DATE%type)
AS
V_AS_COU NUMBER DEFAULT 1;
V_BS_COU NUMBER DEFAULT 1;
V_CS_TOT NUMBER DEFAULT 1;
V_BOD_DATE DATE;
V_LINE_DATA VARCHAR(300);
BEGIN
<<Getting Date into V_BOD_DATE using into statemet>>
--#### Truncating Temp Table
execute immediate 'Truncate table CUSTOM.C_CIBILRPT_TMP';
--#### Borrower Segment Generation Starts --####
FOR custid IN
( Fetching customer id
LOOP
<<Getting the data in V_LINE_DATA>>
INSERT
INTO C_CIBILRPT_TMP VALUES
(
REP_DATE,
V_BOD_DATE,
'XXX',
'BS',
V_BS_COU,
V_LINE_DATA,
custid.cifid
);
COMMIT;
V_BS_COU := V_BS_COU+1;
DBMS_OUTPUT.put_line (custid.cifid);
ADDRESS_SEG_BG (custid.cifid,v_as_cou,rep_date);
V_AS_COU := V_AS_COU+1;
CREDIT_SEG_BG(custid.cifid,rep_date);
END LOOP;
END XYG;

How to use a bind variable in trigger body?

I'm new to PL/SQL. I'm using oracle 11g XE along with sql developer. I'm trying to create to create an after insert trigger as follows
create or replace trigger tr1
after
insert ON
employee
for each row
begin
print :new.emp_id;
end;
The employee table is as follows
create table employee
( emp_id varchar2(5) primary key,
emp_name varchar2(10),
salary number,
company varchar2(10) foreign key references companies(comp_name)
);
When I run the statement I got a 'enter binds' window for the bind variable :new. But I was confused that why do I need to enter the value for :new since it is pseudorecord. Then I entered 'employee' as the values for :new. Now I'm getting the following error.
Error(2,8): PLS-00103: Encountered the symbol "" when expecting one of the following: := . ( # % ; The symbol ":=" was substituted for "" to continue.
Your problem is not in the :new pseudorecord. The error is coming from the usage of print, which is used to print the bind variable used in successful PL/SQL block or used in an EXECUTE command. For example, you can use it this way:
VARIABLE n NUMBER
BEGIN
:n := 1;
END;
/
Then
PRINT n;
But if you want to test the value being inserted, you can use DBMS_OUTPUT.PUT_LINE like this:
create or replace trigger tr1
after
insert ON
employee
for each row
BEGIN
dbms_output.put_line(:new.emp_id);
END;
/
Enable DBMS_OUTPUT window in your SQL Developer, then run
insert into employee values(1, 'empName', 1000, 'ABC');
You'll see 1 printed out.
However, you can always test the value from the table. Because the value should be already inserted into table. You can just query.

PL/SQL Execute immediate create table and insert data into it

Let's have a look on my source code:
CREATE OR REPLACE PROCEDURE MAKE_COPY_OF_CLASSROOMS AUTHID CURRENT_USER AS
TYPE classrooms_table_type IS TABLE OF classrooms%ROWTYPE INDEX BY PLS_INTEGER;
classrooms_backup classrooms_table_type;
CURSOR classrooms_cursor IS
SELECT *
FROM classrooms
WHERE year = 1
ORDER BY name;
v_rowcnt PLS_INTEGER := 0;
BEGIN
OPEN classrooms_cursor;
FETCH classrooms_cursor
BULK COLLECT INTO classrooms_backup;
CLOSE classrooms_cursor;
EXECUTE IMMEDIATE 'CREATE TABLE classrooms_copy AS (SELECT * FROM classrooms WHERE 1 = 2)';
--COPY ALL STORED DATA FROM classrooms_backup TO classrooms_copy
END MAKE_COPY_OF_classrooms;
I'm stucked for hours on trying to insert data from "classrooms_backup" into the table "classrooms_copy", which is created by EXECUTE IMMEDIATE command. It's necessary to create table "classrooms_copy" via EXECUTE IMMEDIATE command. I tried to create another EXECUTE command with for loop in it:
EXECUTE IMMEDIATE 'FOR i IN classrooms_backup.FIRST..classrooms_backup.LAST LOOP
INSERT INTO classrooms_copy(id,room_id,year,name)
VALUES(classrooms_backup(i).id,classrooms_backup(i).room_id,classrooms_backup(i).year,classrooms_backup(i).name);
END LOOP;';
But it's road to the hell. I'm retrieving an invalid SQL statement error.
Thanks for your help!
There's no need for much PL/SQL here. Also, try to avoid the keyword CURSOR - there's almost always a better way to do it.
create or replace procedure make_copy_of_classrooms authid current_user as
begin
execute immediate '
create table classrooms_copy as
select *
from classrooms
where year = 1
order by name
';
end make_copy_of_classrooms;
/

Resources