How can I insert values into a table with a composite primary key? - sql

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.

Related

Securing values for other tables from enumerable table in SQL Server database

English is not my native language, so I might have misused words Enumerator and Enumerable in this context. Please get a feel for what I'm trying to say and correct me if I'm wrong.
I'm looking into not having tables for each enumerator I need in my database.
I "don't want" to add tables for (examples:) service duration type, user type, currency type, etc. and add relations for each of them.
Instead of a table for each of them which values will probably not change a lot, and for which I'd have to create relationships with other tables, I'm looking into having just 2 tables called Enumerator (eg: user type, currency...) and Enumerable (eg: for user type -> manager, ceo, delivery guy... and for currency -> euro, dollar, pound...).
Though here's the kicker. If I implement it like that, I'm loosing the rigidity of the foreign key relationships -> I can't accidentally insert a row in users table that will have a user type of some currency or service duration type, or something else.
Is there another way to resolve the issue of having so many enumerators and enumerables with the benefit of having that rigidity of the foreign key and with the benefit of having all of them in just those 2 tables?
Best I can think of is to create a trigger for BEFORE UPDATE and BEFORE INSERT to check if (for example) the column type of user table is using the id of the enumerable table that belongs to the correct enumerator.
This is a short example in SQL
CREATE TABLE [dbo].[Enumerator]
(
[Id] INT NOT NULL PRIMARY KEY,
[Name] VARCHAR(50)
)
CREATE TABLE [dbo].[Enumerable]
(
[Id] INT NOT NULL PRIMARY KEY,
[EnumeratorId] INT NOT NULL FOREIGN KEY REFERENCES Enumerator(Id),
[Name] VARCHAR(50)
)
INSERT INTO Enumerator (Id, Name)
VALUES (1, 'UserType'),
(2, 'ServiceType');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- UserType
VALUES (1, 1, 'CEO'),
(2, 1, 'Manager'),
(3, 1, 'DeliveryGuy');
INSERT INTO Enumerable (Id, EnumeratorId, Name) -- ServiceDurationType
VALUES (4, 2, 'Daily'),
(5, 2, 'Weekly'),
(6, 2, 'Monthly');
CREATE TABLE [dbo].[User]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
CREATE TABLE [dbo].[Service]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[Type] INT NOT NULL FOREIGN KEY REFERENCES Enumerable(Id)
)
The questions are:
Is it viable to resolve enumerators and enumerables with 2 tables and with before update and before insert triggers, or is it more trouble than it's worth?
Is there a better way to resolve this other than using before update and before insert triggers?
Is there a better way to resolve enumerators and enumerables that is not using 2 tables and triggers, nor creating a table with relations for each of them?
I ask for your wisdom as I don't have one or more big projects behind me and I didn't get a chance to create a DB like this until now.

Violating foreign key constraint with deferred constraint

I'm trying to set my sql scripts into a transaction to achieve atomicity with my database.
The table structure is (simplified):
CREATE TABLE foo (
id serial NOT NULL,
foo varchar(50) NOT NULL,
CONSTRAINT foo_pk PRIMARY KEY (id)
);
CREATE TABLE access (
id serial NOT NULL,
foo_id int NULL
CONSTRAINT access_pk PRIMARY KEY (id)
);
ALTER TABLE access ADD CONSTRAINT access_foo
FOREIGN KEY (foo_id)
REFERENCES foo (id)
ON DELETE CASCADE
ON UPDATE CASCADE
DEFERRABLE
INITIALLY DEFERRED;
In my code I first declare:
client.query('BEGIN'); (I'm using npm library 'pg') then
insert a row into a table 'foo', then another insert to 'access' with a foo_id from the first insert. After that there is client.query('COMMIT');
All of this is in a try catch, and in the catch is client.query('ROLLBACK'); and the rolling back seems to be working if there is an issue either of the inserts. When everything should be committed I still end up in the catch block for this:
message: "insert or update on table "access" violates foreign key constraint "access_foo""
detail: "Key (foo_id)=(20) is not present in table "foo"."
I thought that deferring constraint would be enough to do this, but I guess I'm wrong. Any help is welcome.
You probably have some issue with the transaction demarcation. I ran a simple test and works wells.
insert into foo (id, foo) values (1, 'Anne');
start transaction;
insert into access (id, foo_id) values (101, 1);
insert into access (id, foo_id) values (107, 7); -- 7 does not exist yet...
insert into foo (id, foo) values (7, 'Ivan'); -- 7 now exists!
commit; -- at this point all is good
See running example at DB Fiddle.

How should I handle multiple foreign keys that all point to the same column in another table?

So let's say I have these two tables...
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='UnitsDef' AND xtype='U')
CREATE TABLE UnitsDef
(
UnitsID INTEGER PRIMARY KEY,
UnitsName NVARCHAR(32) NOT NULL,
UnitsDisplay NVARCHAR(8) NOT NULL
);
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='Dimensions' AND xtype='U')
CREATE TABLE Dimensions
(
DimID INTEGER PRIMARY KEY IDENTITY(0,1),
DimX FLOAT,
DimXUnitsID INTEGER DEFAULT 0,
DimY FLOAT,
DimYUnitsID INTEGER DEFAULT 0,
DimZ FLOAT,
DimZUnitsID INTEGER DEFAULT 0,
FOREIGN KEY (DimXUnitsID) REFERENCES UnitsDef(UnitsID),
FOREIGN KEY (DimYUnitsID) REFERENCES UnitsDef(UnitsID),
FOREIGN KEY (DimZUnitsID) REFERENCES UnitsDef(UnitsID)
);
I'll insert data into the first table similar to this...
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (0, 'inch', 'in.');
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (1, 'millimeter', 'mm');
INSERT INTO UnitsDef (UnitsID, UnitsName, UnitsDisplay) VALUES (2, 'degree', '°');
Am I going about this the right way? This is a simplified version of the problem, but I need to know which unit each measurement is given in. Is there a better design practice for this type of situation?
How would I handle the ON DELETE and ON UPDATE for these foreign keys? If I try to cascade deletes and updates, SQL Server would not be so happy about that.
Your method is pretty good. I would make the suggestion right off that UnitsId be an identity column, so it gets incremented. Your inserts would then be:
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('inch', 'in.');
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('millimeter', 'mm');
INSERT INTO UnitsDef (UnitsName, UnitsDisplay) VALUES ('degree', '°');
You should also make the string columns unique in UnitsDef and give them case-sensitive collations. After all, Ml and ml are two different things ("M" is mega and "m" is milli).
You might also want to combine the units and values into a single type. This has positives and negatives. For me it adds overhead, but it can help if you want to support a fuller algebra of types.

