SQL Server unique constraint issue on unicode characters - sql

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

Related

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

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.

Why does the zipcode fail the check constraint?

I feel like I am probably missing something really simple, but I really can't figure out what I'm doing wrong. I'm trying to use a check constraint to make sure zipcodes are 5 digit numbers, but the check restraint keeps failing. Here is the table creating with the constraint:
Create Table Students (
StudentID Int Primary Key Identity(1,1)
StudentNumber nVarchar(100) Unique Not Null,
...
StudentZipCode nChar(10) Not Null
)
Go
Alter Table Students Add Constraint chZipCode
CHECK (StudentZipCode LIKE '[0-9][0-9][0-9][0-9][0-9]' OR StudentZipCode
Like '[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]')
Go
Codes like 12345-6789 work, but when I try to insert the values like '12345' or '01234' it gives me this error:
The INSERT statement conflicted with the CHECK constraint "chZipCode". The conflict occurred in database ..., table "dbo.Students", column 'StudentZipCode'.
It fails because you defined the zip code as a char() instead of a varchar(). Hence, it has a bunch of spaces padding it out.
So, define it as:
Create Table Students (
StudentID Int Primary Key Identity(1,1),
StudentNumber nVarchar(100) Unique Not Null,
StudentZipCode nVarChar(10) Not Null,
CHECK (StudentZipCode LIKE '[0-9][0-9][0-9][0-9][0-9]' OR
StudentZipCode LIKE '[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]')
);
Then '12345' works, because it matches the first of the LIKE patterns.
'012344' does not work, because no pattern has six digits in a row.
Here is a SQL Fiddle.

I can't insert null on a Foreign Key

I've tried to search but nothing works, and I don't know what to do.
There's a table with two foreign keys, one of which can be null. According to what I've searched, it's perfectly fine to have null foreign keys. But no matter what, when I try to insert a null in that value, it fails. It says:
*Cause: A foreign key value has no matching primary key value.
*Action: Delete the foreign key or add a matching primary key.
Here is the code of the table. The FK that I want to be null is idPedido
CREATE TABLE PAGOS(
fechaLimite DATE,
cuantia NUMBER NOT NULL,
fechaInicio DATE DEFAULT SYSDATE,
fechaLiquidacion DATE,
idPago VARCHAR(8) NOT NULL,
dni VARCHAR(14) NOT NULL,
tipoPago VARCHAR(7) DEFAULT 'OTRO' CHECK(tipoPAGO IN('MENSUAL','PEDIDO','OTRO')),
idPedido VARCHAR2(10),
PRIMARY KEY(idPago),
FOREIGN KEY(dni) REFERENCES MIEMBROS ON DELETE SET NULL,
FOREIGN KEY(idPedido) REFERENCES PEDIDOS ON DELETE SET NULL
);
There are some triggers and such to add sequences for the idPago value.
Here is the code of the procedure that creates a new item to the table:
create or replace PROCEDURE CREAR_PAGO(
new_fechaLimite IN PAGOS.fechaLimite%TYPE ,
new_cuantia IN PAGOS.cuantia%TYPE,
new_fechaInicio IN PAGOS.fechaInicio%TYPE,
new_fechaLiquidacion IN PAGOS.fechaLiquidacion%TYPE,
new_dni IN PAGOS.dni%TYPE,
new_tipoPago IN PAGOS.tipoPago%TYPE,
new_idPedido IN PAGOS.idPedido%TYPE
)
IS
BEGIN
INSERT INTO PAGOS(fechaLimite,cuantia,fechaInicio,fechaLiquidacion,dni,tipoPago,idPedido) VALUES(new_fechaLimite,new_cuantia,new_fechaInicio,new_fechaLiquidacion,new_dni,new_tipoPago,new_idPedido);
END CREAR_PAGO;
And here is me trying to insert a new element:
execute CREAR_PAGO('01012020',40,'01012010',null,49035480D,null,null);
I've already tried to put both "NULL" and "DEFAULT NULL" in the table code after idPedido's type and nothing works
Please I need help
It looks like the primary key for your table is idPago, but I don't see it in your insert statement. If that is the case, it would appear that your issue is trying to add a record with no primary key...not that the foreign key is null.

Multiple constraints on a single column

I want to ensure that only the values 'Expert', 'Average' or 'Adequate' are entered into the levelOfExpertise column of this table, however whenever I do try an enter one of those values, it returns an error saying the value entered is too short. Here is the create table query for this particular table. The the column I am referring to is levelOfExpertise:
CREATE TABLE MusicianInstrument
(
musicianNo varchar(5) not null
CONSTRAINT MI_PK1 REFERENCES Musician(musicianNo),
instrumentName varchar(50) not null
CONSTRAINT MI_PK2 REFERENCES Instrument(instrumentName),
levelOfExpertise varchar(50),
CONSTRAINT levelOfExpertise CHECK (levelOfExpertise = 'Expert', 'Adequate', 'Avergage'),
PRIMARY KEY(musicianNo,instrumentName)
);
Any ideas how I can ensure only those three values (Expert, Adequate or Average) can be entered?
Thanks
Use the IN operator
CHECK (levelOfExpertise IN ('Expert','Adequate','Avergage'))
Try to change your CHECK constraint as following:
CONSTRAINT levelOfExpertise CHECK (levelOfExpertise IN ('Expert','Adequate','Avergage'))
I suppose that you use sql server as RDBMS.

Duplicate key error using nvarchar when adding new row with same number but leading 0

I want to insert a row into a table where in the primary key column I have a value of 3719. However, in the same table I want to add details with 03719 but I am getting an error:
The duplicate key value is (3719).
The datatype of that column is nvarchar.
I think your problem arises from the fact that you forgot to wrap the string value to be inserted in single quotes, so it is treated like a number, which is auto-converted to nvarchar.
INSERT INTO Table (Column) VALUES (03719)
is equivalent to
INSERT INTO Table (Column) VALUES (3719)
The value (because of the column type) is then converted to the string '3719'. Of course you then get a duplicate key error.
Check the quotes. If you're calling this from an application, use parameterized queries!
Correct statement to insert the records is like
Create table test (id nvarchar(25) primary key, name varchar(20))
insert into test values('111','hello')
insert into test values('0111','hello')
select * from test
You're forgetting to put the quotes.
If you do not put the quotes, you will get the below kind of error
Violation of PRIMARY KEY constraint 'PK__test__3213E83F2C904DEB'.
Cannot insert duplicate key in object 'dbo.test'. The duplicate key value is (111).