How to 'remember' a value to insert into two tables in sqlite? - sql

I have a trigger that I want to insert the same random value into two tables. How do I do this?
CREATE TRIGGER insertTrigger AFTER INSERT ON TableAB
BEGIN
INSERT INTO TableA(id, num) VALUES(RANDOM(), 1);
INSERT INTO TableB(id, num) VALUES(??, 1);
END;
I am not really using Random, but my own custom sqlite function which essentially does the same thing, but I need to remember that value to insert into TableB. How do I do that?

SQLite has no such thing as variables, but you could read the value from the record that you had just inserted into the first table:
CREATE TRIGGER insertTrigger
AFTER INSERT ON TableAB
BEGIN
INSERT INTO TableA(id, num) VALUES(RANDOM(), 1);
INSERT INTO TableB(id, num) SELECT id, 1
FROM TableA
WHERE rowid = last_insert_rowid();
END;

Related

How to use a newly inserted value from another table in PostgreSQL?

Assuming I have two tables final table and table_1, I want to use the the newest values from table_1 and insert them with a trigger in the final_table with every INSERT ON table_1. When I create the triggerfunction inserttrigger() as shown in the example and create the trigger, I get the newest value times the number of rows in table_1. How to write the trigger proper that I get only the single newest record in table1?
Doing:
-- Create tables and inserting example values
CREATE TABLE final_table(id INTEGER, value_fin INTEGER);
CREATE TABLE table_1(id INTEGER, value INTEGER);
INSERT INTO table_1 VALUES(1, 200), (2,203), (3, 209);
-- Create Triggerfunction
CREATE OR REPLACE FUNCTION inserttrigger()
RETURNS TRIGGER AS
$func$
BEGIN
INSERT INTO final_table
SELECT latest.id, latest.value
FROM (SELECT NEW.id, NEW.value FROM table_1) AS latest;
RETURN NEW;
END;
$func$ language plpgsql;
-- Create Trigger
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
FOR EACH ROW EXECUTE PROCEDURE inserttrigger() ;
--Insert example values
INSERT INTO table_1 VALUES(4, 215);
Results in:
SELECT * FROM final_table
id | value_fin
4 215
4 215
4 215
But should look like:
id | value_fin
4 215
While:
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
EXECUTE PROCEDURE inserttrigger() ;
Results in:
ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
I would recommend the VALUES() syntax:
CREATE OR REPLACE FUNCTION inserttrigger()
RETURNS TRIGGER AS
$func$
BEGIN
INSERT INTO final_table VALUES(NEW.id, NEW.value);
RETURN NEW;
END;
$func$ language plpgsql;
CREATE TRIGGER final_table_update BEFORE INSERT ON table_1
FOR EACH ROW EXECUTE PROCEDURE inserttrigger();
Note that you could also get the same behavior with a common-table-expression and the returning syntax, which avoids the need for a trigger:
with t1 as (
insert into table_1(id, value_fin) values(4, 215)
returning id, value_fin
)
insert into final_table(id, value) select id, value_fin from t1

Get table does not exist error, when trying to insert into table from a trigger

