I've a problem.
I want to create a table with 3 foreign key
PRAGMA foreign_keys = ON;
CREATE TABLE "Dipendente" ("idDipendente" INTEGER PRIMARY KEY AUTOINCREMENT,
"nome" VARCHAR NOT NULL,
"cognome" VARCHAR NOT NULL ,
"email" VARCHAR NOT NULL UNIQUE ,
"password" VARCHAR NOT NULL ,
"tipo" VARCHAR NOT NULL );
CREATE TABLE "Prodotto" ("idProdotto" INTEGER PRIMARY KEY AUTOINCREMENT,
"nome" VARCHAR NOT NULL UNIQUE,
"qta" INTEGER NOT NULL,
"prezzoUnita" FLOAT NOT NULL );
CREATE TABLE "Fondo" ("idFondo" INTEGER PRIMARY KEY AUTOINCREMENT,
"nome" VARCHAR NOT NULL UNIQUE,
"fondoDisponibile" FLOAT NOT NULL );
CREATE TABLE IF NOT EXISTS "Acquisto" (
`idAcquisto` INTEGER PRIMARY KEY NOT NULL ,
`idDipendente` INTEGER NOT NULL DEFAULT -1,
`idProdotto` INTEGER NOT NULL DEFAULT -1,
`idFondo` INTEGER NOT NULL DEFAULT -1,
`qta` INTEGER NOT NULL ,
`dataAcquisto` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ,
CONSTRAINT `fk_acquisto_dipendente`
FOREIGN KEY (`idDipendente` )
REFERENCES `Dipendente` (`idDipendente` )
ON DELETE SET DEFAULT
ON UPDATE NO ACTION,
CONSTRAINT `fk_acquisto_prodotto`
FOREIGN KEY (`idProdotto` )
REFERENCES `Prodotto` (`idProdotto` )
ON DELETE SET DEFAULT
ON UPDATE NO ACTION,
CONSTRAINT `fk_acquisto_fondo`
FOREIGN KEY (`idFondo` )
REFERENCES `Fondo` (`idFondo` )
ON DELETE SET DEFAULT
ON UPDATE NO ACTION);
CREATE INDEX 'fk_acquisto_dipendente' ON 'Acquisto' ('idDipendente' ASC);
CREATE INDEX 'fk_acquisto_prodotto' ON 'Acquisto' ('idProdotto' ASC);
CREATE INDEX 'fk_acquisto_fondo' ON 'Acquisto' ('idFondo' ASC);
So, I want to set Acquisto (idDipendente, idProdotto, idFondo) to -1 value by defaul, but when I delete the Dipendente's row with idDipendente = 1 in the table Acquisto the field idDipendente is set to 1 yet. I don't know what is the problem.
In the table "Acquisto", you have three foreign key references. Each column of those foreign key references has a default value of -1, which isn't (I presume) a valid value in any of the referenced tables.
In this specific case, if you first insert a row into "Dipendente", and that row has "idDipendente" of -1, then you can delete the row where "idDipendente" equals 1. When you do that, you'll find the default value of -1 in Acquisto.idDependente.
The short story is your foreign key reference doesn't prevent you from declaring a default value of -1, but it does prevent you from using it.
To set the values to NULL instead, you need to do something along these lines.
pragma foreign_keys = on;
create table a (id integer primary key);
insert into a values (1);
create table b (
b_id integer primary key,
a_id integer references a(id)
on delete set null);
insert into b values (1, 1);
delete from a;
select * from b;
b_id a_id
---------- ----------
1
Related
I would like to know if it's possible to create table with a not null constraint on a column depending of the value of another column in another table.
(In postgres)
exemple:
CREATE TABLE IF NOT EXISTS Ref (
id SERIAL PRIMARY KEY,
required BOOLEAN DEFAULT FALSE
);
CREATE TABLE IF NOT EXISTS Value (
id SERIAL PRIMARY KEY,
refId INTEGER REFERENCES Ref(id) NOT NULL,
value TEXT,
);
So here I would like to add a constraint NOT NULL to value if required is TRUE.
So I tried to use some check but it seem that it only check column inside the same table :(.
Thanks in advance.
I understood that when required field is equal to true, then we must set NOT NULL to the Value table's field, else set to must be NULL.
You can do this using PostgreSQL check constraints. Firstly we must create a function for checking field values.
CREATE OR REPLACE FUNCTION get_required(p_id integer, p_value text)
RETURNS BOOLEAN AS
$$
declare
v_ret bool;
begin
select required into v_ret from tbl_ref where id = p_id;
if (v_ret)and(p_value is null) then
return false;
end if;
return true;
END;
$$ LANGUAGE PLpgSQL;
Then we can use this function on the create table process:
CREATE TABLE tbl_val (
id serial4 NOT NULL,
ref_id int4 NOT NULL,
"value" text NULL,
CONSTRAINT tbl_val_check CHECK (get_required(ref_id, "value")),
CONSTRAINT tbl_val_pkey PRIMARY KEY (id),
CONSTRAINT tbl_val_fk FOREIGN KEY (ref_id) REFERENCES tbl_ref(id)
);
I have the following 3 tables. They are related:
CREATE TABLE [MemberDetails]
(
[MemberID] int identity (1000,1) NOT NULL UNIQUE,
[MName] varchar(100) NOT NULL,
[MSurname] varchar(100) NOT NULL,
[MPhone] varchar(20) NOT NULL UNIQUE,
[MEmail] varchar(200) NOT NULL UNIQUE,
[MAddress] varchar(250) NOT NULL,
[MActive] char (1) NOT NULL CHECK (MActive IN ('Y','N')) DEFAULT 'Y',
[MUpdateDate] Date NOT NULL DEFAULT GETDATE(),
[MPhoto] Image NOT NULL,
[MDid] int NULL UNIQUE,
[MTid] int NULL UNIQUE,
PRIMARY KEY ([MemberID]),
FOREIGN KEY (MDid) REFERENCES [MembershipDetails] ([MDid])
ON DELETE SET NULL
ON UPDATE CASCADE,
FOREIGN KEY (MTid) REFERENCES [MarketingTarget] ([MTid])
ON DELETE SET NULL
ON UPDATE CASCADE
);
CREATE TABLE [MarketingTarget]
(
[MTid] int identity (5000,1) NOT NULL UNIQUE,
[MDOB] date NOT NULL,
[MSex] char NOT NULL CHECK (MSex IN ('M','F')) DEFAULT 'M',
PRIMARY KEY ([MTid]),
);
CREATE TABLE [MembershipDetails]
(
[MDid] int identity (2000,1) NOT NULL UNIQUE,
[MType] varchar(10) NOT NULL CHECK (MType IN ('Monthly', 'Quaterly', 'Yearly')) DEFAULT 'Monthly',
[JoinDate] Date NOT NULL DEFAULT GETDATE(),
[ExpiryDate] Date NULL,
[MsUpdateDate] Date DEFAULT GETDATE(),
PRIMARY KEY ([MDid])
);
I would like to know if it's possible to insert the FKs automatically into the MemberDetails table from the other two tables? I am trying to write the Stored Procedures.
I was checking the Scope_Identity which can get the last identity generated but I am not sure how to use it properly.
Any suggestions would be much appreciate it.
Here is an example (table has been shortened): Since both IDENTITY values are required, I'd save them into a variable and then insert together into MemberDetail.
I would recommend to have a transaction for this operation. And have a look at TRY..CATCH. Depending on your situation you might want to check XACT_STATE().
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql?view=sql-server-ver15
and there are examples using a trigger
https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-ver15
CREATE TABLE [_TEST_MemberDetails] (
[MemberID] int identity (1000,1) NOT NULL UNIQUE,
[MDid] int NULL UNIQUE,
[MTid] int NULL UNIQUE,
PRIMARY KEY ([MemberID]),
FOREIGN KEY (MDid) REFERENCES [_TEST_MembershipDetails] ([MDid]) ON DELETE SET NULL
ON UPDATE CASCADE,
FOREIGN KEY (MTid) REFERENCES [_TEST_MarketingTarget] ([MTid]) ON DELETE SET NULL
ON UPDATE CASCADE
);
CREATE TABLE [_TEST_MarketingTarget] (
[MTid] int identity (5000,1) NOT NULL UNIQUE,
[MDOB] date NOT NULL,
[MSex] char NOT NULL CHECK (MSex IN ('M','F')) DEFAULT 'M',
PRIMARY KEY ([MTid]),
);
CREATE TABLE [_TEST_MembershipDetails] (
[MDid] int identity (2000,1) NOT NULL UNIQUE,
[MType] varchar(10) NOT NULL CHECK (MType IN ('Monthly','Quaterly','Yearly')) DEFAULT 'Monthly',
[JoinDate] Date NOT NULL DEFAULT GETDATE(),
[ExpiryDate] Date NULL,
[MsUpdateDate] Date DEFAULT GETDATE(),
PRIMARY KEY ([MDid])
);
-- SP CODE START HERE
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION
DECLARE #MTID int = 0, #MDID int = 0
INSERT INTO _TEST_MarketingTarget ([MDOB], [MSex])
VALUES ('Jan 1, 2020', 'M')
SELECT #MTID = SCOPE_IDENTITY()
INSERT INTO [_TEST_MembershipDetails] ([MType], [JoinDate], [ExpiryDate], [MsUpdateDate])
VALUES (DEFAULT, DEFAULT, 'Jan 1, 2020', DEFAULT)
SELECT #MDID = SCOPE_IDENTITY()
INSERT INTO [_TEST_MemberDetails] (Mdid, MTid)
SELECT #MDID, #MTID
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT <> 0 ROLLBACK TRANSACTION
END CATCH
go
This question already has answers here:
Foreign Key Constraint in child table allows to insert values that doesn't exists in the parent table
(2 answers)
Closed 3 years ago.
Consider the following tables:
CREATE TABLE Foo
(
FooId1 int NOT NULL,
FooId2 int NOT NULL,
PRIMARY KEY(FooId1, FooId2)
);
INSERT INTO Foo(FooId1, FooId2) VALUES (1, 10), (2, 20);
CREATE TABLE Bar
(
BarId int NOT NULL PRIMARY KEY,
FooId1 int NULL,
FooId2 int NULL
);
ALTER TABLE Bar ADD CONSTRAINT FK_FOO
FOREIGN KEY(FooId1, FooId2)
REFERENCES Foo(FooId1, FooId2);
INSERT INTO Bar(BarId) VALUES(42);
If I then try
UPDATE Bar
SET FooId1 = 3,
FooId2 = 30
WHERE BarId = 42;
I'm getting an foreign key violation as expected. But if I do
UPDATE Bar
SET FooId1 = NULL,
FooId2 = 30
WHERE BarId = 42;
it works without an error. I would have expected that even though the fields FooId1 and FooId2 are nullable the combination of both would always be checked against the foreign key. Why does the DB allow this UPDATE?
When a value other than NULL is entered into the column of a FOREIGN
KEY constraint, the value must exist in the referenced column;
otherwise, a foreign key violation error message is returned. To make
sure that all values of a composite foreign key constraint are
verified, specify NOT NULL on all the participating columns.
Create Foreign Key Relationships
According to this explanation of the MSDN, you should define the Food1 and Food2 columns of the Bar columns with NOT NULL constraint.
CREATE TABLE Bar
(
BarId int NOT NULL PRIMARY KEY,
FooId1 int NOT NULL,
FooId2 int NOT NULL
)
So that the following insert will not work;
INSERT INTO Bar(BarId) VALUES(42)
Msg 515, Level 16, State 2, Line 23
Cannot insert the value NULL into column 'FooId1', table 'AdventureWorks2017.dbo.Bar'; column does not allow nulls. INSERT fails.
The statement has been terminated.
added Default Constraint on a Foreign key column for default value so if the user does not supply value default value should be inserted. but instead of firing constraint, it shows Column name or number of supplied values does not match table definition.
--Table--
create table tblperson(
Id int not null,
Name nvarchar(50) not null,
Email nvarhcar(50) not null,
GenderId int
);
--tblGender--
Create Table tblGender(
ID int Not Null Primary Key,
Gender nvarchar(50)
);
--Add foreign Key--
Alter table tblPerson
add constraint tblPerson_GenderId_FK FOREIGN KEY (GenderId) references tblGender(ID)
--Default Constraint--
ALTER TABLE tblPerson
ADD CONSTRAINT DF_tblPerson_GenderId
DEFAULT 1 FOR GenderId
--Insert Statement--
insert into tblperson values(5,'Jake','j#j.com')
The answer to your question is:
insert into tblperson(Id, Name, Email) values(1,'Jake','j#j.com');
Most of people forget to write the columns names, you should always be carful of the columns names and the number of supplied values.
BTW, fix the typo in this line:
Email nvarhcar(50) not null,
it should be:
Email nvarchar(50) not null,
When I have table with PRIMARY KEY from 2 columns:
CREATE TABLE SizeTypes
(
TypeID tinyint NOT NULL,
SizeID tinyint NOT NULL,
Name varchar(100) NOT NULL,
CONSTRAINT PK_SizeType
PRIMARY KEY (TypeID, SizeID)
)
How can I create second table with a foreign key that have 1st constant value and 2nd from column like below:
CREATE TABLE Something
(
ID INT IDENTITY(1,1) PRIMARY KEY,
SizeTypeID_1 TINYINT,
SizeTypeID_2 TINYINT,
SizeTypeID_3 TINYINT,
CONSTRAINT FK_Something_SizeTypes_1
FOREIGN KEY (1, SizeTypeID_1)
REFERENCES SizeTypes(TypeID, SizeID),
CONSTRAINT FK_Something_SizeTypes_2
FOREIGN KEY (2, SizeTypeID_2)
REFERENCES SizeTypes(TypeID, SizeID),
CONSTRAINT FK_Something_SizeTypes_3
FOREIGN KEY (3, SizeTypeID_3)
REFERENCES SizeTypes(TypeID, SizeID)
)
This can be done using FOREIGN KEY, if yes then how?
If no then what other ways to do this I have? Triggers on INSERT and UPDATE for table something and on DELETE for table SizeTypes? Any other choices I have?
It looks like the following code will let you create suitable check constraints with the check implemented by a separate function:
-- Create the first table.
create table SizeTypes(
TypeId TinyInt not NULL,
SizeId TinyInt not NULL,
Name VarChar(100) not NULL,
constraint PK_SizeType primary key ( TypeId, SizeId ) );
go
-- Create a function to implement the logic for the check constraint.
create function CheckSizeTypeId(
#TypeId TinyInt, #SizeId TinyInt )
returns Int
as begin
-- Replace the following statement with the logic for your check.
if #SizeId >= 0 and #SizeId <= ( select SizeId from SizeTypes where TypeID = #TypeID )
return 1;
return 0;
end;
go
-- Create the second table with the check constraints.
create table Something(
Id Int identity(1,1) primary key,
SizeTypeId_1 TinyInt,
SizeTypeId_2 TinyInt,
SizeTypeId_3 TinyInt,
constraint Check_SizeTypeId_1 check ( dbo.CheckSizeTypeId( 1, SizeTypeId_1 ) = 1 ),
constraint Check_SizeTypeId_2 check ( dbo.CheckSizeTypeId( 2, SizeTypeId_2 ) = 1 ),
constraint Check_SizeTypeId_3 check ( dbo.CheckSizeTypeId( 3, SizeTypeId_3 ) = 1 ) );
go
-- Houseclean.
drop table SizeTypes;
drop table Something;
drop function CheckSizeTypeId;
Note that the constraints restrict what you can do with values in Something. Changes in SizeTypes will not revalidate data in Something, though that could be implemented in a trigger on SizeTypes.