How to solve this issue in pl/sql - plsql

How to create a trigger which interdicts insertion of symbols and space in a certain column and after insertion just to have only the upper letters
for example:
insert into tale xxx values '"&$))(/-$:&##¥*|^]asjdj';
and the result should be the following:
ASJDJ
thank you
a lot of functions procedures trigger and nothing was right

Add a new column to the table and update that column extracting only the letters from the column with special characters.
Using your eg.
Add new column value in tale table. Right after inserting the xxx column do the updates like:
update tale set value = upper(regexp_substr(xxx,'[[:alpha:]]+'));

That would be a row-level trigger which fires both before insert or update on table so that value is modified in any case. There are various options which let you remove everything but letters; regular expression is simple enough.
Sample table:
SQL> create table test (col varchar2(40));
Table created.
Trigger:
SQL> create or replace trigger trg_biu_test
2 before insert or update on test
3 for each row
4 begin
5 :new.col := upper(regexp_replace(:new.col, '[^[:alpha:]]'));
6 end;
7 /
Trigger created.
Testing:
SQL> insert into test (col) values ('"&$))(/-$:&##¥*|^]asjdj');
1 row created.
SQL> select * from test;
COL
----------------------------------------
YASJDJ
SQL> update test set col = '25xyz';
1 row updated.
SQL> select * from test;
COL
----------------------------------------
XYZ
SQL>

Related

How to write trigger on the source table

I have a table data_package_code with schema as follows:
Name Null? Type
----------------- ----- ------------
mult qty VARCHAR2(2)
CHARGE NUMBER(19,4)
Credit Charge NUMBER(19,4)
Stop Date VARCHAR2(7)
Table_id NUMBER
SYS_CREATION_DATE DATE
I want to implement a trigger which will run an insert statement on the same table to add sysdate in sys_creation_date column.
It is done to store the date on which a new entry is inserted in the table.
My implementation is as follows:
create or replace trigger package_insert_date
before insert on data_package_code for each row
begin
insert into data_package_code(sys_creation_date)
values(sysdate);
end;
But it is giving me an error on line 2.
I am using oracle sql developer for this project.
It is just
create or replace trigger package_insert_date
before insert on data_package_code
for each row
begin
:new.sys_creation_date := sysdate;
end;
Although, you could have created table that way:
create table ...
(...
sys_creation_date date default sysdate --> this
);

Deleting a record in parent table and updating "DELETED" column in child table

I have a parent table(profiles) in which profile_id is the primary key and is a foreign key to 3 different child tables. (s_profile, p_profile, c_profile)
Now, i want to delete a record from the table profile and want to update a "DELETED" column in the child tables with sysdate.
However my script doesn't allow it saying "Foreign key violated- Child record found".
Is there a solution to it?
What is the purpose of that foreign key constraint, if you want to allow deleting master while details exist?
Anyway, here's an example which shows what you might do; is it the right way, I can't tell (I suspect not - once again, it is cancels the purpose of the referential constraint).
Create two tables - master and its detail:
SQL> create table profiles
2 (id_profile number primary key);
Table created.
SQL> create table s_profile
2 (id number primary key,
3 id_profile number constraint fk_s_pro references profiles (id_profile),
4 deleted date);
Table created.
SQL>
Sample data and attempt to delete a master while detail exists:
SQL> insert into profiles values (1);
1 row created.
SQL> insert into s_profile (id, id_profile) values (100, 1);
1 row created.
SQL> delete from profiles where id_profile = 1;
delete from profiles where id_profile = 1
*
ERROR at line 1:
ORA-02292: integrity constraint (SCOTT.FK_S_PRO) violated - child record found
SQL>
Create a trigger on the master table which removes foreign key value and sets the date:
SQL> create or replace trigger trg_bd_prof
2 before delete on profiles
3 for each row
4 begin
5 update s_profile s set
6 s.id_profile = null,
7 s.deleted = sysdate
8 where s.id_profile = :old.id_profile;
9 end;
10 /
Trigger created.
Let's try to delete master again:
SQL> delete from profiles where id_profile = 1;
1 row deleted.
SQL> select * From s_profile;
ID ID_PROFILE DELETED
---------- ---------- ----------
100 2018-10-03
SQL>
If you want to save foreign key value, you could alter detail table and add another column, say deleted_id_profile and populate it with the same trigger. Though, what would you do with it, if parent doesn't exist any more and you can't find any info about it?

Creating table with limited number of rows

