How to model ownership of a resource (e.g. credit card) - sql

I'm trying to figure out how to model ownership of a resource. An example can be a credit card. In a scenario a credit card can be owned by a company, a business or a business_admin which is used to pay for a service that belongs to a business.
What I came up with is a table business_payment that references company_payment_method, business_payment_method, business_admin_payment_method as well as the business that gets the payment method assigned. They are all nullable which requires a trigger to check if the insert is valid - exactly one ID must be not null before insert:
CREATE TABLE business_payment (
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
company_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__company_payment_method
FOREIGN KEY (company_payment_method_id)
REFERENCES company_payment_method(id)
ON DELETE CASCADE,
business_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_payment_method
FOREIGN KEY (business_payment_method_id)
REFERENCES business_payment_method(id)
ON DELETE CASCADE,
business_admin_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_admin_payment_method
FOREIGN KEY (business_admin_payment_method_id)
REFERENCES business_admin_payment_method(id)
ON DELETE CASCADE
);
Pro:
The advantage I see here is that if any of the credit cards are deleted e.g.
DELETE FROM company_credit_card WHERE id = #companyCreditCardId;
also the business_payment_method will get deleted. On the application layer nobody has to take care of the cleaning this up.
Con:
On the other hand I now have a table which has NULL values and if Ever there was a new entity x_credit_card I'd have to add this column to this table as well as make sure the trigger does its job correctly.
So this is the solution I was thinking about but I'm not sure if this is very elegant - especially because I'm creating an M*N matrix with (M*N - M) NULL entries.
Can I do better than this setup?
Below is the complete code if you want to check it out. Unfortunately I can't make it run on SQLFiddle because of this DELIMITER thing.
DROP TABLE IF EXISTS company_business;
DROP TABLE IF EXISTS company_employee;
DROP TABLE IF EXISTS payment_method;
DROP TABLE IF EXISTS business_payment;
DROP TABLE IF EXISTS business_admin_payment_method;
DROP TABLE IF EXISTS company_payment_method;
DROP TABLE IF EXISTS business_payment_method;
DROP TABLE IF EXISTS company;
DROP TABLE IF EXISTS business_admin;
DROP TABLE IF EXISTS business;
CREATE TABLE company (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE business_admin (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE business (
id BIGINT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE company_employee (
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_employee__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
business_admin_id BIGINT NOT NULL,
CONSTRAINT fk_company_employee__business_admin
FOREIGN KEY (business_admin_id)
REFERENCES business_admin(id)
ON DELETE CASCADE,
PRIMARY KEY (company_id, business_admin_id)
);
CREATE TABLE company_business (
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_business__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
business_id BIGINT NOT NULL,
CONSTRAINT fk__company_business__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
PRIMARY KEY (company_id, business_id)
);
SET #businessAdminId1 = 1;
INSERT INTO business_admin(id) VALUES (#businessAdminId1);
SET #companyId1 = 1;
INSERT INTO company(id) VALUES (#companyId1);
INSERT INTO company_employee(company_id, business_admin_id) VALUES (#companyId1,#businessAdminId1);
SET #businessId1 = 1;
INSERT INTO business VALUES (#businessId1);
INSERT INTO company_business VALUES(#companyId1, #businessId1);
CREATE TABLE company_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
company_id BIGINT NOT NULL,
CONSTRAINT fk__company_payment_method__company
FOREIGN KEY (company_id)
REFERENCES company(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment_method__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_admin_payment_method (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
business_admin_id BIGINT NOT NULL,
CONSTRAINT fk__business_admin_payment_method__business_admin
FOREIGN KEY (business_admin_id)
REFERENCES business_admin(id)
ON DELETE CASCADE,
payment_method_token VARCHAR(128) NOT NULL
);
CREATE TABLE business_payment (
business_id BIGINT NOT NULL,
CONSTRAINT fk__business_payment__business
FOREIGN KEY (business_id)
REFERENCES business(id)
ON DELETE CASCADE,
company_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__company_payment_method
FOREIGN KEY (company_payment_method_id)
REFERENCES company_payment_method(id)
ON DELETE CASCADE,
business_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_payment_method
FOREIGN KEY (business_payment_method_id)
REFERENCES business_payment_method(id)
ON DELETE CASCADE,
business_admin_payment_method_id BIGINT,
CONSTRAINT fk__business_payment__business_admin_payment_method
FOREIGN KEY (business_admin_payment_method_id)
REFERENCES business_admin_payment_method(id)
ON DELETE CASCADE
);
DELIMITER //
CREATE TRIGGER before_insert_business_payment_method BEFORE INSERT ON business_payment
FOR EACH ROW BEGIN
DECLARE notNullForeignKeyFound BOOLEAN;
DECLARE errorMessage VARCHAR(100);
SET errorMessage = 'Exact one foreign key must be not null!';
SET notNullForeignKeyFound = FALSE;
-- Company credit card ID
IF NEW.company_payment_method_id IS NOT NULL THEN
SET notNullForeignKeyFound = TRUE;
END IF;
-- Business credit card ID
IF NEW.business_payment_method_id IS NOT NULL THEN
IF notNullForeignKeyFound IS TRUE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
SET notNullForeignKeyFound = TRUE;
END IF;
-- Business admin credit card ID
IF NEW.business_admin_payment_method_id IS NOT NULL THEN
IF notNullForeignKeyFound IS TRUE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
SET notNullForeignKeyFound = TRUE;
END IF;
-- Check if at least one ID is not null
IF notNullForeignKeyFound IS FALSE THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END IF;
END//
DELIMITER ;
SET #companyCreditCardId1 = 1;
INSERT INTO company_payment_method (id, company_id, payment_method_token) VALUES (#companyCreditCardId1, #companyId1, 'wergef');
SET #businessCreditCardId1 = 1;
INSERT INTO business_payment_method (id, business_id, payment_method_token) VALUES (#businessCreditCardId1, #businessId1, 'asjio');
--
-- Here comes the actual action ..
--
-- Succeeds
INSERT INTO business_payment (business_id, business_payment_method_id) VALUES (#businessId1, #companyCreditCardId1);
-- Fails
-- INSERT INTO business_payment (business_id, company_payment_method_id, business_payment_method_id) VALUES (#businessId1, #companyCreditCardId1, #businessCreditCardId1);
-- The following will delete:
-- + business_payment_method.payment_method_id = 1
-- + busuiness_payment_method.payment_method_id = 1
DELETE FROM business_payment_method WHERE id = #companyCreditCardId1;

Another way would be for you to have a business_entity table with an entity_type(business, employee, admin, etc.). Payment could have a single Foreign Key back to entity. You would then have a detail table for each entity type that would have the detail information for that particular type of entity.
business_entity--1----M--business_payment
| |--1-----1--employee
|--1-------1--admin

Related

Which the best way to use inheritance of tables in postgreSQL?

i want to use inheritance in my database (PostgreSQL) so i wrote this code but finally i found there are inherits in PostgreSQL
CREATE SEQUENCE public.user_account_id_seq;
CREATE TABLE public.user_account (
id BIGINT NOT NULL DEFAULT nextval('public.user_account_id_seq'),
login VARCHAR(50) NOT NULL,
f_name VARCHAR(50),
l_name VARCHAR(50),
email VARCHAR(50) ,
CONSTRAINT user_account_pk PRIMARY KEY (id)
);
CREATE SEQUENCE public.simple_user_account_id_seq;
CREATE TABLE public.simple_user_account (
id BIGINT NOT NULL DEFAULT nextval('public.simple_user_account_id_seq'),
CONSTRAINT simple_user_account_pk PRIMARY KEY (id)
);
CREATE SEQUENCE public.supervisor_account_id_seq;
CREATE TABLE public.supervisor_account (
id BIGINT NOT NULL DEFAULT nextval('public.supervisor_account_id_seq'),
CONSTRAINT supervisor_account_pk PRIMARY KEY (id)
);
with
ALTER TABLE public.simple_user_account ADD CONSTRAINT simple_user_account_fk
FOREIGN KEY (id)
REFERENCES public.user_account (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE public.supervisor_account ADD CONSTRAINT supervisor_account_fk
FOREIGN KEY (id)
REFERENCES public.user_account (id)
ON DELETE CASCADE
ON UPDATE NO ACTION
NOT DEFERRABLE;
or i use INHERITS of postgreSQL
With inheritance you cannot have globally unique constraints. If that doesn't bother you, you can use the feature.

Use two foreign key in table with 'on delete cascade'

CREATE TABLE Comments(
Id INT PRIMARY KEY IDENTITY(0,1),
TEXT NOT NULL,
Date Date NOT NULL ,
Point INT NOT NULL DEFAULT(0),
ID_User INT FOREIGN KEY REFERENCES Users(Id) ON DELETE CASCADE NOT NULL,
ID_Post INT FOREIGN KEY REFERENCES Posts(Id) NOT NULL
)
When I delete User from Users table it show me error that Comments table has
other Reference Key. What i have to do ?
The DELETE statement conflicted with the REFERENCE constraint "FK__Comments__ID_Pos__76969D2E". The conflict occurred in database "Facebook", table "dbo.Comments", column 'ID_Post'.
If you want to delete a user record, you need to delete the records in the foreign key tables.
In this case, you need to delete records in Comments table.
DELETE from dbo.Commnts
Where ID_User = "userid"
Then, you can remove the user record from Users table
I did some work on this, there is no error in the foreign keys you referenced here. you may probably have reference to comment id in some other tables.
this is what I tried
CREATE TABLE Users(
Id int primary key
)
CREATE TABLE posts(
Id int primary key
)
insert into Users values(1);
insert into Users values(2);
insert into posts values(3);
insert into posts values(4);
CREATE TABLE Comments(
Id INT PRIMARY KEY IDENTITY(0,1),
ID_User INT FOREIGN KEY REFERENCES Users(Id) ON DELETE CASCADE NOT NULL,
ID_Post INT FOREIGN KEY REFERENCES Posts(Id) NOT NULL
)
insert into Comments values(1,3);
insert into Comments values(2,4);
DELETE
FROM Users
WHERE id = 1 --this works fine

Invalid Column Name when Create trigger using SQL server

I encountered several errors when I tried to create a simple trigger using SQL server. Tables are created using:
CREATE TABLE person
(
person_id INT NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL,
phone INT,
birth_date DATE,
address VARCHAR
);
CREATE TABLE volunteers
(
person_id INT NOT NULL PRIMARY KEY,
skill VARCHAR,
FOREIGN KEY (person_id) REFERENCES person(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE physicians
(
person_id INT NOT NULL PRIMARY KEY,
speciality VARCHAR,
phone_number INT,
FOREIGN KEY (person_id) REFERENCES person(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE patients
(
person_id INT NOT NULL PRIMARY KEY,
contact_date DATE,
physician_id INT, -- TODO determine whether NULL able
-- TODO determine ON DELETE ACTION
CHECK (person_id <> physician_id),
FOREIGN KEY (person_id) REFERENCES person(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (physician_id) REFERENCES physicians(person_id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
);
CREATE TABLE outpatients
(
person_id INT NOT NULL PRIMARY KEY,
FOREIGN KEY (person_id) REFERENCES patients(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE visits
(
person_id INT NOT NULL,
date DATE NOT NULL,
comments VARCHAR,
PRIMARY KEY (person_id, date),
FOREIGN KEY (person_id) REFERENCES outpatients(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE employees
(
person_id INT NOT NULL PRIMARY KEY,
date_hire DATE,
FOREIGN KEY (person_id) REFERENCES person(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE nurses
(
person_id INT NOT NULL PRIMARY KEY,
certificate VARCHAR,
care_center_name VARCHAR,
FOREIGN KEY (person_id) REFERENCES employees(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
-- FOREIGN KEY (care_center_name) REFERENCES care_centers(name)
-- ON DELETE CASCADE
-- ON UPDATE CASCADE
);
CREATE TABLE care_centers
(
name VARCHAR PRIMARY KEY NOT NULL,
nurses_in_charge INT NOT NULL,
location VARCHAR,
type VARCHAR
-- FOREIGN KEY (nurses_in_charge) REFERENCES registered_nurse(person_id)
);
CREATE TABLE registered_nurse
(
person_id INT NOT NULL PRIMARY KEY,
care_center_name VARCHAR,
FOREIGN KEY (person_id) REFERENCES nurses(person_id),
-- ON DELETE CASCADE
-- ON UPDATE CASCADE,
FOREIGN KEY (care_center_name) REFERENCES care_centers(name)
-- ON DELETE CASCADE
-- ON UPDATE CASCADE
);
ALTER TABLE nurses
ADD constraint nurses__care_centers_FK
FOREIGN KEY (care_center_name) REFERENCES care_centers(name)
ON DELETE CASCADE
ON UPDATE CASCADE;
ALTER TABLE care_centers
ADD constraint care_centers__registered_nurse_FK
FOREIGN KEY (nurses_in_charge) REFERENCES registered_nurse(person_id);
CREATE TABLE beds
(
bed_number INT NOT NULL,
room_number INT NOT NULL,
care_center_name VARCHAR,
PRIMARY KEY (bed_number,room_number),
FOREIGN KEY (care_center_name) REFERENCES care_centers(name)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE residents
(
person_id INT NOT NULL PRIMARY KEY,
date_admitted DATE,
bed_number INT,
room_number INT,
FOREIGN KEY (person_id) REFERENCES patients(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (bed_number, room_number) REFERENCES beds(bed_number, room_number)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE staffs
(
person_id INT NOT NULL PRIMARY KEY,
job_class DATE,
FOREIGN KEY (person_id) REFERENCES employees(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE technicians
(
person_id INT NOT NULL PRIMARY KEY,
skill VARCHAR,
FOREIGN KEY (person_id) REFERENCES employees(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE TABLE laboratories
(
name VARCHAR NOT NULL PRIMARY KEY,
location VARCHAR
);
CREATE TABLE assignTechnicianToLab
(
person_id INT NOT NULL,
laboratories_name VARCHAR NOT NULL,
PRIMARY KEY(person_id, laboratories_name),
FOREIGN KEY (person_id) REFERENCES employees(person_id)
ON DELETE CASCADE
ON UPDATE CASCADE,
FOREIGN KEY (laboratories_name) REFERENCES laboratories(name)
ON DELETE CASCADE
ON UPDATE CASCADE
)
And the trigger I am trying to create:
-- Trigger
/* if nurse has certificate "RN", add to registered_nurse */
CREATE TRIGGER registered_nurse_trigger
ON nurses
FOR INSERT, UPDATE
AS
BEGIN
IF EXISTS (SELECT * FROM inserted where certificate = "RN")
BEGIN
INSERT INTO registered_nurse
VALUES(inserted.person_id, nurses.care_center_name);
END
END;
And I keep getting errors saying that:
Msg 207, Level 16, State 1, Procedure registered_nurse_trigger, Line 6
Invalid column name 'RN'.
Msg 4104, Level 16, State 1, Procedure registered_nurse_trigger, Line 8
The multi-part identifier "inserted.person_id" could not be bound.
Msg 4104, Level 16, State 1, Procedure registered_nurse_trigger, Line 8
The multi-part identifier "nurses.care_center_name" could not be bound.
I've been hanging over here for several hours and I really appreciate anyone can help me with it. Thank you very much!
You can't use VALUES() like that. Use INSERT..SELECT instead:
-- Trigger
/* if nurse has certificate "RN", add to registered_nurse */
CREATE TRIGGER registered_nurse_trigger ON nurses
For INSERT, UPDATE
AS BEGIN
INSERT INTO registered_nurse (person_id, care_center_name)
SELECT person_id, care_center_name
FROM inserted
WHERE certificate = 'RN'
END;
I don't think you need to reference nurses or have that EXISTS() either, but maybe I'm overlooking something.
You are using double quote instead of single quotes in your Create Trigger statement try this and see if it works:
-- Trigger
/* if nurse has certificate "RN", add to registered_nurse */
CREATE TRIGGER registered_nurse_trigger ON nurses
FOR INSERT, UPDATE
AS
BEGIN
IF EXISTS (SELECT * FROM inserted where certificate = 'RN')
BEGIN
INSERT INTO registered_nurse
SELECT person_id, care_center_name FROM Inserted;
END
END;

don`t understand how trigger works

Trigger should react to deleting row from table Suppliers if there is some supplies in the table Supplies from this supplier, trigger should cancel deleting.
This code allows to delete both, suppliers with supplies and suppliers without supply:
CREATE TRIGGER SuppliersDeleteCondition
ON Suppliers
FOR DELETE
AS
IF EXISTS (
SELECT 1
FROM Supplies Ses
JOIN DELETED D
ON D.SupplierID=Ses.SupplierID
)
BEGIN
RAISERROR ('This supplier has some supplies', 16, 1)
ROLLBACK TRANSACTION
END;
Approx tables view are:
Suppliers(SupplierID,Name,Address,BankDetails), Supplies(SupplyID,SupplierID,ProductID,ImplementationPeriod,Weight,Price)
Here is CREATE TABLE:
CREATE TABLE Suppliers
(
SupplierID INT IDENTITY,
Name VARCHAR(150) NOT NULL UNIQUE,
Address VARCHAR(900) NOT NULL,
BankDetails VARCHAR(9) NOT NULL UNIQUE,
CONSTRAINT pk_SupplierID PRIMARY KEY (SupplierID),
CONSTRAINT chk_Name_Suppliers CHECK (NOT Name LIKE '%[^a-z ]%' AND NOT Name LIKE '[ ]%' AND NOT Name LIKE '%[ ]' AND NOT Name LIKE '%[ ][ ]%'),
CONSTRAINT chk_Address_Suppliers CHECK (NOT Address LIKE '%[^a-zA-z0-9,./ ]%' AND NOT Address LIKE '[ ]%'),
CONSTRAINT chk_BankDetails_Suppliers CHECK (BankDetails LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
);
CREATE TABLE Supplies
(
SupplyID INT IDENTITY,
SupplierID INT,
ProductID INT,
ImplementationPeriod DATE NOT NULL,
Weight REAL NOT NULL,
Price MONEY NOT NULL,
CONSTRAINT pk_SupplyID PRIMARY KEY (SupplyID),
CONSTRAINT fk_SupplierID FOREIGN KEY (SupplierID) REFERENCES Suppliers(SupplierID) ON DELETE CASCADE,
CONSTRAINT fk_ProductID FOREIGN KEY (ProductID) REFERENCES Products(ProductID) ON DELETE CASCADE,
CONSTRAINT chk_Weight_Supplies CHECK (Weight > 0)
);
When I delete the row like this:
DELETE FROM Suppliers WHERE SupplierID=18
this row deleted and I got no error
You have a foreign key with the DELETE CASCADE option so the delete trigger is superfluous. The AFTER DELETE trigger will fire after rows from suppliers and supplies have been deleted so no rows will ever qualify for the EXISTS predicate. No need for the trigger here unless you could remove the foreign key, which I wouldn't recommend. Let SQL Server do the work for you.

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