Why does violation of PRIMARY KEY constraint return error code 2627 not 2601 in SQL Server? - sql-server

I am confused for a while since the Document point out:
When you create a PRIMARY KEY constraint, a unique clustered index on
the column or columns is automatically created if a clustered index on
the table does not already exist and you do not specify a unique
nonclustered index. The primary key column cannot allow NULL values.
I have a table in SQL server with a PRIMARY KEY constraint. According to the above point,a unique clustered index on the column or columns is automatically created since i did't create any clustered in the table.
I learned 2601 Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls' from Database Engine Errors.
My question is that why SQL server return error code 2627 and not 2601 when I try to insert duplicate value in primary key column into my table which have a unique clustered index on primary key? Is it because 2627 has a higher priority than 2601 or what?
Can someone please give me some advice or help? Thanks.

A Primary Key, at least on SQL Server, is a type of Constraint. As a result when you create a Primary Key it is both a (unique) Index and a Constraint. Both error 2627 and 2601 have the same severity, so it appears that SQL Server will return the higher error code (as both a unique index and constraint were violated).
From testing, you'll only get the error 2601 is the column has a unique index that is violated, but does not have a constraint. Most likely, therefore, you'll see this on a conditional unique index.
Take the below examples:
USE Sandbox;
GO
--First sample table with primary key (Clustered)
CREATE TABLE dbo.TestTable1 (ID int PRIMARY KEY);
GO
--inserts fine
INSERT INTO dbo.TestTable1
VALUES(1);
GO
--Errors with code 2627
INSERT INTO dbo.TestTable1
VALUES(1);
GO
--Create second sample table, with unique Constraint
CREATE TABLE dbo.TestTable2(ID int,
CONSTRAINT U_ID UNIQUE(ID));
GO
--Inserts fine
INSERT INTO dbo.TestTable2
VALUES(1);
GO
--Errors with code 2627
INSERT INTO dbo.TestTable2
VALUES(1);
GO
--Create third sample table
CREATE TABLE dbo.TestTable3(ID int);
--Create unique index, without Constraint
CREATE UNIQUE INDEX ID_UX ON dbo.TestTable3(ID);
GO
--Inserts fine
INSERT INTO dbo.TestTable3
VALUES(1);
GO
--Errors with code 2601
INSERT INTO dbo.TestTable3
VALUES(1);
GO
--Clean up
DROP TABLE dbo.TestTable1
DROP TABLE dbo.TestTable2
DROP TABLE dbo.TestTable3
Note that only the last insert fails with error 2601; the other 2 fail with 2627.

Related

Snowflake Primary key using alter statement

when I was adding primary key to snowflake table I saw something weird.
When I ran a query
ALTER TABLE "TESTSCHEMA".table1 ADD PRIMARY KEY (ID);
Above query works as expected. But when I tried to run
ALTER TABLE IF EXISTS "TESTSCHEMA".table1 ADD PRIMARY KEY (ID);
Query was returning error error line 0 at position 0 invalid identifier 'TOK_IF_EXISTS'
Is this a bug or Am I doing something wrong?
Adding a primary key to the same column is expected to result in an error as provided below.
create table "TESTSCHEMA".table (id number);
--Statement executed successfully.
ALTER TABLE "TESTSCHEMA".table ADD PRIMARY KEY (ID);
--Statement executed successfully.
ALTER TABLE "TESTSCHEMA".table ADD PRIMARY KEY (ID);
--SQL compilation error: primary key already exists for table 'TABLE'
create table "TESTSCHEMA"."table1" (id number);
--Statement executed successfully.
ALTER TABLE "TESTSCHEMA"."table1" ADD PRIMARY KEY (ID);
--Statement executed successfully.
ALTER TABLE "TESTSCHEMA"."table1" ADD PRIMARY KEY (ID);
---SQL compilation error: primary key already exists for table 'table1'
The test case shared by you with the error details can be reported to Snowflake for validation
According to docs, it looks like a bug. Could you raise snowflake support case so that the behaviour can be validated? Thanks,
https://docs.snowflake.com/en/sql-reference/sql/alter-table.html

filetable inserted duplicate key for "stream_id" column

