Fill in bridge table with query - sql

I have four tables, the main purpose of these tables is to have a many to many keyword to message relationship. each keyword can have many messages and each message can have many keywords they are related together if the category id matches.
CREATE TABLE public.trigger_category
(
id integer NOT NULL DEFAULT nextval('trigger_category_id_seq'::regclass),
description text COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT trigger_category_id PRIMARY KEY (id)
)
CREATE TABLE public.trigger_keyword
(
id integer NOT NULL DEFAULT nextval('trigger_keyword_id_seq'::regclass),
keyword text COLLATE pg_catalog."default" NOT NULL,
category_id bigint NOT NULL,
CONSTRAINT trigger_keyword_id PRIMARY KEY (id),
CONSTRAINT trigger_keyword_category_id_fkey FOREIGN KEY (category_id)
REFERENCES public.trigger_category (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE NO ACTION
)
CREATE TABLE public.trigger_message
(
id integer NOT NULL DEFAULT nextval('trigger_message_id_seq'::regclass),
message text COLLATE pg_catalog."default" NOT NULL,
category_id bigint NOT NULL,
CONSTRAINT trigger_message_id PRIMARY KEY (id),
CONSTRAINT trigger_message_category_id_fkey FOREIGN KEY (category_id)
REFERENCES public.trigger_category (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
)
CREATE TABLE public.trigger_keyword_trigger_message
(
trigger_keyword_id bigint NOT NULL,
trigger_message_id bigint NOT NULL,
CONSTRAINT trigger_keyword_trigger_message_trigger_keyword_id_trigger_mess PRIMARY KEY (trigger_keyword_id, trigger_message_id),
CONSTRAINT trigger_keyword_trigger_message_trigger_keyword_id_fkey FOREIGN KEY (trigger_keyword_id)
REFERENCES public.trigger_keyword (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE NO ACTION,
CONSTRAINT trigger_keyword_trigger_message_trigger_message_id_fkey FOREIGN KEY (trigger_message_id)
REFERENCES public.trigger_message (id) MATCH SIMPLE
ON UPDATE CASCADE
ON DELETE NO ACTION
)
I manually insert keywords in the trigger_keyword table and I manually insert messages in the trigger_message table, if they are related then they would get the same category_id
Is it possible to write a query that would automatically go through the rows and if a keyword and message have the same category_id then it would create all the appropriate rows for the bridge table trigger_keyword_trigger_message?

You could achieve this with an Oracle Merge Query.
The USING clause selects all records to insert, and the WHEN MATCHED does to inserts in the bridge table.
MERGE INTO trigger_keyword_trigger_message tktm
USING (
SELECT tk.id tk_id, tm.id tm_id
FROM
trigger_keyword tk
INNER JOIN trigger_message tm on tm.category_id = tk.category_id
) us
WHEN MATCHED THEN
INSERT (tktm.trigger_keyword_id, tktm.trigger_message_id)
VALUES (us.tk_id, us.tm_id)
;

Related

ERROR: No unique constraint matching when having FK

I have three tables that are linked together
My script:
-- Ticket --
CREATE TABLE public.ticket (
id bigint NOT NULL,
libelle character varying(255) NOT NULL,
description character varying(255) NOT NULL,
status character varying(255) NOT NULL,
date_creation timestamp NOT NULL,
date_modification timestamp NOT NULL,
user_createur_id bigint,
referent_realisateur_id bigint,
CONSTRAINT pk_ticket PRIMARY KEY (id)
);
-- Ticket_Avance TABLE --
CREATE TABLE public.ticket_avance (
id bigint NOT NULL,
date_livraison_souhaite timestamp NOT NULL,
date_engagement_livraison timestamp NOT NULL,
referent_demandeur_id bigint
);
ALTER TABLE public.ticket_avance ADD CONSTRAINT "fk_ticket_ticketAvance" FOREIGN KEY (id)
REFERENCES public.ticket (id) MATCH SIMPLE
ON DELETE NO ACTION ON UPDATE NO ACTION;
-- Demande_Travaux TABLE --
DROP TABLE IF EXISTS public.demande_travaux CASCADE;
CREATE TABLE public.demande_travaux (
id bigint NOT NULL,
contrat_id bigint
);
ALTER TABLE public.demande_travaux ADD CONSTRAINT "fk_ticketAvance_DDT" FOREIGN KEY (id)
REFERENCES public.ticket_avance (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
I have this error on the demand_travaux creation
SQL Error [42830]: ERROR: there is no unique constraint matching given keys for referenced table "ticket_avance"
ERROR: there is no unique constraint matching given keys for referenced table "ticket_avance"
ERROR: there is no unique constraint matching given keys for referenced table "ticket_avance"
You have forgotten to declare column ID in table ticket_avance as primary key.
Please use the following SQL:
-- Ticket_Avance TABLE --
CREATE TABLE public.ticket_avance (
id bigint NOT NULL,
date_livraison_souhaite timestamp NOT NULL,
date_engagement_livraison timestamp NOT NULL,
referent_demandeur_id bigint,
CONSTRAINT pk_avance PRIMARY KEY (id) --- add this
);
you need add constraint in Ticket_Avance table because you provide reference this id to demande_travaux
-- Ticket_Avance TABLE --
CREATE TABLE ticket_avance (
id bigint NOT NULL,
date_livraison_souhaite timestamp NOT NULL,
date_engagement_livraison timestamp NOT NULL,
referent_demandeur_id bigint,
CONSTRAINT pk_ticket_avance PRIMARY KEY (id) //constraint that you need
);
ALTER TABLE demande_travaux ADD CONSTRAINT "fk_ticketAvance_DDT" FOREIGN KEY (id)
REFERENCES ticket_avance (id) MATCH FULL
ON DELETE NO ACTION ON UPDATE NO ACTION;
here is the demo link of your full query
A foreign key constraint has to target a primary key or unique constraint. The database has to be able to identify a single row in the "parent" table.
You could add primary key constraints:
ALTER TABLE public.ticket_avance ADD PRIMARY KEY (id);
In addition, you should have an index on the column on which the foreign key is defined, particularly if you plan to delete parent rows. With the primary key above, you have such an index on id, but you also should have one on demande_travaux.
The simplest way is to define id as primary key there too:
ALTER TABLE public.demande_travaux ADD PRIMARY KEY (id);

PostgreSQL CHECK Constraint on columns other than foreign keys

I have a situation where I want to create a table that associates records from other tables by the id. A constraint of the association is that the year must be the same in the record being associated in each table... Is there a way to get PostgreSQL to CHECK this condition on INSERT?
Table 1:
CREATE TABLE "tenant"."report" (
"id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(),
CONSTRAINT "report_pkc_id" PRIMARY KEY ("id"),
"reporting_period" integer NOT NULL,
"name" VARCHAR(64) NOT NULL,
CONSTRAINT "report_uc__name" UNIQUE ("reporting_period", "name"),
"description" VARCHAR(2048) NOT NULL
);
Table 2:
CREATE TABLE "tenant"."upload_file" (
"id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(),
CONSTRAINT "upload_file_pkc_id" PRIMARY KEY ("id"),
"file_name" VARCHAR(256) NOT NULL,
"reporting_period" integer
)
Association Table:
CREATE TABLE "tenant"."report_upload_files"
(
"report_id" UUID NOT NULL,
CONSTRAINT "report_upload_files_pkc_tenant_id" PRIMARY KEY ("report_id"),
CONSTRAINT "report_upload_files_fkc_tenant_id" FOREIGN KEY ("report_id")
REFERENCES "tenant"."report" ("id") MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
"upload_file_id" UUID NOT NULL,
CONSTRAINT "report_upload_files_fkc_layout_id" FOREIGN KEY ("upload_file_id")
REFERENCES "tenant"."upload_file" ("id") MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
I want to add something like to the association table CREATE statement:
CHECK ("tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period")
You're solving problems that you've created yourself.
Your data model is a typical one-to-many relationship. You don't need an association table. Also, you don't need the same column in two related tables, one of them is redundant. Use the model as shown below to avoid typical problems resulting from lack of normalization.
create table tenant.report (
id uuid primary key default pascal.uuid_generate_v1(),
reporting_period integer not null,
name varchar(64) not null,
description varchar(2048) not null,
unique (reporting_period, name)
);
create table tenant.upload_file (
id uuid primary key default pascal.uuid_generate_v1(),
report_id uuid references tenant.report(id),
file_name varchar(256) not null
);
Using this approach there's no need to ensure that the reporting periods match between the associated records.
BTW, I would use text instead of varchar(n) and integer (serial) instead of uuid.
Using a TRIGGER function I was able to achieve the desired effect:
CREATE FUNCTION "tenant".report_upload_files_create() RETURNS TRIGGER AS
$report_upload_files_create$
BEGIN
IF NOT EXISTS (
SELECT
*
FROM
"tenant"."report",
"tenant"."upload_file"
WHERE
"tenant"."report"."id" = NEW."report_id"
AND
"tenant"."upload_file"."id" = NEW."upload_file_id"
AND
"tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period"
)
THEN
RAISE EXCEPTION 'Report and Upload File reporting periods do not match';
END IF;
RETURN NEW;
END
$report_upload_files_create$ LANGUAGE plpgsql;
CREATE TRIGGER "report_upload_files_create" BEFORE INSERT ON "tenant"."report_upload_files"
FOR EACH ROW EXECUTE PROCEDURE "tenant".report_upload_files_create();

error: there is no unique constraint matching given keys for referenced table "incident"

I know that this question has been already answered a million of times, but I couldn't find any solution. Well I have these three tables on postgres sql.
CREATE TABLE user_account (
id SERIAL not null,
firstName VARCHAR(60) not null,
lastName VARCHAR(60) not null,
password VARCHAR(150) not null,
email VARCHAR(40) not null UNIQUE,
isVolunteer BOOLEAN,
complete BOOLEAN,
CONSTRAINT pk_user PRIMARY KEY (id));
CREATE TABLE incident (
id SERIAL not null,
patientId INTEGER not null,
incidentTime VARCHAR(10) not null,
latitude NUMERIC not null,
longitude NUMERIC not null,
city VARCHAR(60) not null,
state VARCHAR(60),
country VARCHAR(60),
complete BOOLEAN,
CONSTRAINT pk_incident PRIMARY KEY (id, patientId),
CONSTRAINT fk_incident FOREIGN KEY (patientId)
REFERENCES user_account (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE incident_has_volunteer (
incidentId INTEGER not null,
volunteerId INTEGER not null,
incidentTime VARCHAR(10) not null,
complete BOOLEAN,
CONSTRAINT pk_incident_has_volunteer PRIMARY KEY (incidentId, volunteerId),
CONSTRAINT fk_volunteer FOREIGN KEY (volunteerId)
REFERENCES user_account (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT fk_incident FOREIGN KEY (incidentId)
REFERENCES incident (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE);
When I try to create the table incident_has_volunteer it throws the error there is no unique constraint matching given keys for referenced table "incident".
I tried to add on the third table and the patientId as a foreign key from table incident table but with no luck. I can't understand why it throws this error even if I have already set the primary keys on the incident table.
I'm not an expert in postgres, but I believe that the problem is while fk_incident is referencing incident.id, incident's primary key is made of id + patientId. Since incident.id is guaranteed to be unique only in combination with patientId, there's no way to ensure referential integrity.
I believe that if you add a unique constraint to incident.id (I'm assuming that it would be unique), your foreign key will be legal.
Very simply - one table of primary key acts as a foreign key for another table, so you must ensure that both key is referenced or not.
Simply you will not assign foreign key to the column of another table which does not have primary key. this is called as RDBMS.
Thanks

Sybase constraint with foreign key and conditional check against foreign table column value

Is it possible on Sybase to define a constraint(s) which require a column to be a foreign key and also satisfy a condition based on the value of a foreign column, e.g. in the below example tables could a constraint be created on the "product" table such that "product.code is a foreign key of a brand.code which has valid=1"?
CREATE TABLE brand (
code char(8) NOT NULL,
valid int NOT NULL,
rowid numeric(10,0) IDENTITY,
CONSTRAINT brand_pk PRIMARY KEY (code),
CONSTRAINT valid_check CHECK (valid IN (0,1))
)
CREATE TABLE product (
code char(8) NOT NULL,
CONSTRAINT product_pk PRIMARY KEY (code)
)
I think it's best to change the structure just a little bit.
CREATE TABLE brand (
code char(8) NOT NULL,
valid int NOT NULL,
rowid numeric(10,0) IDENTITY,
CONSTRAINT brand_pk PRIMARY KEY (code),
-- The following UNIQUE constraint lets the pair of values be the target of
-- a foreign key reference.
CONSTRAINT brand_is_valid UNIQUE (code, valid),
CONSTRAINT valid_check CHECK (valid IN (0,1))
);
CREATE TABLE product (
code char(8) NOT NULL,
valid int NOT NULL,
-- The column "code" is a PK in the referenced table, so this still works. It's
-- a 1:0 or 1:1 relationship.
CONSTRAINT product_pk PRIMARY KEY (code),
-- The next constraint requires a unique constraint on the pair of
-- columns in the table "brand". By itself, it references every row
-- in "brand". That's too many rows.
CONSTRAINT product_fk FOREIGN KEY (code, valid)
REFERENCES brand (code, valid),
-- But this constraint restricts the foreign key references to only those
-- rows that have valid = 1 in the table "brand".
CHECK (valid = 1)
);
In order to bypass the creation of a foreign-key based on the "valid" condition, you will need to modify your table design and create a trigger to set the product.code = NULL. Pardon my syntax (I haven't coded Sybase for a while), but this is the general idea:
Add a new column to serve as the primary key since we will need to set product.code = NULL when valid=0:
CREATE TABLE product (
rowid int identity primary key,
code char(8) NULL,
CONSTRAINT brand_fk FOREIGN KEY (code) REFERENCES brand(code)
)
Then create a trigger similar to this one:
create trigger FK_WhenValid
on product
for insert
AS
IF (SELECT COUNT(*) FROM brand b inner join inserted i on b.code = i.code AND b.valid=0 ) > 0
BEGIN
UPDATE product SET code = NULL WHERE code in (SELECT i.code from brand b join inserted i on b.code = i.code and b.valid = 0)
END
Note: this trigger only supports product insertions. If "valid" can change, another approach is required.
You could also implement the foreign key as a trigger instead of a declarative constraint and only set product.code = inserted.code when valid = 1

How can I get around this foreign key constraint having to have a unique name?

I'm not sure why these have to be unique, but from reading the MySQL forums it appears that they do. However, I think it has something more to do with the INDEX name. I have two tables that have foreign key constraints referencing the same primary key on a third table. If it helps, I'm using MySQL workbench to design the schema.
I usually name my foreign key on each table the same name as the primary key it references. I guess this isn't possible. It will create the first table with the foreign key constraint, but when it tries to create the second table it throws an error. Here is the second table it throws the error on:
CREATE TABLE IF NOT EXISTS `joe`.`products_to_categories` (
`product_to_category_id` INT NOT NULL AUTO_INCREMENT ,
`category_id` INT NOT NULL ,
`product_id` INT NOT NULL ,
PRIMARY KEY (`product_to_category_id`) ,
INDEX `category_id` (`category_id` ASC) ,
INDEX `product_id` (`product_id` ASC) ,
CONSTRAINT `category_id`
FOREIGN KEY (`category_id` )
REFERENCES `joe`.`categories` (`category_id` )
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `product_id`
FOREIGN KEY (`product_id` )
REFERENCES `joe`.`products` (`product_id` )
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I want the foreign key names to be the same as the primary key in both of the other tables. What should I remove here so that I can use these names. What is the best practice here.
It is not possible because you would have a conflict in the filename for the file that is used for the index IIRC. I probably would name the key < tablename >_< column_name > or something like that.
You are creating an index (constraint) by the name of product_id via:
INDEX product_id
Then you are going and creating another constraint (for the foreign key) with the same name:
CONSTRAINT product_id
What you need to do is allow the server to provide a default, unique constraint name by removing the
CONSTRAINT product_id
See this URL: http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
"If the CONSTRAINT symbol clause is given, the symbol value must be unique in the database. If the clause is not given, InnoDB creates the name automatically."
In PostgreSQL, the default for naming indexes is to append "_pkey" and "_fkey" to the name of the primary and foreign key, respectively. So your case would look like:
INDEX `product_id_fkey` (`product_id` ASC) ,
UPDATE: I just tried this and it worked. See if that's what you had in mind.
use test;
create table if not exists test.product
(
product_id int not null auto_increment,
name varchar(80) not null,
primary key(product_id)
);
create table if not exists test.category
(
category_id int not null auto_increment,
name varchar(80) not null,
primary key(category_id)
);
create table if not exists test.product_category
(
product_id int,
category_id int,
primary key(product_id, category_id),
constraint product_id_fkey
foreign key(product_id) references product(product_id)
on delete cascade
on update no action,
constraint category_id_fkey
foreign key(category_id) references category(category_id)
on delete cascade
on update no action
);
insert into test.product(name) values('teddy bear');
insert into test.category(name) values('toy');
insert into test.product_category
select p.product_id, c.category_id from product as p, category as c
where p.name = 'teddy bear' and c.name = 'toy';