Oracle SQL combine columns from one table - sql

i am using oracle sql developer and want to build a trigger to insert values into a table column.
My table is:
column1(num) | column2(num) | column3(var)
1 5
6 4
7 3
I want to combine the first two columns, so in the end column3 should look like this:
column3(var)
1_5
6_4
7_3
My Idea was:
create or replace TRIGGER "Database"."TRIGGER"
BEFORE INSERT OR UPDATE ON "Database"."TABLE"
FOR EACH ROW
BEGIN
SELECT column1 || column2
INTO :NEW.column3
FROM TRIGGER;
END;
But column3 is still empty, can anybody tell me what i am doing wrong?
thanks in advance

Rather than using a trigger, you can preferably add a virtual column after dropping the existing one such as
SQL> ALTER TABLE t DROP COLUMN col3;
SQL> ALTER TABLE t
ADD (
col3 AS (col1||'_'||col2)
);
which always will depend on those two columns, and any DML is not allowed, already not needed, it's good for displaying purposes with no interfering human factor.
Demo

BEGIN
:NEW.column3 :=column1 || column2;
END;
Calling a trigger name "Trigger" is a bad idea.

Related

Postgresql function and trigger to copy content from one column to another?

I need to implement a function and a trigger to copy the contents of COLUMN A to COLUMN B( last one completely NULL) both in the same table. This function must be executed by the trigger whenever a new record is entered. I have tried to do the following in the function but it does not seem to work
UPDATE table
SET column1 = column2;
RETURN column1;
On the other hand in the trigger I have:
CREATE TRIGGER name
AFTER UPDATE OR INSERT ON table
FOR EACH ROW EXECUTE PROCEDURE function();
Does anyone see the error?
maybe you need generated column? Documentation
create table test_table (column1 text, column2 text
GENERATED ALWAYS AS (column1) stored);
and results
insert into test_table(column1) values('Megatest'),('Ubertest');
column1 | column2
----------+----------
Megatest | Megatest
Ubertest | Ubertest
update
update test_table set column1='11111111111111' where column1='Megatest';
select * from test_table;
column1 | column2
----------------+----------------
Ubertest | Ubertest
11111111111111 | 11111111111111
You need a before insert trigger for that.
create or replace function the_trigger_f() returns trigger language plpgsql as
$$
begin
new.column_b := new.column_a;
return new;
end;
$$;
CREATE TRIGGER trigger_name
BEFORE INSERT ON the_table
FOR EACH ROW EXECUTE PROCEDURE the_trigger_f();

Dynamically renaming of column names with column values present in some other table in oracle