I would like to create table that have limited numbers of rows.
For example if we try insert data into that table where rownumber is bigger than 2.000, that return some error or something.
How to manage this?
An approach could be by creating a trigger to check the number of inserted rows; for example, say you have this table
create table notManyRows(n number)
and you want to limit the number of rows to 3, you can add a trigger like:
create or replace trigger notManyRowsTrg
after insert on notManyRows
declare
vCheck number;
begin
select count(*)
into vCheck
from notManyRows;
--
if vCheck > 3 then
raise_application_error(-20001, 'Too many rows in the table');
end if;
end;
How it works:
SQL> insert into notManyRows values (1);
1 row created.
SQL> insert into notManyRows values (1);
1 row created.
SQL> insert into notManyRows values (1);
1 row created.
SQL> insert into notManyRows values (1);
insert into notManyRows values (1)
*
ERROR at line 1:
ORA-20001: Too many rows in the table
ORA-06512: at "ALEK.NOTMANYROWSTRG", line 9
ORA-04088: error during execution of trigger 'ALEK.NOTMANYROWSTRG'
SQL>

update of multiple columns

I flipped through the official doc. and the existing threads but couldn't figure out when would the following trigger execute :
CREATE OR REPLACE TRIGGER TRIG_TS_TRANSPORT_AFTER
AFTER INSERT OR
UPDATE OF iud, addressid, idd, rld, pickupaddressid, vessel
ON chassitransports
REFERENCING NEW AS new OLD AS old
FOR EACH ROW
.
.
.
Any one of the columns is updated
ALL the columns are updated
Since the updates occur from an external db, I cannot test the above scenarios :|
It should fire after INSERT of rows or after UPDATE of any of the mentioned column. See below example :
---- Create sample Tables
CREATE TABLE temptable1 (regNo VARCHAR2(20), timec TIMESTAMP(6));
create table TEMPTABLE2
(
idx NUMBER,
regno VARCHAR2(20),
eventb VARCHAR2(20),
timec DATE,
rfid NUMBER
);
----- Trigger definition
CREATE OR REPLACE TRIGGER after_update_tr
AFTER UPDATE OF timec, regNo ON temptable2
FOR EACH ROW
BEGIN
INSERT INTO temptable1
VALUES(:NEW.regNo,
:NEW.timec);
EXCEPTION WHEN OTHERS THEN
dbms_output.put_line(sqlerrm);
END;
------ Fire update statement ----
UPDATE temptable2
SET regNo = 'VISIT0000011'
WHERE timec IS NULL;
and it executed successfully.

SQLite update trigger changes all rows in the table

Problem: a simplest possible update trigger writes a new value to all table rows instead of just the row being updated. Here is the table:
[names]
id INTEGER PRIMARY KEY
name TEXT
len INTEGER
Now I want to create triggers to update 'len' with the length of 'name'. This INSERT trigger seems to be doing the job corectly:
CREATE TRIGGER 'namelen' AFTER INSERT ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (id=NEW.id);
END;
Problems begin when I add a similar UPDATE trigger:
CREATE TRIGGER 'namelenupd' AFTER UPDATE ON 'names'
BEGIN
UPDATE 'names' SET len = length(NEW.name) WHERE (OLD.id=NEW.id);
END;
The update trigger writes the new length to all rows of the table, despite the WHERE clause. For example, if I say
UPDATE 'names' SET name='foo' where id=1;
then the value of 'len' becomes 3 for all rows of the table. I've looked at sqlite trigger examples and I can't see my error. What else must I do to make sure the trigger updates the 'len' column only in the row(s) that are actually updated?
Both OLD.xxx and NEW.xxx refer to the table row that caused the trigger to run.
The UPDATE statement inside the trigger runs independently; if you want to restrict it to one table row, you have to explicitly do this in its WHERE clause by filtering on that statement's table values, i.e., names.id or just id.
When the original UPDATE statement does not change the id column, the old and new id values are the same, and the expression OLD.id=NEW.id is true for all records in the table, as seen by the inner UPDATE statement.
The correct trigger looks like this:
CREATE TRIGGER "namelenupd"
AFTER UPDATE OF name ON "names"
BEGIN
UPDATE "names" SET len = length(NEW.name) WHERE id = NEW.id;
END;
Had the same issue, here's the syntax from my trigger
You would change "ALTER" to "CREATE" depending on what you already have (or not)
You have "id" as your primary key
Your dbo is "names"
Obviously, this will set the name value to "foo" (not really what you wanted). The key seems to be the last line, where you set inner join inserted on names.Id = inserted.Id.
USE [yourDBname]
ALTER TRIGGER [dbo].[yourTrigger]
ON [dbo].[names]
After INSERT, UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Select id from inserted
begin
update [dbo].names
set [dbo].names.name = 'foo'
from dbo.names
inner join inserted
on names.id = inserted.id
END

Resources