SQL not allowing to add data into foreign keys [duplicate] - encoding

This question already has answers here:
ERROR 1452: Cannot add or update a child row: a foreign key constraint fails
(27 answers)
Closed 1 year ago.
I have ran into an error in MySQL where it will not allow me to enter data for foreign keys. This is my data:
create table Location(
LocationID char(4) primary key,
LocationName char(20),
LocationState char(3),
LocationPostCode char(4),
StartLoc char(3),
EndLoc char(3)
);
drop table Location;
insert into Location values ('L10','Norwood','TAS','7250','L31','L30');
insert into Location values ('L11','Cressy','TAS','7586','L33','L32');
insert into Location values ('L12','Launceston','TAS','7907','L35','L34');
insert into Location values ('L13','Epping Forest','TAS','7354','L37','L36');
insert into Location values ('L14','Avoca','TAS','7812','L39','L38');
insert into Location values ('L15','Royal George','TAS','7009','L41','L40');
insert into Location values ('L16','Westbury','TAS','7893','L43','L42');
create table TripSchedule(
ScheduleID char(3),
foreign key(StartLoc) references Location(StartLoc),
foreign key(EndLoc) references Location(EndLoc),
foreign key(RequestID) references BookingReq(RequestID),
foreign key(TruckVINNum) references Allocation(TruckVINNum),
foreign key(TransportID) references Allocation(TransportID),
foreign key(StaffID) references Staff(StaffID),
TripStart char(40),
TripEnd char(40)
);
drop table TripSchedule;
insert into TripSchedule values('S23',L11','L10', 'R101', 'VO20','T1','S1''6th of December 2020-1:30pm','7th of December 2021-1:30 pm');
insert into TripSchedule values('S24', 'L13','L12', 'R102', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
insert into TripSchedule values('S25', 'L15','L14', 'R103', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
insert into TripSchedule values('S26', 'L17','L16', 'R104', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
insert into TripSchedule values('S27', 'L19','L18', 'R105', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
insert into TripSchedule values('S28', 'L21','L20', 'R101', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
insert into TripSchedule values('S29', 'L23','L22', 'R106', 'VO20','T1','S1','6th of December 2020-1:30pm','7th of December, 2021-1:30 pm');
The issue I'm having is a bit of a weird one, it lies with the relationship between the Location and TripSchedule table. SQL will allow the first three rows of the insert values for the TripSchedule table to be entered, however the rest of the insert values give error: "Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (assessment.tripschedule, CONSTRAINT tripschedule_ibfk_1 FOREIGN KEY (StartLoc) REFERENCES location (LocationID))".
I have tried referencing the StartLoc and EndLoc as primary keys in the Location table and have also tried completely deleting the StartLoc and EndLoc from the Location table but still get the same problem. Is there any solution to this?

Your foreign key constraint is requiring that locations exist in order to specify them as StartLoc. Your fourth through seventh inserts specify StartLoc as L17, L19, L21, and L23, none of which are LocationIDs that exist.
Either create the Location records before inserting the TripSchedule records that refer to them, or remove your foreign key constraint:
alter table TripSchedule drop constraint tripschedule_ibfk_1;

Related

How can I update TABLE1 rows when I change some TABLE2 rows in POSTGRESQL?

I am building a soccer management tool where the league's admin can update the score of every match in the MATCHES TABLE. At the same time I want to update the TEAMS TABLE columns.
For instance if the match is DALLAS vs PHOENIX, and the score was DALLAS 2 - PHOENIX 3, I want to update that match in the MATCH TABLE (I know how to tho this) but at the same time I want to update the points of those two teams based on the result we just updated.
Is there a way to do that in POSTGRESQL?
Thanks for your help.
You can do this for triggers. What is a Database trigger? A database trigger is a special stored procedure that is run when specific actions occur within a database. Most triggers are defined to run when changes are made to a table’s data. Triggers can be defined to run after (or before) INSERT, UPDATE, and DELETE table records. Triggers use two special database objects, INSERTED and DELETED, to access rows affected by the database actions.
When table record is inserted – Use the INSERTED table to determine which rows were added to the table.
When table record is deleted – Use the DELETED table to see which rows were removed from the table.
When table record is updated – Use the INSERTED table to inspect the new or updated values and the DELETED table to see the values prior to update.
In PostgreSQL INSERTED trigger object is called NEW and DELETED object is called OLD
For example:
We have two tables, user_group and user_detail. I would like to insert 12 records into table user_detail when inserting data to table user_group
CREATE TABLE examples.user_group (
id serial4 NOT NULL,
group_name varchar(200) NOT NULL,
user_id int4 NOT NULL
);
CREATE TABLE examples.user_detail (
id serial4 NOT NULL,
user_id int4 NOT NULL,
"month" int2 NOT NULL
);
-- create trigger function for inserting 12 records into user_detail table
CREATE OR REPLACE FUNCTION examples.f_user_group_after_insert()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
p_user_id integer;
begin
p_user_id := new.user_id; -- new is a system table (trigger objects), which return inserted new records for user_group tables
insert into examples.user_detail (user_id, month) values (p_user_id, 1);
insert into examples.user_detail (user_id, month) values (p_user_id, 2);
insert into examples.user_detail (user_id, month) values (p_user_id, 3);
insert into examples.user_detail (user_id, month) values (p_user_id, 4);
insert into examples.user_detail (user_id, month) values (p_user_id, 5);
insert into examples.user_detail (user_id, month) values (p_user_id, 6);
insert into examples.user_detail (user_id, month) values (p_user_id, 7);
insert into examples.user_detail (user_id, month) values (p_user_id, 8);
insert into examples.user_detail (user_id, month) values (p_user_id, 9);
insert into examples.user_detail (user_id, month) values (p_user_id, 10);
insert into examples.user_detail (user_id, month) values (p_user_id, 11);
insert into examples.user_detail (user_id, month) values (p_user_id, 12);
return new;
end;
$function$
;
-- join trigger function to user_group table, when will be run after insert
create trigger user_group_after_insert
after insert
on
examples.user_group for each row execute function examples.f_user_group_after_insert();

Firebird update or insert primary key violation

I try to update or insert into a Firebird database table.
But after a new entry, the next time I try to update I get a PK violation.
Both times I use:
UPDATE OR INSERT INTO NAMES ( ID, NAME , SURENAME ) VALUES ( 123, 'Peter', 'Miller' ) matching (Name)
But each time with different surnames.
The ID is a PK in the table. And I generate the ID at the first time.

Insert data into strongly normalized DB and maintain the integrity (Postgres)

I'm trying to develop a simple database for the phonebook. This is what I wrote:
CREATE TABLE phone
(
phone_id SERIAL PRIMARY KEY,
phone CHAR(15),
sub_id INT, -- subscriber id --
cat_id INT -- category id --
);
CREATE TABLE category
(
cat_id SERIAL PRIMARY KEY, -- category id --
cat_name CHAR(15) -- category name --
);
CREATE TABLE subscriber
(
sub_id SERIAL PRIMARY KEY,
name CHAR(20),
fname CHAR(20), -- first name --
lname CHAR(20), -- last name --
);
CREATE TABLE address
(
addr_id SERIAL PRIMARY KEY,
country CHAR(20),
city CHAR(20),
street CHAR(20),
house_num INT,
apartment_num INT
);
-- many-to-many relation --
CREATE TABLE sub_link
(
sub_id INT REFERENCES subscriber(sub_id),
addr_id INT
);
I created a link table for many-to-many relation because few people can live at the same address and one person can live in different locations at different times.
But I cannot figure out how to add data in strongly normalized DB like this and maintain the integrity of the data.
The first improvement was that I added inique key on address table bacause this table should not contain duplicated data:
CREATE TABLE address
(
addr_id SERIAL PRIMARY KEY,
country CHAR(20),
city CHAR(20),
street CHAR(20),
house_num INT,
apartment_num INT,
UNIQUE (country, city, street, house_num, apartment_num)
);
Now the problem is how to add a new record about some person into DB. I think I should use the next order of actions:
Insert a record into subscriber table, because sub_link and phone tables must use id of a new subscriber.
Insert a record into address table because addr_id must exist before adding record into sub_link.
Link last records from subscriber and address in sub_link table. But at this step I have a new problem: how can I get sub_id and addr_id from steps 1) and 2) in PostgreSQL effectively?
Then I need to insert a record into the phone table. As at 3) step I dont know how to get sub_id from previous queries effectively.
I read about WITH block in the Postgres but I cannot figure out how to use it in my case.
UPDATE
I've done like ASL suggested:
-- First record --
WITH t0 AS (
WITH t1 AS (
INSERT INTO subscriber
VALUES(DEFAULT, 'Twilight Sparkle', NULL, NULL)
RETURNING sub_id
),
t2 AS (
INSERT INTO address
VALUES(DEFAULT, 'Equestria', 'Ponyville', NULL, NULL, NULL)
RETURNING addr_id
)
INSERT INTO sub_link
VALUES((SELECT sub_id FROM t1), (SELECT addr_id FROM t2))
)
INSERT INTO phone
VALUES (DEFAULT, '000000', (SELECT sub_id FROM t1), 1);
But I have an error: WITH clause containing a data-modifying statement must be at the top level
LINE 2: WITH t1 AS (INSERT INTO subscriber VALUES(DEFAULT,
You can do it all in one query using a WITH block with a RETURNING clause. See PostgreSQL docs on INSERT. For example:
WITH t1 AS (INSERT INTO subscriber VALUES ... RETURNING sub_id),
t2 AS (INSERT INTO address VALUES ... RETURNING addr_id)
INSERT INTO sub_link VALUES ((SELECT sub_id FROM t1), (SELECT addr_id FROM t2))
Note that this simple form will only work when inserting a single row into each table.
This is somewhat off the topic of your question, but I suggest you also consider making sub_id and cat_id columns in the phone table foreign keys (use REFERENCES).
You got the idea. Insert data from topmost tables so that you have their IDs before inserting references to them.
In PostgreSQL you can use INSERT/UPDATE ... RETURNING id construct. If you are not using some ORM which do it automatically, this may be useful.
The only thing here is that in step 2 you probably want to check if the address already exists before inserting:
SELECT addr_id FROM address WHERE country = ? AND city = ? ...

postgresql serial column not resetting

UPDATE
Adding create table statement to replicate the issue:
CREATE TABLE table1
(
id serial NOT NULL,
"timestamp" timestamp with time zone,
dir integer,
created timestamp without time zone,
deleted boolean DEFAULT false,
CONSTRAINT pk_table1_id PRIMARY KEY (id)
);
CREATE TABLE table2
(
id serial NOT NULL,
"timestamp" timestamp with time zone,
dir integer,
created timestamp without time zone,
deleted boolean DEFAULT false,
CONSTRAINT pk_table2_id PRIMARY KEY (id)
);
insert into table1 (timestamp, dir, created) values('2015-01-01 17:52:00', 3, now()), ('2015-01-02 17:52:00', 1, now()), ('2015-01-03 17:52:00', 1, now());
insert into table2
select * from table1
insert into table2 (timestamp, dir, created) values('2015-01-04 17:52:00', 3, now());
ERROR: duplicate key value violates unique constraint "pk_table2_id"
DETAIL: Key (id)=(1) already exists.
I am trying to reset the serial counter of a newly created table in postgres using the following:
SELECT setval('table2_id_seq', (SELECT MAX(id) FROM table2));
setval returns 3.
But counter is not being set as my next insert statement fails with the following error:
insert into table2 (timestamp, dir, created) values('2015-01-04 17:52:00', 3, now());
ERROR: duplicate key value violates unique constraint "pk_table2_id"
DETAIL: Key (id)=(2) already exists.
select version();
PostgreSQL 9.4.5 on x86_64-apple-darwin14.5.0, compiled by Apple LLVM version 7.0.0 (clang-700.0.72), 64-bit

Postgres before insert trigger using sequence from another table

Using Postgres, what I would like to achieve is to be able to have many different instrument types, with corresponding [TYPE].instrument tables, which all have a unique ID in the table, but also reference a unique ID in the instrument.master table. I have the following:
create schema instrument
CREATE TABLE instrument.type (
id smallserial NOT NULL,
name text not null,
code text not null,
CONSTRAINT pk_instrument_type PRIMARY KEY (id)
);
ALTER TABLE instrument.type ADD CONSTRAINT unq_instrument_type_code UNIQUE(code);
ALTER TABLE instrument.type ADD CONSTRAINT unq_instrument_type_name UNIQUE(name);
insert into instrument.type (name, code) values ('futures', 'f');
CREATE TABLE instrument.master (
id serial NOT NULL,
type smallint not null references instrument.type (id),
timestamp timestamp with time zone not null,
CONSTRAINT pk_instrument_master PRIMARY KEY (id)
);
CREATE TABLE futures.definition (
id smallserial NOT NULL,
code text not null,
CONSTRAINT pk_futures_definition PRIMARY KEY (id)
);
ALTER TABLE futures.definition ADD CONSTRAINT unq_futures_definition_code UNIQUE(code);
insert into futures.definition (code) values ('ED');
CREATE TABLE futures.instrument (
id smallserial NOT NULL,
master serial not null references instrument.master (id),
definition smallint not null references futures.definition (id),
month smallint not null,
year smallint not null,
CONSTRAINT pk_futures_instrument PRIMARY KEY (id),
check (month >= 1),
check (month <= 12),
check (year >= 1900)
);
ALTER TABLE futures.instrument ADD CONSTRAINT unq_futures_instrument UNIQUE(definition, month, year);
CREATE OR REPLACE FUNCTION trigger_master_futures()
RETURNS trigger AS
$BODY$
BEGIN
insert into instrument.master (type, timestamp)
select id, current_timestamp from instrument.type where code = 'f';
NEW.master := currval('instrument.master_id_seq');
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
create trigger trg_futures_instrument before insert on futures.instrument
for each row
execute procedure trigger_master_futures();
I then test with:
insert into futures.instrument (definition, month, year)
select id, 3, 2015 from futures.definition where code = 'ED';
Everything works almost as I would like it to. The only issue is that somehow, instrument.master.id ends up being one more than futures.instrument.master. I am not sure what I need to do to achieve the behavior I want, which is that whenever an entry is inserted into futures.instrument, an entry should be inserted into instrument.master, and the id entry of the latter should be inserted into the master entry of the former. I actually think it should have failed since the foreign key relationship is violated somehow.
As it turns out, everything was correct. The issue was that in futures.instrument, the type of the master column is serial, and it should have been int.