I am trying to solve a problem where I have 2 tables in Oracle:
Table 1
id name
101 xyz
102 abc
103 def
Table 2
columnname columndesc
id identifier
name customer name
I want to rename the column name of Table1 with the values present in Table2
Expected output is:
identifier customer name
101 xyz
102 abc
103 def
One option you could try is you should use a Cursor to iterate through each row of Table1 and for each of these rows execute the alter table.
Another option is to also use a cursor to iterate through Table rows and instead build one Alter Table statement, which in turn can be run with EXEC
Useful links:
Alter Table
List item
Execute command
For such dynamic renaming you have to use execute immediate to achieve it,
Here is the sample code using a normal for loop,
begin
for i in (select columnname,columndesc from table2) loop
begin
execute immediate 'alter table table1 rename column '||i.columnname ||' to '||i.columndesc;
exception
when others then
dbms_output.put_line('Renaming failed for column '''|| i.columnname ||''' and columndesc '''||i.columndesc||'''');
continue;
end;
end loop;
end;
/
The code is self explanatory, however I have listed some points to be taken care which are instantly coming to mind.
I hope the the table1's columns you are trying to rename are exactly same as value of columnname in table2
During the rename as you see I have put the statements in begin end and using exception we just skip the one which will fail.
Failure reason could be anything such as,
. the column name you are trying to rename doesn't exists
. the column name value from columndesc exceeds 30/128 char (version < oracle 12.2 and version > oracle 12.2 its 128 characters ) which is the limit in oracle for object names
I have hard coded the table table1 as only talble to rename in this example but again you have got idea now where you can even make the table as dynamic also if you want.
At the end bottom line is to use execute immediate for your primary purpose but you also need to consider all the failure cases as the compilation and execution of the actual statements will happen during run time.
EDIT:
Do not use space in columndesc in table2 as customr name rather use - like customer_name which is standard naming for oracle.

Values of the inserted row in a Trigger Oracle

I want a trigger that updates the value of a column, but I just want to update a small set of rows that depends of the values of the inserted row.
My trigger is:
CREATE OR REPLACE TRIGGER example
AFTER INSERT ON table1
FOR EACH ROW
BEGIN
UPDATE table1 t
SET column2 = 3
WHERE t.column1 = :new.column1;
END;
/
But as I using FOR EACH ROW I have a problem when I try it, I get the mutating table runtime error.
Other option is not to set the FOR EACH ROW, but if I do this, I dont know the inserted "column1" for comparing (or I dont know how to known it).
What can I do for UPDATING a set of rows that depends of the last inserted row?
I am using Oracle 9.
You should avoid the DML statements on the same table as defined in a trigger. Use before DML to change values of the current table.
create or replace trigger example
before insert on table1
for each row
begin
:new.column2 := 3;
end;
/
You can modify the same table with pragma autonomous_transaction:
create or replace trigger example
after insert on table1 for each row
declare
procedure setValues(key number) is
pragma autonomous_transaction;
begin
update table1 t
set column2 = 3
where t.column1 = key
;
end setValues;
begin
setValues(:new.column1);
end;
/
But I suggest you follow #GordonLinoff answere to your question - it's a bad idea to modify the same table in the trigger body.
See also here
If you need to update multiple rows in table1 when you are updating one row, then you would seem to have a problem with the data model.
This need suggests that you need a separate table with one row per column1. You can then fetch the value in that table using join. The trigger will then be updating another table, so there will be no mutation problem.
`create table A
(
a INTEGER,
b CHAR(10)
);
create table B
(
b CHAR (10),
d INTEGER
);
create trigger trig1
AFTER INSERT ON A
REFERENCING NEW AS newROW
FOR EACH ROW
when(newROW.a<=10)
BEGIN
INSERT into B values(:newROW.b,:newROW.a);
END trig1;
insert into A values(11,'Gananjay');
insert into A values(5,'Hritik');
select * from A;
select * from B;`

Orace: Default column value based on a filter

Hi a developer asked to add a column on a table which will have a default value of 'N', however if the entry has an id = 3 then the default value of this column should be 'Y', is there anyway I can achieve this in oracle?
I agree with the commenters who have mentioned that this is not a good database design. That said, making compromises with database design is not unusual in real-life situations.
I am not sure that a virtual column is what is wanted. The OP asked for a way to have a default; a virtual column works differently than a default constraint (e.g., with a default constraint we can insert a value other than the default into the column. The best route to take might be to use a trigger to set the "default" value:
CREATE OR REPLACE TRIGGER mytrigger
BEFORE INSERT ON mytable FOR EACH ROW
WHEN (new.mycolumn IS NULL)
BEGIN
SELECT DECODE(id, 3, 'Y', 'N') INTO :new.mycolumn FROM dual;
END;
/
A trigger will also work whether you're using Oracle 10g or 11g (both of which you've tagged).
Hope this helps.
11g approach
From Oracle 11g and up, you could do this in one step using VIRTUAL columns.
Test case
SQL> CREATE TABLE tab_default (
2 ID NUMBER,
3 flag varchar2(1) GENERATED ALWAYS AS (decode(id, 3, 'Y', 'N')) VIRTUAL
4 );
Table created.
SQL>
SQL> INSERT INTO tab_default (ID) VALUES (1);
1 row created.
SQL> INSERT INTO tab_default (ID) VALUES (3);
1 row created.
SQL> INSERT INTO tab_default (ID) VALUES (10);
1 row created.
SQL> SELECT * FROM tab_default;
ID F
---------- -
1 N
3 Y
10 N
SQL>
So, the DECODE function in the VIRTUAL column declaration handles the requirement for you.
10g approach
You could fulfill the requirement using -
DEFAULT value
AFTER INSERT TRIGGER whenever id = 3
Create the table to have DEFAULT value as 'N'. Let the trigger fire only when a new row is inserted with value in id column = 3, such that the trigger updates the value to 'Y'. Else for all other cases the default value would be 'N'.
After adding new column to your table you can insert value in column using below query :
update table_name set column_name = ( case when id = 3 then 'Y' else 'N' end );
At the of inserting new records you may use below approach :
1) Decide column at the time of creating insert query, you can add logic for that when you create query.
2) Create a trigger in database that should update you column value after inserting any new row to table.
This is a very poor database design. It doesn't respect relational database normal form.
I suggest keeping that table as it is and create a new view on the table with an extra column which is calculated using DECODE or CASE WHEN ...
Create a new table with the additional value column:
create table table1 as
select u.*,
case when id=3 then 'Y' ELSE 'N'
END value
from table2 u

What is the syntax to use a Select statement inside a PL/SQL Trigger?

This is what I currently have:
CREATE OR REPLACE TRIGGER MYTRIGGER
AFTER INSERT ON SOMETABLE
FOR EACH ROW
DECLARE
v_emplid varchar2(10);
BEGIN
SELECT
personnum into v_emplid
FROM PERSON
WHERE PERSONID = :new.EMPLOYEEID;
dbms_output.put(v_emplid);
/* INSERT INTO SOMEOTHERTABLE USING v_emplid and some of the other values from the trigger table*/
END MYTRIGGER;
DBA_ERRORS has this error:
PL/SQL: ORA-00923: FROM keyword not found where expected
1) There must be something else to your example because that sure seems to work for me
SQL> create table someTable( employeeid number );
Table created.
SQL> create table person( personid number, personnum varchar2(10) );
Table created.
SQL> ed
Wrote file afiedt.buf
1 CREATE OR REPLACE TRIGGER MYTRIGGER
2 AFTER INSERT ON SOMETABLE
3 FOR EACH ROW
4 DECLARE
5 v_emplid varchar2(10);
6 BEGIN
7 SELECT personnum
8 into v_emplid
9 FROM PERSON
10 WHERE PERSONID = :new.EMPLOYEEID;
11 dbms_output.put(v_emplid);
12 /* INSERT INTO SOMEOTHERTABLE USING v_emplid and some of the other values
from the trigger table*/
13* END MYTRIGGER;
14 /
Trigger created.
SQL> insert into person values( 1, '123' );
1 row created.
SQL> insert into sometable values( 1 );
1 row created.
2) You probably want to declare V_EMPLID as being of type Person.PersonNum%TYPE so that you can be certain that the data type is correct and so that if the data type of the table changes you won't need to change your code.
3) I assume that you know that your trigger cannot query or update the table on which the trigger is defined (so no queries or inserts into someTable).
You are playing with Lava (not just fire) in your trigger. DBMS_OUTPUT in a trigger is really, really bad. You can blow-out on a buffer overflow in your trigger and the whole transaction is shot. Good luck tracking that down. If you must do output-to-console like behavior, invoke an AUTONOMOUS TRANSACTION procedure that writes to a table.
Triggers are pretty evil. I used to like them, but they are too hard to remember about. They affect data often times leading to MUTATING data (scary and not just because Halloween is close).
We use triggers to change the value of columns like .new:LAST_MODIFIED := sysdate and .new:LAST_MODIFIED_BY := user. That's it.
Don't ever allow a TRIGGER to prevent a transaction from completing. Find another option.
I would not use a select statment in a trigger ever. Insert into the table rather than a select into. Once the table already exists select into does not work in most databases.