I have a stored-procedure which will save a file into a filetable table:
DECLARE #table1 TABLE (id NVARCHAR(50))
INSERT INTO FileTable1(file_stream,name,path_locator) OUTPUT inserted.stream_id INTO #table1 VALUES(#File,#FName,#SubDirectoryPath)
The problem is, SOME TIMES stored procedure raises insert duplicate key error and i don't know why.
ERROR MESSAGE:
Violation of UNIQUE KEY constraint ''UQ__FileTabl__A236CBB318510CF4''. Cannot insert duplicate key in object ''dbo.FileTable1''. The duplicate key value is...
-----------------EDIT---------------------
I know what Duplicate key means, But i'm wondering that: should stream-id automatically inserted by sql server according to the following table structure?
CREATE TABLE [dbo].[FileTable1] AS FILETABLE ON [PRIMARY] FILESTREAM_ON [FSDataGroup]
WITH
(
FILETABLE_DIRECTORY = N'FileTable1', FILETABLE_COLLATE_FILENAME = Arabic_CI_AS
)
Can you please check your UNIQUE KEY constraint on the table columns. It seems you are trying to insert same value to unique key column.
do you have identity in your column stream_id.

SQL Server - Adding foreign key to a table

As in my previous post (linked here) I have been designing a table and I'm trying to insert only some specific values into the BrothersName column which can be done by adding a constraint.
TABLE Family
(
BrothersName varchar(30)
);
However my question now is that I'm trying to do this instead by foreign key. Is the only way to do it is by making a new table and add primary key into it?
What can be the best way otherwise?
So you should have a primary key table to hold all possible master data set for brother names like below
create table MasterBrotherNames (ID int IDENTITY(1,1) PRIMARY KEY, Name nvarchar(30)) ;
insert into MasterBrotherNames(Name) values (N'Alex'),(N'Tom');
Now you should hold foreign key ID into the Family table as int, say in column BrothersNameID using following query to create FK relationship
create table Family( BrothersNameID int NOT NULL);
alter table Family add constraint fk_family_brothername foreign key ( BrothersNameID ) references MasterBrotherNames (ID);
To test out try queries below
insert into Family values (1)-- for Alex
insert into Family values (2)-- for Tom
insert into Family values (3)-- this gives error
--The INSERT statement conflicted with the FOREIGN KEY constraint "fk_family_brothername".
Based on OP's following request
is there any way to implement this without having any Id in MasterBrothersName, where only names can be inserted and accepted as values
here's the modified query
create table MasterBrotherNames ( Name nvarchar(30) PRIMARY KEY) ;
insert into MasterBrotherNames(Name) values (N'Alex'),(N'Tom');
create table Family( BrothersName nvarchar(30) NOT NULL);
alter table Family add constraint fk_family_brothername foreign key ( BrothersName ) references MasterBrotherNames (Name);
insert into Family values (N'Alex')-- for Alex
insert into Family values (N'Tom')-- for Tom
insert into Family values (N'A')-- this gives error
--The INSERT statement conflicted with the FOREIGN KEY constraint "fk_family_brothername".

SQL Server 2008 Insert fails reporting

