I can't understand why this sequence is incremented by 2.
Is there any error in sequence to increment by 1? I need this to insert primary key value in table 'food'.
CREATE SEQUENCE food_id_ai START WITH 1 INCREMENT BY 1 CACHE 100;
create table food(
food_id integer,
f_name varchar(30) not null,
category varchar(30) not null,
price number(4),
amount number(4)
);
alter table food add constraint fpk primary key(food_id);
CREATE OR REPLACE TRIGGER insert_into_food
BEFORE INSERT ON food
FOR EACH ROW
BEGIN
:new.food_id:= food_id_ai.nextval;
END;
/
insert into food values(food_id_ai.nextval,'ruchi', 'chanachur' , 8, 50);
insert into food values(food_id_ai.nextval,'chips', 'chips' , 8, 50);
insert into food values(food_id_ai.nextval,'aeromatic', 'soap' , 8, 50);
insert into food values(food_id_ai.nextval,'handwash', 'toyletries', 8, 50);
insert into food values(food_id_ai.nextval,'tissue', 'toyletries' , 8, 50);
Because you're accessing the sequence both in your INSERT statement and in the trigger that is launched for each row, of course it's incremented by two.
Choose one.
I'd go for the trigger-based one, since you won't have to remember to specify the sequence in each insert statement you may execute.
In that case, you'll have to explicitly list the columns you are going to insert VALUES to:
INSERT INTO food (f_name, category, price, amount)
VALUES ('ruchi', 'chanachur' , 8, 50);
you have two options to correct this.
modify insert statement to be like this:
insert into food (f_name, category,price , amount)
values ('ruchi', 'chanachur' , 8, 50);
or modify you triggers as follow:
CREATE OR REPLACE TRIGGER insert_into_food
BEFORE INSERT ON food
FOR EACH ROW
BEGIN
if :new.food_id is null then
:new.food_id:= food_id_ai.nextval;
end if;
END;
/
Related
I want to add a BIT column to a table. I have provided the statement to do so, but an error declares the BIT in my statement as a invalid datatype. What would be the correct way to add a bit column?
ALTER TABLE Persons
ADD is_person BIT NULL
[You should specify database you use; this is Oracle example, see if it helps].
There's no such a datatype in Oracle, so you'd use NUMBER and constrain it:
SQL> create table persons
2 (id number,
3 bit number(1,0) check (bit in (0, 1)) --> this
4 );
Table created.
A few examples:
SQL> insert into persons (id, bit) values (1, 2);
insert into persons (id, bit) values (1, 2)
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.SYS_C008434) violated
SQL> insert into persons (id, bit) values (1, 1);
1 row created.
SQL> insert into persons (id, bit) values (1, 0);
1 row created.
SQL> insert into persons (id, bit) values (1, 10);
insert into persons (id, bit) values (1, 10)
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL>
Or, if you'd want to add it (as table already exists), then
alter table persons add bit number(1, 0) check (bit in (0, 1));
I want to insert data using procedure. At first I wanna insert match, but id for football match is generated automatically using trigger. Secondly I want use this id for other table - stats_footballmatch_club. It is possible?
INSERT INTO FootballMatch(FootballMatch_Date, Stadium_Id, Tournament_Id) VALUES(TO_DATE('02-04-22','DD-MM-YY'), 1, 1);
INSERT INTO STATS_FOOTBALLMATCH_CLUB(FootballMatch_Id, Club_Id , Goals, Shots, BallControl, Pass) VALUES (1, 1, 0, 0, 0, 0);
INSERT INTO STATS_FOOTBALLMATCH_CLUB(FootballMatch_Id, Club_Id , Goals, Shots, BallControl, Pass) VALUES (1, 2, 0, 0, 0, 0);
If for example, my trigger name is FOOTBALLMATCHTRIGGER, can I do something like that?
INSERT INTO STATS_FOOTBALLMATCH_CLUB(FootballMatch_Id, Club_Id , Goals, Shots, BallControl, Pass) VALUES (FOOTBALLMATCHTRIGGER:new, 2, 0, 0, 0, 0);
This is the footballmatchtrigger:
CREATE OR REPLACE TRIGGER FootballMatchTrigger
BEFORE INSERT
ON FootballMatch
FOR EACH ROW
BEGIN
if :NEW.FootballMatch_Id is null then
SELECT FootballMatchIdSequence.NEXTVAL
INTO :new.FootballMatch_Id
FROM dual;
end if;
END;
And there is footballmatch table:
CREATE TABLE FootballMatch(
FootballMatch_Id NUMBER(4) PRIMARY KEY,
FootballMatch_Date DATE,
Stadium_Id NUMBER(4) REFERENCES Stadium(Stadium_Id) on delete cascade,
Tournament_Id NUMBER(4) REFERENCES Tournament(Tournament_Id) on delete cascade
);
It also refers to other tables like stadium, and tournament.
Short answer: no you cannot use a trigger for that. A trigger cannot be referenced in code.
Solution: Use the RETURNING INTO clause.
Simplified example:
DROP TABLE stats_footballmatch_club;
DROP TABLE footballmatch;
DROP SEQUENCE footballmatch_s;
CREATE TABLE footballmatch(
footballmatch_id NUMBER(4) PRIMARY KEY,
footballmatch_date DATE
);
CREATE SEQUENCE footballmatch_s;
CREATE OR REPLACE TRIGGER footballmatch_bi BEFORE
INSERT ON footballmatch
FOR EACH ROW
BEGIN
:new.footballmatch_id := footballmatch_s.nextval;
END footballmatch_bi;
/
CREATE TABLE stats_footballmatch_club(
stats_id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
goals NUMBER,
club VARCHAR2(100),
footballmatch_id NUMBER(4) REFERENCES footballmatch(footballmatch_id) on delete cascade
);
DECLARE
l_footballmatch_id footballmatch.footballmatch_id%TYPE;
BEGIN
INSERT INTO footballmatch(footballmatch_date) VALUES(TO_DATE('02-04-22','DD-MM-YY'))
RETURNING footballmatch_id INTO l_footballmatch_id;
INSERT INTO stats_footballmatch_club (footballmatch_id, goals, club) VALUES (l_footballmatch_id,3, 'Real Madrid');
INSERT INTO stats_footballmatch_club (footballmatch_id, goals, club) VALUES (l_footballmatch_id,2, 'PSG');
END;
/
Notes:
No need for SELECT INTO to assign sequence.NEXTVAL. Just assign using := sequence.NEXTVAL
Don't even need the trigger for primary key - identity columns are a lot handier ( see table stats_footballmatch_club primary key)
I have two tables:
CREATE TABLE project.teacher
(
PROFESSOR_Codigo SMALLINT IDENTITY( 100, 1),
birth DATE NOT NULL,
phone VARCHAR(15)
);
CREATE TABLE project.student
(
STUDENT_Codigo IDENTITY( 1, 1),
birth DATE NOT NULL,
phone VARCHAR(15)
);
When I add a student to the student table it will increment 1 from the number 1, and stay (1, 2, 3, 4, 5, 6, ...)
In the teacher table I already have data entered, and start with a value of 100 in the identity column, but when I add 1, it gets identity 1, not 101
I've tried everything, scope_identity(), ##identity, but I couldn't! Does anyone have any ideas?
What I do to insert a row into the teacher table:
INSERT INTO project.student
VALUES ('1998-05-08', '963597461');
INSERT INTO project.teacher
VALUES ('1994-05-09', '968413692');
try
dbcc checkident(teacher, noreseed)
this will return the current identity value of the ident column. your create statement is fine so maybe something went wrong on the on create?
I have created the following tables:
CREATE TABLE IF NOT EXISTS public.teams (
id SERIAL PRIMARY KEY,
name VARCHAR(64) NOT NULL UNIQUE
) WITH (OIDS = FALSE);
CREATE TABLE IF NOT EXISTS public.submissions (
id SERIAL PRIMARY KEY,
team_id INTEGER REFERENCES public.teams NOT NULL,
records_num INTEGER NOT NULL,
timestamp TIMESTAMP NOT NULL
) WITH (OIDS = FALSE);
CREATE TABLE IF NOT EXISTS public.predictions (
id SERIAL PRIMARY KEY,
submission_id INTEGER REFERENCES public.submissions NOT NULL,
customer INTEGER REFERENCES public.real NOT NULL,
date DATE NOT NULL,
billing NUMERIC(20, 2) NOT NULL
) WITH (OIDS = FALSE);
CREATE TABLE IF NOT EXISTS public.real (
customer INTEGER PRIMARY KEY,
date DATE NOT NULL,
billing NUMERIC(20, 2) NOT NULL
) WITH (OIDS = FALSE);
The relation for submissions-predictions is one-to-many; users will submit predictions in packets of 1000 rows that should get the same submission id.
I am trying to create a trigger that runs BEFORE INSERT ON predictions that creates a submissions row. This is what I have so far:
CREATE OR REPLACE FUNCTION insert_submission() RETURNS TRIGGER AS
$$
BEGIN
INSERT INTO submissions(team_id, records_num, timestamp)
VALUES (1, 1, '2018-04-21 00:00:00'); /*example values, need to fill with dynamically assigned ones, specially for records_num and team_id*/
RETURN NULL;
END
$$ LANGUAGE plpgsql;
DROP TRIGGER trigger_submission ON public.predictions;
CREATE TRIGGER trigger_submission BEFORE INSERT ON predictions
EXECUTE PROCEDURE insert_submission();
So, my questions are:
How do I go about retrieving the newly created submissions.id for the row inserted by the trigger, in order to add it to all the rows inserted in predictions by the user? Do I have to run another trigger AFTER INSERT for this?
EDIT: to clarify following #bignose answer, the sequence of events would go like this:
User inserts 1000 rows into public.predictions:
INSERT INTO predictions(customer, date, billing)
VALUES
(1, '2018-01-05', 543.42),
(4, '2018-04-02', 553.21),
...
(423, '2019-11-18', 38.87) /* 1000th row */
He does not know which submission_id to insert in those rows and indeed, the submissions row for this packet of predictions doesn't exist yet so a trigger runs before to create a row in submissions that would execute something like this:
INSERT INTO public.submisssions(team_id, records_num, timestamp)
VALUES (
4, /* I will need something to retrieve team_id here */
1000, /* I will need something to count the rows of the insert that triggered this */
NOW() /* convert to timestamp */
)
This last query should return the public.submission.id value that it has just created to the insert the user requested so that it ends up being something like this:
INSERT INTO predictions(customer, date, billing)
VALUES
(#submission_id, 1, '2018-01-05', 543.42),
(#submission_id, 4, '2018-04-02', 553.21),
...
(#submission_id, 423, '2019-11-18', 38.87) /* 1000th row */
Where #submission_id should be the value retrieved from the trigger (and the some for all the 1000 rows)
How could I count the rows inserted by the user to use them as value for submissions.records_num?
How could I retrieve team.id to insert during the trigger execution, assuming I know team.name beforehand?
Thank you!
Kind regards
A trigger function, when used for a row-level trigger, has access to the old and new state of the table.
CREATE OR REPLACE FUNCTION insert_submission() RETURNS TRIGGER AS
$$
BEGIN
INSERT INTO submissions(team_id, records_num, timestamp)
VALUES (NEW.foo, NEW.bar, '2018-04-21 00:00:00');
RETURN NULL;
END
$$ LANGUAGE plpgsql;
It's not clear from the description, which fields you expect to retrieve from the row that triggers this function. So you'll need to substitute NEW.foo and NEW.bar with field references in the NEW row state.
I have 2 tables, which were created by executing the following (keep in mind that every query is executed through on node.js, i.e., connection.execute('select....') ):
create table User(userid int not null, name varchar(50) not null, primary key(userid));
create table Random(userid int not null, random int, primary key (userid), foreign key (userid) references User(userid) );
I also added a sequence to auto increment the userid:
create sequence userid_seq;
create or replace trigger userid_bir
before insert on User
for each row
begin
select userid_seq.nextval
into :new.userid
from dual;
end;
/
Now, I have a process whereby after I insert a new user, that user's id is inserted immediately into Random. I browsed through Stackoverflow and came up with:
insert into User(name) values('John');
SET #last_id = LAST_INSERT_ID();
insert into Random(userid, random) values( last_id, 2);
However, I got the following error:
SP2-0735: unknown SET option beginning "#last_id"
Any ideas?
My other concern is that if there are 2 computers trying to insert 2 users (in total) at the same time, the last_id value (or MAX userid value) might mess up. That is, the server might be executing:
insert into User(name) values('John'); ## from Person A
insert into User(name) values('Brian'); ## from Person B
SET #last_id = LAST_INSERT_ID(); ## from Person A, say it's set to 1
SET #last_id = LAST_INSERT_ID(); ## from Person B, say it's set to 2
insert into Random(userid, random) values( last_id, 2); ## from Person A
insert into Random(userid, random) values( last_id, 2); ## from Person B, error: duplicate values?
That's probably MySQL syntax. In Oracle you can use RETURNING INTO clause.
declare
last_id number;
begin
insert into user(name) values('Abcd')
returning userid into last_id;
insert into Random(userid, random) values( last_id, 2);
commit;
end;
/
userid_seq.currval will return the most recent value returned for the sequence in the current session. So you can
INSERT INTO random( userid, random )
VALUES( user_id_seq.currval, 2 );
If you want to have the value in a local variable
DECLARE
l_userid user.user_id%type;
BEGIN
INSERT INTO user(name)
VALUES( 'John' )
RETURNING userid
INTO l_userid;
INSERT INTO random( userid, random )
VALUES( l_userid, 2 );
END;