Msg 547, The INSERT statement conflicted with the FOREIGN KEY constraint

In SQL Server 2012 Management studio, I tried many time to create some tables and insert into the tables some values, but the problem here is in relationship with tables :
The INSERT statement conflicted with the FOREIGN KEY constraint
The Errors :
Msg 8152, Level 16, State 14, Line 116 String or binary data would be
truncated.
Msg 547, Level 16, State 0, Line 122 The INSERT statement conflicted
with the FOREIGN KEY constraint "eworkerFK". The conflict occurred in
database "7", table "dbo.member_clup", column 'manager_id'.
The statement has been terminated.
Msg 547, Level 16, State 0, Line 128
The INSERT statement conflicted with the FOREIGN KEY constraint
"SALEDFk". The conflict occurred in database "7", table "dbo.worker",
column 'worker_number'.
Can anyone help me to insert values into the correct
tables ?
CREATE TABLE address
(
code_place int,
PLACE_NAME VARCHAR (15),
OUT_israel varchar (15)
CONSTRAINT address1 PRIMARY KEY(code_place)
)
create table member_clup
(
manager_id int,
manager_name varchar(15),
manager_last varchar(12),
phone_num int,
type varchar(10),
CONSTRAINT manager1PK PRIMARY KEY(manager_id)
)
create table worker
(
worker_number int,
worker_name varchar(50),
worker_last varchar(49),
id varchar(9),
type varchar(50),
manager_id int
CONSTRAINT workerPK PRIMARY KEY(worker_number)
CONSTRAINT eworkerFK FOREIGN KEY(manager_id)
REFERENCES member_clup(manager_id)
)
CREATE TABLE rooms(
room_number int,
floor int,
room_type varchar(8)
CONSTRAINT roomsKEY PRIMARY KEY(room_number)
)
CREATE TABLE cars
(
cars_number int,
car_type varchar(15),
car_model int,
CONSTRAINT carsPK PRIMARY KEY(cars_number)
)
CREATE TABLE tourest(
Cust_number int ,
Cust_name varchar(50),
cust_lastname varchar(50),
cust_phone varchar(10),
code_place int,
Room_id int,
Saledby int
CONSTRAINT tourest1 PRIMARY KEY(Cust_number)
CONSTRAINT addressFK FOREIGN KEY(code_place)
REFERENCES address(code_place),
CONSTRAINT SALEDFk FOREIGN KEY(Saledby)
REFERENCES worker(worker_number),
CONSTRAINT roomsFK FOREIGN KEY(Room_id)
REFERENCES rooms(room_number)
)
CREATE TABLE kesher
(
Cust_number int,
cars_number int,
CONSTRAINT custPK1 PRIMARY KEY(Cust_number,cars_number),
CONSTRAINT kesher1FK FOREIGN KEY(Cust_number)
REFERENCES cars(cars_number),
CONSTRAINT kesherFK FOREIGN KEY(Cust_number)
REFERENCES tourest(Cust_number)
)
insert into cars VALUES
(100100,'mazda',2002),
(100205,'ford',2017),
(100206,'porch',1998),
(100207,'mazda',2017),
(100208,'opel',2002),
(100209,'mazda',2016),
(100210,'pijuot',2002),
(100211,'mazda',2015),
(100212,'mazda',2010),
(100213,'volvo',2002),
(100215,'ford',20012)
insert into rooms VALUES
(100,1,'single'),
(101,1,'double'),
(102,1,'single'),
(103,1,'double'),
(201,2,'signle'),
(202,2,'signle'),
(203,2,'signle'),
(204,2,'signle'),
(300,3,'double'),
(301,3,'double'),
(302,3,'double'),
(303,3,'double'),
(304,3,'signle')
insert into address VALUES
(500,'Akko','no'),
(501,'Haifa','no'),
(502,'Nahariya','no'),
(503,'Nataniya','no'),
(504,'carmieal','no'),
(505,'Nahef','no'),
(507,'Nitsrat','no'),
(510,'OUT','yes')
insert into member_clup VALUES
(5400,'shmolek','snaa','0525732572','General'),
(5696,'malloc','ali','0525552501','Rooms'),
(5991,'ramada','hassan','0532731212','Rooms & Tips'),
(5210,'meri','yako','0525022572','General Manager')
insert into worker
VALUES(1234,'halaa','khaled',1234567,'none',5696),
(2234,'fares','adoon',6542897,'none',5696),
(6670,'halaa','khaled',1001234,'none',5991),
(2554,'halaa','khaled',5658741,'none',5210),
(9987,'halaa','khaled',1123456,'none',5400)
insert into tourest VALUES
(1510,'moshe','yke','0525732579',500,101,2234),
(1520,'ninar','lait','052655541',500,102,6670),
(1521,'hasan','ahmad','0532578741',501,101,2234),
(1522,'ameer','karm','0545222741',500,104,6670),
(1523,'aliel','sraa','0525771572',504,100,2234),
(1524,'hasa','veto','0525122579',505,303,6670),
(1525,'saed','snaa','05255632579',505,303,2234),
(1526,'yakov','mero','0528132579',502,202,6670),
(1527,'mece','loka','0525962579',502,302,9987),
(1528,'ana','yokaf','0525791179',502,302,9987),
(1529,'lelya','mandlina','0527832579',505,203,9987),
(1530,'mnal','khokha','0525758579',507,204,5991),
(1531,'moka','panana','0525805579',507,200,2234)
insert into kesher VALUES
(1510,100100),
(1520,100209),
(1521,100100),
(1522,100209),
(1523,100206),
(1524,100206),
(1525,100213),
(1526,100206),
(1527,100213),
(1528,100213),
(1529,100209)
This code is straightforward to debug, you surely can work it out. Run each statement on it's own and see its result. If it fails, split it into smaller statements and repeat. If you can't split it, it's already small enough to debug by eyesight, it won't take long to figure the issue.
Before debugging though, know this, restarting from scratch is sometimes helpful/necessary, so have restart script(s) ready. In this scenario only a bunch of DROP TABLEs are necessary, they'll remove the tables and their records.
Your CREATE TABLE statements are working fine, that's one thing passed. Even if you had problems with them though, run them one by one to debug, not all at once.
Your INSERTs are problematic, yeah. Run each INSERT block one by one, and for the block that fails, split it into individual INSERT statements, one per record, and now you'll be able to tell which row is the problem.
Even though you cite certain foreign key conflict issues, I'm getting a bunch of different foreign key issues. Double-check the code you provided. Also,
the order of what statement is ran first matters (can I furnish the third floor of my house while I don't even have third and second floors? Can you cancel a booking that you didn't book yet?)
Lastly, the data seem to have truncation issues, whether the table column should be bigger or the records' values are incorrect is something only you can tell.

SQL Server unique constraint issue on unicode characters

I have my table definition as follows:
create table [Language](
Id int primary key identity,
Code varchar(11) not null unique,
NativeName nvarchar(50) not null unique
)
And then, I have a long list of statements that insert into that table. The problem is that some of the insert statements conflict on my NativeName column's unique constraint. The weird thing is that the content is not unique at all. For example, if I only insert the following with the table empty:
insert into Language (Code, NativeName) values('am', N'አማርኛ');
insert into Language (Code, NativeName) values('dv', N'ދިވެހިބަސް‏');
I get for the second insert.
Violation of UNIQUE KEY constraint 'UQ__Language__EB1957A5F98D1F9C'. Cannot insert duplicate key in object 'dbo.Language'. The duplicate key value is (ދިވެހިބަސް‏).
Does anyone know why unicode characters are causing these issues?
Try declaring the NativeName column with a more specific (binary) collation.
eg:
NativeName nvarchar(50) collate SQL_Latin1_General_CP437_BIN not null unique