I'm attempting to use a trigger to fill values of another table. The trigger watches for insert on table ratings and updates the values of another table, top5restaurants. I haven't figured out how to maintain only the top 5 in top5restaurants, I don't know how to limit a table to a certain number of entries. But right now I can't seem to do anything to top5restaurants from within the trigger.
drop view top_rest;
create view top_rest (rid, rat)
as
(select distinct rid, max(stars)
from rating
group by rid);
drop table top5restaurants;
create table top5restaurants(rid int);
insert into top5restaurants(rid)
select rid from top_rest
where rownum <= 5
order by rat asc;
create or replace trigger top5_trigger
after insert on ratings
for each row
declare top5 top5restaurants%rowtype;
cursor top5_cursor is
select rid from top_rest
where rownum <=5
order by rat;
begin
for record in top5_cursor
loop
fetch top5_cursor into top5;
insert into top5restaurants values(top5);
end loop;
end;
/
--
--
begin
update_reviews('Jade Court','Sarah M.', 4, '08/17/2017');
update_reviews('Shanghai Terrace','Cameron J.', 5, '08/17/2017');
update_reviews('Rangoli','Vivek T.',3,'09/17/2017');
update_reviews('Shanghai Inn','Audrey M.',2,'07/08/2017');
update_reviews('Cumin','Cameron J.', 2, '09/17/2017');
end;
/
select * from top5restaurants;
insert into top5restaurants values(184);
However, the table does exist and I can run queries on it and it returns the data I inserted when I created the table. I can also insert values. Not sure why I get table not found error when using a trigger.
Apart from the difference in table names(answer by Littlefoot) in the trigger and view, You have not used the rowtype collection properly while inserting the data.
you must remove the brackets:
replace
insert into top5restaurants values(top5);
with
insert into top5restaurants values top5;
Cheers!!
You didn't post all tables involved, but - what is obvious, is that view is created as
create view top_rest ... from rating
------
while trigger is created as
after insert on ratings
-------
^
s?
Which one is it? rating or ratings?

SQL - How to create a trigger for two joined tables which is used for inserting

