Data check during insertion in table - oracle

I want to Check the value of data Before insertion in a table.Like ,if things like " or & come in the data,it should ignore it or insert using some escape sequence .
create table test (checkit varchar2(40));
insert into test values("Here is the & test data");
or
insert into test values("Here is the " test data");
Is there a way to do that in oracle?
thanks
EDIT
I want to know the solution especially for Characters like & , " etc not for normal data as shown in the example.

You can do it using BEFORE trigger.
Here is an example replacing & with & and " with "
SET DEFINE OFF;
drop table test;
create table test (checkit varchar2(60));
CREATE OR REPLACE TRIGGER validateTest
BEFORE DELETE OR INSERT OR UPDATE ON test
FOR EACH ROW
BEGIN
:new.checkit := replace(:new.checkit, '&', '&lte;');
:new.checkit := replace(:new.checkit, '"', '"');
END;
/
insert into test (checkit) values ('Here is the & test "data"');
select * from test;
Output:
drop table test succeeded.
create table succeeded.
TRIGGER validateTest Compiled.
1 rows inserted
CHECKIT
------------------------------------------------------------
Here is the &lte; test "data"
1 rows selected
Obviously replacement strings can be whatever.

Related

How to create a procedure to remove all special characters and duplicate records

I want to create a procedure to remove all special characters from a column of my spesific table and then remove duplicate records.
I tried the following query so far to show the desired logic :
SELECT ft_nm_val,count(*)
FROM ( SELECT REGEXP_REPLACE(ft_nm_val, '[^A-Za-z0-9, ]') AS ft_nm_val
FROM fraud_token_name )
GROUP BY ft_nm_val
HAVING COUNT(*) > 1
Since you want to remove duplicate records and if there are other columns exist in the table, then concept duplicate would change row-wisely. So, I assume you have that table with only one column mentioned. Then you can create such a procedure :
SQL> create or replace procedure make_unique is
begin
--# Leave only alpha-numeric characters through applying [^ ] to [:alnum:] posix
update fraud_token_name
set ft_nm_val = regexp_replace(ft_nm_val,'[^[:alnum:]]');
--# Then delete duplicate records
delete fraud_token_name f1
where rowid <
(
select max(rowid)
from fraud_token_name f2
where f2.ft_nm_val = f1.ft_nm_val
);
commit;
end;
/
SQL> exec make_unique;
Demo

Alter all table columns with out white space in between names

Oracle - Alter all table column names with trim of white space in between names
For suppose column names before alter :
Home number
Mobile number
Local number
After alter column names shall be :
Homenumber
Mobilenumber
Localnumber
I've tried this way: but unable to crack:
UPDATE SA_VW_PHONENUMBER TN SET TN.Column_Name = TRIM (TN.Column_Name);
Fully automatic way
Use this cursor based DDL hacking - statement concat.
BEGIN
FOR alters IN
(
SELECT
'ALTER TABLE "'||table_name||'" RENAME COLUMN "'||column_name||
'" TO "'||replace(cols.column_name,' ','')||'"' sql_stmt
FROM all_tab_cols cols
WHERE REGEXP_LIKE(column_name,'[[:space:]]')
AND owner = user --Add real schema name here
ORDER BY 1
) LOOP
DBMS_OUTPUT.PUT_LINE ( alters.sql_stmt ||';') ;
EXECUTE IMMEDIATE alters.sql_stmt;
END LOOP;
END;
/
If you want to use the safe way
As I know you cannot perform a DDL as a dynamic SQL, so you cannot pass variables to the ALTER TABLE command, but here is what you can do instead of that.
Selecting the occurences:
SELECT table_name,column_name,replace(cols.column_name,' ','') as replace_name
FROM all_tab_cols
WHERE REGEXP_LIKE(column_name,'[[:space:]]');
Use the ALTER TABLE DDL command:
alter table T_TABLE rename column "COLUMN SPACE" TO "COLUMNNOSPACE";
Try the REPLACE function
UPDATE SA_VW_PHONENUMBER TN SET TN.Column_Name = REPLACE(TN.Column_Name,' ','')

How to create TRIGGER with a reference to the triggered table?

Can I create an AFTER TRIGGER on a table and using that table in my SELECT query without getting mutating table error?
Example to a query I want to use.
This query will update number of times a certain status name is showing up in alert life cycle:
CREATE OR REPLACE TRIGGER COUNT_STEP
AFTER INSERT
ON STEPS
FOR EACH ROW
DECLARE
V_COUNT_SETP VARCHAR (10000);
BEGIN
SELECT COUNT (STATUS_NAME)
INTO V_COUNT_SETP
FROM (SELECT A.ALERT_ID, S.STATUS_NAME
FROM ALERTS A, ALERT_STATUSES S, STEPS ST
WHERE :NEW.ALERT_INTERNAL_ID = A.ALERT_INTERNAL_ID
AND ST.ALERT_STATUS_INTERNAL_ID = S.STATUS_INTERNAL_ID
AND S.STATUS_NAME IN ('Auto Escalate'))
GROUP BY ALERT_ID;
UPDATE ALERTS A
SET A.COUNT = V_COUNT_ESC
WHERE A.ALERT_INTERNAL_ID = :NEW.ALERT_INTERNAL_ID;
END;
/
The table I'm inserting a record to is also needed for counting the number of step occurrences since it's stores the alert id and all the steps id it had.
You need to be a bit more clearer in your questions. But, from what i understood, you need to create a trigger on a table, and perform a select for that same table. That gives you a mutanting table error. To bypass that, you need to perform a compound trigger on that table. Something like this:
create or replace trigger emp_ct
for insert on employees compound trigger
v_count number; -- Add variable here
before statement is
begin
-- PERFORM YOUR SELECT AND SEND TO A VARIABLE
end before statement;
after each row is
begin
-- DO WANT YOU WANTED TO DO. USE THE VARIABLE
end after each row;
end;
basically, with a compound trigger, you can capture every trigger event. By doing that, allows to query the table you're capturing.

Generate automatic Id

I am making a web application which uses a database in which I have a field I_ID which i want to automatically increment like I0 then I1 then I2 and so on with each record insertion in the database.
To achieve it I made a trigger for this table.But its not working fine.What can be the reason.Please help
My Trigger T1:
CREATE OR REPLACE TRIGGER "T1"
before
insert on "TBINDIVIDUAL"
for each row
declare
x varchar2(10);
mx varchar2(13);
mx2 varchar2(13);
y number(3);
begin
x:=:new.I_ID;
mx:=substr(x,1,1);
select max(I_ID) into mx2 from tbindividual where I_ID like mx||'%';
y:=to_number(substr(mx2,2));
:new.I_ID:=mx||to_char(y+1);
end t1;
/
EDITED :
As i do by answer
CREATE OR REPLACE TRIGGER "TBINDIVIDUAL_T1"
BEFORE
insert on "TBINDIVIDUAL"
for each row
begin
:new.I_ID = SEQ1.nextval;
end;
/
But it give two errors
Encountered the symbol "=" when expecting one of the following: := . ( # % ; indicator
Encountered the symbol "END"
Please help
So Oracle is not SQL Server...
if you want to get unique ID's, you need to populate them from a sequence.
for creating a sequence use:
create sequence myseq;
and in your code use (depends on the version):
:new.I_ID := myseq.nextval;
or
select myseq.nextval into :new.I_ID from dual;
the problem your code doesn't work is what :new and :old means...
I would recommend you reading about their meaning...
Hope I've been helpful...
Because of the discussion in the comments - here is a full example:
for this table:
CREATE TABLE test (A number);
to add a unique, sequential ID you need to first create a sequence:
CREATE SEQUENCE myseq;
and a trigger:
CREATE OR REPLACE TRIGGER "T1"
before
insert on "test"
for each row
begin
:new.I_ID := myseq.nextval;
end t1;
/
by the way - I would recommend to check before substituting :new.I_ID, if it is null or not, cause sometimes in upgrades people add a unique ID from an external resource.. (such as them getting a unique number from the sequence themselves...)
you can read more about sequences here:
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6015.htm#SQLRF01314
sorry for the way the code is displayed.. need to learn how to write code here...
One more thing - In Oracle - you cannot create such a PL/SQL to increase existing counter without locks.
Concurrent queries might run the first query in the PL/SQL simultaneously, which means multiple sessions will get the same I_ID.
Also notice that in your code you queried the max on varchar, which is not the same as max on number...
Adding concatenated text is unrelated to the unique ID. In your case it will look like:
:new.I_ID = substr(:new.I_ID,1,1)||to_char(myseq.nextval);
assuming x is being inputted with the char you want..

TRIGGER Oracle to prevent updating or inserting

I am having problems with this code below, which is a trigger used in Oracle SQL:
CREATE OR REPLACE TRIGGER TRG_TUTOR_BLOCK
BEFORE INSERT OR UPDATE ON tutors
FOR EACH ROW
DECLARE
BEGIN
IF :new.tutorName = :old.tutorName
THEN
RAISE_APPLICATION_ERROR(-20101, 'A tutor with the same name currently exists.');
ROLLBACK;
END IF;
END;
/
This trigger is used to prevent users from entering the same tutor name at different records.
After I insert two records with the same tutorname, the trigger does not block me from inserting it. Is there anyone can tell me what are the problems with this coding? Here are the sample format and insert values:
INSERT INTO tutors VALUES (tutorID, tutorName tutorPhone, tutorAddress, tutorRoom, loginID);
INSERT INTO tutors VALUES ('13SAS01273', 'Tian Wei Hao', '019-8611123','No91, Jalan Wangsa Mega 2, 53100 KL', 'A302', 'TianWH');
Trigger in Kamil's example will throw ORA-04091, you can see this with your own eyes here. ROLLBACK in a trigger is unnecessary, it runs implicitly when a trigger makes a statement to fail.
You can prohibit any DML on table by altering it with read only clause:
alter table tutors read only;
At last, integrity should be declarated with integrity constraints and not with triggers.
Good luck!
You don't need a trigger for this in Oracle.
You can do it with an "unique index" on the tutorName column (see http://docs.oracle.com/cd/B28359_01/server.111/b28310/indexes003.htm#i1106547).
Note: about your trigger, it fails on checking for another record with the same tutorName because it's not scanning the tutors table for another record with the same tutorName, it's just comparing the tutorName values of the row you are creating (in this case, old.tutorName is just NULL, because the row doesn't exist yet).
Check the case in yours trigger body
IF :new.tutorName = :old.tutorName
It returns true only if 'tutorName' value is the same in new and old record. When you'll trying to updat some value you'll get
IF 'someTutorName' = 'someTutorName'
which will return TRUE.
Inserting row cannot fire this rule because you're trying to compare something like that:
'someTutorName' = NULL
This case always returns FALSE.
Try to use something like that
CREATE OR REPLACE TRIGGER TRG_TUTOR_BLOCK
BEFORE INSERT OR UPDATE ON tutors
FOR EACH ROW
DECLARE
rowsCount INTEGER;
BEGIN
SELECT COUNT(*) FROM tutors WHERE tutorName is :new.tutorName INTO rowsCount;
IF rowsCount > 0
THEN
RAISE_APPLICATION_ERROR(-20101, 'A tutor with the same name currently exists.');
ROLLBACK;
END IF;
END;
/
But the best solution is the one mentioned by friol - use unique index by executing SQL like this
ALTER TABLE tutors
ADD CONSTRAINT UNIQUE_TUTOR_NAME UNIQUE (tutorName);
If you wanna completely ignore recording a row to a table you can follow these steps
rename table to something else and create a view with the same name and create an instead of trigger.
create table usermessages (id number(10) not null)
GO
alter table usermessages rename to xusermessages
GO
create or replace view usermessages as (select * from xusermessages)
GO
create or replace trigger usermessages_instead_of_trg
instead of insert or update on usermessages
for each row
begin
Null ;
end ;
GO
insert into usermessages(123)
Live test available here below
http://sqlfiddle.com/#!4/ad6bc/2

Resources