I have unique constraints on both Username and Nickname fields. When I run the following code with a duplicate Nickname then SQL Server 2008 reports Err 23000 Violation of Unique Key constraint. But when I run it with a duplicate Username no Error is thrown (though the Message "Affected Rows: 0" results and no changes are effected to the table).
I don't understand why this should be or how to deal with this (I want an error thrown in either instance). Thanks in advance.
INSERT INTO Members (UserName, Nickname)
VALUES ('bob', 'bob55')
CREATE TABLE [Members].[Members] (
[GUID] uniqueidentifier NOT NULL DEFAULT (newsequentialid()) ,
[UserName] nvarchar(256) NOT NULL ,
[NickName] nvarchar(256) NOT NULL ,
)
-- ----------------------------
-- Indexes structure for table Members
-- ----------------------------
CREATE UNIQUE INDEX [Index:UserName] ON [Members].[Members]
([UserName] ASC)
WITH (IGNORE_DUP_KEY = ON)
GO
-- ----------------------------
-- Primary Key structure for table Members
-- ----------------------------
ALTER TABLE [Members].[Members] ADD PRIMARY KEY ([GUID])
GO
-- ----------------------------
-- Uniques structure for table Members
-- ----------------------------
ALTER TABLE [Members].[Members] ADD UNIQUE ([NickName] ASC)
GO
ALTER TABLE [Members].[Members] ADD UNIQUE ([UserName] ASC)
GO
There are two ways to make field unique in SQL Server:
unique constraint
unique index
When you create an unique index, you can set a database behavior in case of trying to insert duplicate value:
WITH (IGNORE_DUP_KEY = ON) - do nothing, just ignore new record with duplicate value
WITH (IGNORE_DUP_KEY = OFF) - throw an exception
When you create an unique constraint, SQL Server in implicit way creates an unique index WITH (IGNORE_DUP_KEY = OFF)
In your question you create 3 unique indexes: one explicit on the column UserName, and two impicit on both NickName and UserName fields. When you try to insert a record with duplicate UserName, the inserting stops on unique index violation and SQL Server ignores the record. There is no work for an unique constraint. But when you try to insert a record with duplicate NickName, an unique constraint generates an error.
If you want to get errors for both fields in same manner, just drop the unique index:
DROP INDEX [Index:UserName] ON [Members].[Members]

Add primary key column in SQL table

I am student of RDBMS.
I have very basic question let say I have one existing Table in SQL server. What will be script to alter table.
Drop Column 'RowId' if exist.
Drop contraint if exist.
Add one new column 'RowId' into table.
Make this column as primary key.
Autoincrement type int.
In SQL Server 2005 or newer, you could use this script:
-- drop PK constraint if it exists
IF EXISTS (SELECT * FROM sys.key_constraints WHERE type = 'PK' AND parent_object_id = OBJECT_ID('dbo.YourTable') AND Name = 'PK_YourTable')
ALTER TABLE dbo.YourTable
DROP CONSTRAINT PK_YourTable
GO
-- drop column if it already exists
IF EXISTS (SELECT * FROM sys.columns WHERE Name = 'RowId' AND object_id = OBJECT_ID('dbo.YourTable'))
ALTER TABLE dbo.YourTable DROP COLUMN RowId
GO
-- add new "RowId" column, make it IDENTITY (= auto-incrementing)
ALTER TABLE dbo.YourTable
ADD RowId INT IDENTITY(1,1)
GO
-- add new primary key constraint on new column
ALTER TABLE dbo.YourTable
ADD CONSTRAINT PK_YourTable
PRIMARY KEY CLUSTERED (RowId)
GO
Of course, this script may still fail, if other tables are referencing this dbo.YourTable using foreign key constraints onto the pre-existing RowId column...
Update: and of course, anywhere I use dbo.YourTable or PK_YourTable, you have to replace those placeholder with the actual table / constraint names from your own database (you didn't mention what they were, in your question.....)
Note: this answer was added before questions update
Add new column (note: you can only have one IDENTITY column per table)
Drop old primary key
Add new primary key
Drop old column if needed
Sample script:
CREATE TABLE whatever (
OldPKColumn uniqueidentifier NOT NULL,
CONSTRAINT PK_whatever PRIMARY KEY (OldPKColumn)
)
ALTER TABLE whatever
ADD RowId int NOT NULL IDENTITY (1,1);
ALTER TABLE whatever
DROP CONSTRAINT PK_whatever;
ALTER TABLE whatever WITH CHECK
ADD CONSTRAINT PK_whatever PRIMARY KEY CLUSTERED (RowId);
ALTER TABLE whatever
DROP COLUMN oldPKcolumn;
And a random thought... are you trying to reset an IDENTITY column?
If so, then use DBCC CHECKIDENT
Just a comment to improve these great answers (can't use comments yet - I'm one reputation point away from that privilege) and as future reference for myself:
A new IDENTITY (autonumber) column can be added and made the primary key in a single statement as well:
ALTER TABLE [TableName] ADD [ColumnName] int IDENTITY PRIMARY KEY;
I prefer not to bother with constraint names when it doesn't help.
You can specify seed (and increment) values between parantheses after the IDENTITY keyword.

Resources