Ok , so I know that inserting information in a view based on two joined tables is impossible.
In order to do so , I need to create a trigger to insert the information in both tables , when an insert is made in that view.
For example :
CREATE VIEW myJoinedView AS
SELECT name,g.value from students
JOIN grades g on g.id=students.id;
The trigger is not working :
CREATE TRIGGER myTrigger
INSTEAD OF INSERT ON myJoinedView
BEGIN
INSERT INTO students
(name,value)
SELECT i.myJoinedView
FROM inserted i
INNER JOIN grades
ON i.id = grades.id
END myTrigger;
Then I'm trying to insert :
INSERT INTO myJoinedView VALUES ('Alex',10);
I don't know if the syntax is correct , I did not find any helpful documentation on this specific type of trigger.
I'm getting this error:
Error(10,46): PLS-00103: Encountered the symbol "end-of-file" when
expecting one of the following: ( begin case declare end exception
exit for goto if loop mod null pragma raise return select update
while with
<< continue close current delete fetch lock
insert open rollback savepoint set sql execute commit forall merge
pipe purge
Any help will be well received.
Thank you!
You need to either perform the inserts separately with separate single table insert or merge statements or by using a multi table insert (insert all) statement. Assuming you have a sequence to generate the id you are joining on for example this code will work in a very rudimentary way, but has some significant issues:
create table students ( id number primary key
, name varchar2(60));
create table grades( id number not null
, value number
, constraint grades_fk1 foreign key (id) references students(id));
create sequence student_id_seq;
create or replace view studentgrades as
select name, value from students s join grades g on s.id = g.id;
create or replace trigger studentgrades_ii_trg
instead of insert on studentgrades
begin
insert all into students(id, name) values (student_id_seq.nextval, name)
into grades(id, value) values (student_id_seq.nextval, value)
select :new.name name, :new.value value from dual;
end;
/
insert into studentgrades values ('Alex',10);
insert into studentgrades values ('Alex',8);
The BIG issue with the above trigger is that every time a grade is inserted for 'Alex' a new student record for 'Alex' is also created instead of reusing the previous student record for 'Alex'. That's probably not the desired behavior. Instead it should probably just insert a new grade record for Alex. One way to acheive this is for the studentgrades view to include the id column from the students table so you can uniquely identify which student to add the grade to, updating the trigger as needed:
create or replace view studentgrades as
select s.id, name, value from students s join grades g on s.id = g.id;
create or replace trigger studentgrades_ii_trg
instead of insert on studentgrades
declare
newid students.id%type;
begin
if :new.id is null then
newid := student_id_seq.nextval;
else
newid := :new.id;
end if;
insert all when :new.id is null
then into students(id, name) values (id, name)
else into grades(id, value) values (id, value)
select newid id, :new.name name, :new.value value from dual;
end;
/
insert into studentgrades values (null, 'Paul',10);
insert into studentgrades values (student_id_seq.currval, 'Paul',8);
However, now what happens if you try this:
insert into studentgrades values (student_id_seq.currval, 'Mary',10);
In this case the name is effectively ignored and Paul gets a new grade so again this isn't quite right. The question is should Paul's name be updated to Mary, or should a new student record for Mary be created, or should an exception be raised?

Automatic sequence in oracle

I am trying to cretae a automatic sequence number genaration using trigger but it is giving me following wrror while inserting the values.
ALTER TABLE sppinv_tblinventory_ex ADD (
CONSTRAINT sppinv_tblinventory_PK PRIMARY KEY (uniqueid));
create sequence row_seq ;
create or replace trigger row_count before insert on sppinv_tblinventory_ex
for each row
begin
select row_seq.nextval into : new.uniqueid from dual;
end;
if I am excuting below then I am able to insert values
insert into sppinv_tblinventory_ex
select row_seq.nextval,
b.member_id,b.src_claim_nbr,b.client_nbr,b.src_platform_cd,
b.suspense_date,b.batch_gen_key,b.bucket_name,b.grouper_rule,
b.event_number,b.case_stat,b.case_stat_dt,b.assigned_to,
b.assigned_on,b.followup_dt,b.release_ind,b.release_dt,
b.viewtype
from sppinv_tblinventory b
When I am inserting the values with out uniqueID I am getting error like below
insert into sppinv_tblinventory_ex
select b.member_id,b.src_claim_nbr,b.client_nbr,b.src_platform_cd,
b.suspense_date,b.batch_gen_key,b.bucket_name,b.grouper_rule,
b.event_number,b.case_stat,b.case_stat_dt,b.assigned_to,
b.assigned_on,b.followup_dt,b.release_ind,b.release_dt,
b.viewtype
from sppinv_tblinventory b
ORA-00947: not enough values
Note : I dont want to disable the trigger
ORA-00947: not enough values - means you have n number of columns in the table but you are only supplying values for (n-m) number of fields.
In your case, if you dont want to insert unique id, then you may have to do
Insert into sppinv_tblinventory_ex (col1, col2, col3.. coln) select (val1, val2, val3 .. valn)
There are so many answers for this on internet...
Try removing the space before new.uniqueid ; and add a IF test like this :
create or replace trigger row_count
before insert on sppinv_tblinventory_ex
for each row
begin
IF :new.uniqueid IS NULL THEN
select row_seq.nextval into :new.uniqueid from dual;
END IF;
end;
Now if you put null in the corresponding value field in your insert, it should work

Creating a trigger with a case statement

I have these two tables:
USERS(username, role_id)
COMMISSION_RATES(username, commission_rate)
users.username is the primary key, commission_rates.username is a foreign key.
I want to write a trigger, after an insert on users, check if role_id = 2, then insert into commission_rates the users.username, and 0 for commission rate.
This is what I have so far, it doesn't work though:
create or replace TRIGGER SETCOMISSIONRATE
AFTER INSERT ON USERS
BEGIN
CASE
WHEN users.role_id = 2 THEN
INSERT INTO COMISSION_RATE
(username,
comission_rate)
VALUES (
:NEW.username,
0)
END;
Any help would be appreciated
It should go like this:
CREATE OR REPLACE TRIGGER SETCOMISSIONRATE
AFTER INSERT ON USERS FOR EACH ROW
WHEN (new.role_id = 2)
BEGIN
INSERT INTO COMISSION_RATE (username, comission_rate)
VALUES (:new.username, 0);
END;
WHEN condition must be in the definition part, not in the body. They can only by used for row trigger.
create or replace
TRIGGER SETCOMISSIONRATE
AFTER INSERT ON USERS
FOR EACH ROW
WHEN (NEW.role_id = 2)
BEGIN
INSERT INTO COMISSION_RATE
(username,
comission_rate)
VALUES (
:NEW.username,
0)
END;