i'm facing a problem with a primary key in PostgreSQL, my plan was to make an addition of two values and set this to one primary key, how could this be realized (first try below):
/* Tabelle fuer die Test*/
create table Test(
var_a integer,
var_b integer,
var_key integer,
var_key = var_a + var_b,
primarykey(var_key),
);
if i call this with a foreign key then it should be one value:
foreign key (var_key_f) references Test(var_key),
EDIT: I know th option of two multiple primary keys entries but i want to have only one primary key, so that i not have to reference over two vars again. I need to have both variables generated to one primary key.
It appears this can be accomplished without triggers: (pg-9.3):
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE test
( var_key INTEGER NOT NULL PRIMARY KEY
, var_a INTEGER NOT NULL
, var_b INTEGER NOT NULL
, var_key_f INTEGER REFERENCES test(var_key)
, CONSTRAINT the_sum CHECK (var_a+var_b = var_key)
);
INSERT INTO test(var_key, var_a, var_b) VALUES(42, 21, 21); -- Ok
INSERT INTO test(var_key, var_a, var_b) VALUES(666, 660, 6); -- Ok
INSERT INTO test(var_key, var_a, var_b) VALUES(34, 21, 11); -- bad sum
INSERT INTO test(var_key, var_a, var_b) VALUES(666, 600, 66); -- duplicate sum
INSERT INTO test(var_key, var_a, var_b, var_key_f) VALUES(14, 6, 8, 42); -- Ok
INSERT INTO test(var_key, var_a, var_b, var_key_f) VALUES(13, 5, 8, 43); -- Bad FK
Result:
NOTICE: drop cascades to table tmp.test
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 1
INSERT 0 1
ERROR: new row for relation "test" violates check constraint "the_sum"
DETAIL: Failing row contains (34, 21, 11, null).
ERROR: duplicate key value violates unique constraint "test_pkey"
DETAIL: Key (var_key)=(666) already exists.
INSERT 0 1
ERROR: insert or update on table "test" violates foreign key constraint "test_var_key_f_fkey"
DETAIL: Key (var_key_f)=(43) is not present in table "test".
Related
So I have a table trans which has two columns tx_type and ref_nbr
and I want to create a trigger such that the trigger ensures the following condition
in the trans table.
The following two conditions should be ensured:
if tx_type = D or W then ref_nbr should match the branch_nbr in branch table
if tx_type= B , P or R then ref_nbr should match mer_nbr in mer table
Triggers are not intended for keeping consistency in database relations. Use foreign keys for that. So make a table trans not with one column ref_nbr but use 2 columns - one for each relation (foreign key). Additionaly you can create check constraint for making sure that correct column is filled for given tx_type.
If you try to use triggers, you will have problems with concurrent transactions changing related tables like deleting your ref_nbr.
Example definitions for mer, branch and trans tables with some sample inserts:
create table branch(
branch_nbr number generated by default on null as identity start with 3 primary key,
branch_name varchar2(100) not null
);
create table mer (
mer_nbr number generated by default on null as identity start with 2 primary key,
mer_name varchar2(100) not null
);
create table trans (
id number generated by default on null as identity primary key,
tx_type varchar2(1) not null,
ref_branch_nbr number,
ref_mer_nbr number,
constraint ck_tx_type check (tx_type in ('D', 'W', 'B', 'P', 'R')),
constraint ck_correct_ref_for_tx_type
check (
(tx_type in ('D', 'W') and ref_branch_nbr is not NULL and ref_mer_nbr is NULL)
or (tx_type in ('B', 'P', 'R') and ref_branch_nbr is NULL and ref_mer_nbr is not NULL)
),
constraint fk_trans_ref_branch_nbr
foreign key (ref_branch_nbr)
references branch(branch_nbr),
constraint fk_trans_ref_mer_nbr
foreign key (ref_mer_nbr)
references mer(mer_nbr)
);
insert into branch(branch_nbr, branch_name) values(1, 'Master');
insert into branch(branch_nbr, branch_name) values(2, 'Test');
insert into mer(mer_nbr, mer_name) values(1, 'Test to Master');
commit;
-- working:
insert into trans(tx_type, ref_mer_nbr) values('P', 1);
insert into trans(tx_type, ref_branch_nbr) values('D', 1);
-- not working - non existing parent:
insert into trans(tx_type, ref_mer_nbr) values('P', 999);
insert into trans(tx_type, ref_branch_nbr) values('D', 999);
-- not working - wrong tx_type or wrong ref column:
insert into trans(tx_type, ref_mer_nbr) values('D', 1);
insert into trans(tx_type, ref_branch_nbr) values('P', 1);
insert into trans(tx_type, ref_branch_nbr, ref_mer_nbr ) values('P', 1, 1);
-- not working - cant insert without tx_type
insert into trans(ref_mer_nbr, ref_branch_nbr) values(1, 1);
These are the tables I already have:
CREATE TABLE Gyartok
(
GyID INT IDENTITY(2, 3),
Nev VARCHAR(20),
CONSTRAINT PK_Gyartok PRIMARY KEY (GyID)
)
CREATE TABLE Focicsuka
(
CsID INT IDENTITY(2, 2),
Meret INT,
CONSTRAINT PK_Focicsuka PRIMARY KEY (CsID)
)
CREATE TABLE FcsGyartjaGya
(
GyID INT IDENTITY(3, 2),
CsID INT,
Ar INT,
CONSTRAINT FK_FcsGyartjaGya1
FOREIGN KEY (GyID) REFERENCES Gyartok(GyID),
CONSTRAINT FK_FcsGyartjaGya2
FOREIGN KEY (CsID) REFERENCES Focicsuka(CsID),
CONSTRAINT PK_FcsGyartjaGya
PRIMARY KEY (GyID, CsID)
)
The problem is that every time I try to add new values to the table (like such)
INSERT INTO FcsGyartjaGya (Ar) VALUES (300);
I get an error saying I didn't initialize the CsID INT column:
Cannot insert the value NULL into column 'CsID', table 'Lab3.dbo.FcsGyartjaGya'; column does not allow nulls. INSERT fails.
I know I must initialize it with something, but I have no idea what do to it with, because IDENTITY(x, y) doesn't work (it's occupied by another column already) and adding another parameter to the code (like such)
INSERT INTO FcsGyartjaGya (Ar, CsID) VALUES (300, 7);
creates another error which says
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_FcsGyartjaGya1". The conflict occurred in database "Lab3a", table "dbo.Gyartok", column 'GyID'.
It is important to note that I already filled every column with data, so that couldn't be the problem.
As I mention in the comments, your INSERT will work fine, provided the stars align correctly. For your table Gyartok you have GyID as your PRIMARY KEY, which is defined as a IDENTITY(2,3); so the first value generated is 2 and then each row attempted to be INSERTed will increment by 3.
So, if we run the following, we get the IDs 2, 5, 7 and 17. (11 and 14 are skipped as the INSERT failed).
CREATE TABLE Gyartok (
GyID INT IDENTITY(2, 3),
Nev VARCHAR(20),
CONSTRAINT PK_Gyartok PRIMARY KEY (GyID)
);
GO
INSERT INTO dbo.Gyartok (Nev)
VALUES ('asdfjahsbvd'),
('ashjkgdfakd'),
('kldfbhjo');
GO
INSERT INTO dbo.Gyartok (Nev)
VALUES (REPLICATE('A',25)), --Force a truncation error
('ashjkgdfakd');
GO
INSERT INTO dbo.Gyartok (Nev)
VALUES (REPLICATE('A',15));
Let's now add some data for your other table:
CREATE TABLE Focicsuka (
CsID INT IDENTITY(2, 2),
Meret INT,
CONSTRAINT PK_Focicsuka PRIMARY KEY (CsID)
)
INSERT INTO dbo.Focicsuka (Meret)
VALUES(12),
(25);
Now we want to INSERT into the table FcsGyartjaGya, defined as the following:
CREATE TABLE FcsGyartjaGya (
GyID INT IDENTITY(3, 2),
CsID INT,
Ar INT,
CONSTRAINT FK_FcsGyartjaGya1 FOREIGN KEY (GyID) REFERENCES Gyartok(GyID),
CONSTRAINT FK_FcsGyartjaGya2 FOREIGN KEY (CsID) REFERENCES Focicsuka(CsID),
CONSTRAINT PK_FcsGyartjaGya PRIMARY KEY (GyID, CsID)
)
This has a IDENTITY on GyID, but defined as an IDENTITY(3,2), so the first value is 3 and then incremented by 2.
As this has 2 foreign keys, on GyID and CsID when we INSERT the row the values must appear in the respective tables. As GyID is defined as anIDENTITY(3,2) however, this is where we need to rely on the Stars luck for the INSERT to work. Why? Well 2 + (3*n) and 3+(2*n) can give very different numbers. The first are as you saw at the start of this answer. For the latter, we have numbers like 3, 5, 7, 9, 11. As you can see, only 1 in 3 of these numbers match a number in our original sequence, so luck is what we are going to be relying on.
Let's, therefore, try a single INSERT.
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(2,1);
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_FcsGyartjaGya1". The conflict occurred in database "Sandbox", table "dbo.Gyartok", column 'GyID'.
Well, that didn't work, but it was expected. 3 isn't a value in the table Gyartok. Let's try again!
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(2,2);
It worked! The stars Luck was our side, and the IDENTITY value was a value in the table Gyartok. Let's try a couple of rows this time!
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(4,3),
(4,4);
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_FcsGyartjaGya1". The conflict occurred in database "Sandbox", table "dbo.Gyartok", column 'GyID'.
No!! Not again. :( That's because the stars didn't align; 7 and 9 aren't in the other table. But wait, 11 was in the sequence, so let's try that:
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(4,5);
Error, again?! No, it cannot be!!! :( Oh wait, I forgot, the stars were against us before, because that INSERT failed against Gyartok for the value of 11. I need to wait for 17!
--13 fails
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(4,6);
GO
--15 fails
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(4,6);
GO
--17 works!
INSERT INTO dbo.FcsGyartjaGya (CsID,Ar)
VALUES(4,6);
And now we have another row in our table.
So what is the problem? Your design. GyID is defined as an IDENTITY and a FOREIGN KEY; meaning you are at the "whims" of SQL Server generating a value valid. This is not what you want. Just don't define the column as an IDENTITY and then INSERT the data with all 3 of your columns defined:
CREATE TABLE FcsGyartjaGya (
GyID int,-- IDENTITY(3, 2),
CsID INT,
Ar INT,
CONSTRAINT FK_FcsGyartjaGya1 FOREIGN KEY (GyID) REFERENCES Gyartok(GyID),
CONSTRAINT FK_FcsGyartjaGya2 FOREIGN KEY (CsID) REFERENCES Focicsuka(CsID),
CONSTRAINT PK_FcsGyartjaGya PRIMARY KEY (GyID, CsID)
)
GO
INSERT INTO dbo.FcsGyartjaGya (GyID, CsID, Ar)
VALUES(2,2,1),
(2,4,2),
(5,4,3),
(8,2,4),
(8,4,5);
And all these rows insert fine.
I think there is a bit confusion, if I understand correctly what You're trying to do, then you have two tables each with their own id, which is based on an identity column, so you get new values in those for free.
Then you are trying to make a relation table with extra data.
Issue 1: You cannot have FcsGyartjaGya.GyID be identity if it refers to Gyartok.GyID because you will want to insert into it and not rely on an auto increment. If it doesn't refer to the same it should have another name or my head will possibly explode :))
Issue 2: When populating a relation table you need to insert it with what pairs you want, there is no way SQL server can know how it should match these identity pairs in the relation table
I think this is what people are aiming at in the comments, for example
to insert a relationship between row with Focicsuka.CsID = 1 to Gyartok.GyID 7 and adding Ar = 300 have to look like
INSERT INTO FCSGYARTJAGYA(GYID, CSID, AR)
VALUES(7, 1, 300)
Unless You've forgotten to mention that you want to put some value for each of some value or based on something which can be scripted, in other words unless You have logics to define the pairs and their values, relationship tables cannot have defaults on their foreign key fields.
I have a xml script I'm reading from to populate my database with data. One of the nodes in the xml file don't have a idDirector field (the nodes are movies) and so the xml reads a -1 as idDirector and then my stored procedure tries to insert -1 into the fk field and this makes my database returna constraint error : director -1 doesn't exist in Director table. How can I make it so it inserts null instead and make my fk field nullable?
CREATE TABLE Film (
PRIMARY KEY (idFilm),
FOREIGN KEY (idDirector) REFERENCES Director
);
Thank you
Looks like CASE to me, e.g.
insert into film (id_film, id_director)
select id_film,
case when id_director = -1 then null
else id_director
end
from ...
Will it work? Yes:
SQL> create table director (id number primary key);
Table created.
SQL> create table film (id number primary key, id_director number references director);
Table created.
SQL> insert into director values (100);
1 row created.
Inserting -1 fails:
SQL> insert into film (id, id_director) values (1, -1);
insert into film (id, id_director) values (1, -1)
*
ERROR at line 1:
ORA-02291: integrity constraint (SCOTT.SYS_C0065885) violated - parent key not
found
Inserting NULL works:
SQL> insert into film (id, id_director) values (1, null);
1 row created.
SQL>
New to sql here and cant find the answer to this problem...
create table Stranka (
id_stranka integer not null,
ime varchar(50) not null,
telst integer not null,
tk_id_naslov integer
);
alter table Stranka
add (constraint pk_Stranka primary key (id_stranka));
create table Avto (
id_avto integer not null,
regst varchar(50) not null,
stmotorja integer not null,
stpopravila integer not null,
tk_id_stranka integer
);
alter table Avto
add (constraint pk_Avto primary key (id_avto));
alter table Avto
add(constraint tk_avto_id_stranka foreign key (tk_id_stranka) references
Avto(id_avto));
here are the inserts
insert into Avto values (1, 'LJ-123-12', 1123, 4, 1);
insert into Avto values (2, 'LJ-A21-BP', 3039, 1, 2);
insert into Avto values (3, 'MB-H62-06', 1562, 2, 5);
insert into Avto values (4, 'LJ-AT2-19', 2021, 2, 4);
insert into Avto values (5, 'LJ-12S-23', 1784, 4, 6);
the question i have is why do i get the above listed error for inserts number 3 and 5 but not for number 1, 2 and 4? What am i missing? The inserts are basically the same. Any additional info i need to add let me know. Thanks
PS: the other TK(table Stranka) works fine and in table stranka we have 10 ids.
Look at your foreign key constraint:
alter table Avto
add(constraint tk_avto_id_stranka foreign key (tk_id_stranka) references
Avto(id_avto));
You're putting a foreign key on table Avto to another column in table Avto.
Happens that the 2 columns involved in the foreign key are the first and last columns in your inserts. In inserts 1, 2, and 4, the id_avto and tk_id_stranka are the same.
insert into Avto values (1, 'LJ-123-12', 1123, 4, 1);
insert into Avto values (2, 'LJ-A21-BP', 3039, 1, 2);
insert into Avto values (4, 'LJ-AT2-19', 2021, 2, 4);
Oracle is smart enough to see that these do not violate the constraint, since the row being inserted itself satisfies the constraint. Whereas on inserts 3 and 5, there is no row in the table that satisfies the foreign key constraint - no row in the table with id_avto 5 or 6.
insert into Avto values (3, 'MB-H62-06', 1562, 2, 5);
insert into Avto values (5, 'LJ-12S-23', 1784, 4, 6);
What you probably need to do is change your foreign key to point at the other table - given how you've named everything that seems like what you intended:
alter table Avto
add(constraint tk_avto_id_stranka foreign key (tk_id_stranka) references
Stranka (id_stranka));
Learner here in Oracle 11g. I'm having an issue with INSERTing some rows into two tables that are linked by a primary/foreign key relationship.
Basically I create a sequence to start with 1000 and increment by 1.
Then create a 'STORE' table with a ST_ID column
The ST_ID column is linked to the SEQUENCE with a TRIGGER.
Then I have an 'EMPLOYEE' table that has a EST_ID field that is a foreign key to the ST_ID column in the STORE table.
However, when I tried to insert rows I initially got a error saying EST_ID could not be null. So I created a sequence and trigger for EST_ID and now I'm getting an error saying the foreign key constraint is being violated.
I think that was maybe the wrong thing to do. Do I really want E_ID and EST_ID to be identical and how would I get that to happen? With some kind of trigger?
The actual code:
CREATE SEQUENCE "STORSEQ" MINVALUE 1000 MAXVALUE 9999 INCREMENT BY 1 START WITH 1000 NOCACHE NOORDER
NOCYCLE ;
CREATE TABLE "STORE"
( "ST_ID" CHAR(4) NOT NULL ENABLE,
"STADDR_ID" CHAR(4) NOT NULL ENABLE,
CONSTRAINT "STORE_PK" PRIMARY KEY ("ST_ID") ENABLE
) ;
CREATE TABLE "EMPLOYEE"
( "E_ID" CHAR(8) NOT NULL ENABLE,
"EF_NAME" VARCHAR2(20) NOT NULL ENABLE,
"EL_NAME" VARCHAR2(20) NOT NULL ENABLE,
"EST_ID" CHAR(4) NOT NULL ENABLE,
CONSTRAINT "EMPLOYEE_PK" PRIMARY KEY ("E_ID") ENABLE
) ;
alter table "EMPLOYEE" add CONSTRAINT "EMPLOYEE_CON" foreign key ("EST_ID") references
"STORE" ("ST_ID")
/
CREATE OR REPLACE TRIGGER "BI_STORE"
before insert on "STORE"
for each row
begin
if :NEW."ST_ID" is null then
select "STORSEQ".nextval into :NEW."ST_ID" from dual;
end if;
end;
/
At the moment my INSERT code looks like this:
INSERT INTO STORE
(ST_ID, STADDR_ID)
VALUES
(DEFAULT, DEFAULT);
INSERT INTO EMPLOYEE
(EF_NAME, EL_NAME)
VALUES
('James', 'Smith');
When you try to insert data into table that has foreign key reference, it will not get value for id automatically, you need to pass that value.
You can do this:
declare
v_store_id integer;
begin
INSERT INTO STORE (ST_ID, STADDR_ID) VALUES (DEFAULT, DEFAULT)
RETURNING ST_ID INTO v_Store_id;
INSERT INTO EMPLOYEE (EF_NAME, EL_NAME, EST_ID)
VALUES ('James', 'Smith', v_store_id);
end;
You can also insert id in store id table without trigger using this
declare
v_store_id integer;
begin
INSERT INTO STORE (ST_ID, STADDR_ID) VALUES ("STORSEQ".nextval, DEFAULT)
RETURNING ST_ID INTO v_Store_id;
INSERT INTO EMPLOYEE (EF_NAME, EL_NAME, EST_ID)
VALUES ('James', 'Smith', v_store_id);
end