Is Identity Column hold the duplicate values? - sql-server

I have the table with the identity column. This is looks like identity column is duplicated. What are all the possibilities that column hold the duplicate values.
Table structure looks like below,
create table Table1(ID INT identity, value varchar(10))

if the column has no unique constraint, it is possible to get duplicate values in it.
One way to do this is like this
SET IDENTITY_INSERT Table1 ON
INSERT INTO Table1 (ID, value)
VALUES (1, 'hello')
SET IDENTITY_INSERT Table1 OFF
Another way is to reseed the table, check the answer of Satheesh on how to do that.
If you dont want that, make this column primary key or create an unique constraint on that column.
how to make a unique index :
CREATE UNIQUE NONCLUSTERED INDEX idx_Table1_ID
ON dbo.Table1(ID)
WHERE ID IS NOT NULL;
The WHERE ID IS NOT NULL; is needed in your example because you allow null values in the ID column, which I do not recommend
I am reasonably sure your table should look like this
Create table Table1 (
ID int identity not null,
Value varchar(10),
constraint PK_Table1_ID primary key (ID)
)

Of course and Identity Column can have Duplicate values.
But since the values are auto-populated by the Table itself, there is no chance that the Duplicates can be created by the system.
But you can add Duplicate values using the INSERT INTO Statement. or if you RESEED the identity column without removing the Existing values the system itself will create Duplicates.
because of The identity column in Not having a UNIQUE constraint by default.
see the below Example
CREATE TABLE Temp
(
SeqNo INT IDENTITY(1,1),
MyStr VARCHAR(10)
)
INSERT INTO Temp
VALUES('A')
Result
SeqNo MyStr
1 A
SET IDENTITY_INSERT TEMP ON
INSERT INTO TEMP(SeqNo,MyStr)
VALUES(1,'B')
SET IDENTITY_INSERT TEMP OFF
Result
SeqNo MyStr
1 A
1 B
Inserted Couple more records
INSERT INTO TEMP
VALUES('C')
INSERT INTO TEMP
VALUES('D')
Result
SeqNo MyStr
1 A
1 B
2 C
3 D
Perform identity Reseed and insert a New value
DBCC CHECKIDENT ('TEMP', RESEED, 1)
INSERT INTO TEMP
VALUES('E')
Final result
SeqNo MyStr
1 A
1 B
2 C
3 D
2 E

Related

SQL: How do I insert data from one table and output to a temporary table with extra value from first table

I can use the OUTPUT keyword of the insert statement to insert new data to a table and output to a temporary table.
The input table which to be inserted into another table have an Id I need to pass to the temporary table but not the table I going to insert into. This temporary table will later have to use to do extra insertion to the other table.
INSERT INTO table1 (Name, Age)
OUTPUT inserted.Id, User.Id (??) INTO TemporaryTable
SELECT Name, Age FROM User
Is there a way to do it? Because the next insertion will need the new table1.Id with the User.Id, so I can migrate some data.
Instead of using the Temporary table you can use Variable so that it will not occupy more memory.
create table table1
(
id int NOT NULL,
,name varchar(50)
,age int,
PRIMARY KEY (id)
)
insert into table1 (name,age) values ('name', 10)
declare #extracolumn as int = scope_identity()
select #extracolumn
use this #extracolumn in next insert operation.
Have you included the extra column in the schema of the temporary table?
create table table1
(
id int
,name varchar(50)
,age int
)
declare #TemporaryTable table -- or Create table #TemporaryTable
(
id int,
userid int -- defining the extra column
);
declare #extracolumn as int = 100;
-- or declare #extracolumn as int = (select value from table where condition)
-- note that subqueries cannot be added directly in the output clause
-- so need to declare and set a variable that holds the value
insert into table1
output inserted.id,#extracolumn into #TemporaryTable -- or #TemporaryTable
values(1,'name',10)
select * from #TemporaryTable
Output is
id userid
1 100

Throw error on invalid insertion in SQL Server

I have a SQL Server 2012 database with two tables:
CREATE TABLE Products
(
Id INT IDENTITY(1, 1) NOT NULL,
Code NVARCHAR(50) NOT NULL,
Name NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Product
PRIMARY KEY CLUSTERED (Id ASC)
);
CREATE TABLE BlockedProductCodes
(
Code NVARCHAR(50) NOT NULL,
ReasonCode INT NOT NULL
CONSTRAINT PK_BlockedProductCodes
PRIMARY KEY CLUSTERED (Code ASC)
);
I want to be able to prevent products being inserted into the Products table if their product code exists in the BlockedProductCodes table.
The only way I could think of doing this was with a BEFORE INSERT trigger:
CREATE TRIGGER trg_Products_BEFORE_INSERT
ON Products
INSTEAD OF INSERT AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT Code
FROM BlockedProductCodes BPC
INNER JOIN inserted I ON BPC.Code = I.Code)
BEGIN
RAISERROR('The product has been blocked!', 16, 1);
END
ELSE
BEGIN
INSERT Product (Id, Code, Name)
SELECT Id, Code, Name
FROM INSERTED
END
SET NOCOUNT OFF;
END
But this caused an error with the identity column:
Cannot insert explicit value for identity column in table 'Products' when IDENTITY_INSERT is set to OFF
Can anyone suggest a way to fix this or a better approach?
Please note, this check is also made at the application level, but I want enforce that at the data table level.
Thanks.
Update: using check constraint
I have tried the following that seems to work..
CREATE FUNCTION dbo.IsCodeBlocked
(
#code nvarchar(50)
)
RETURNS BIT
WITH SCHEMABINDING
AS
BEGIN
DECLARE #ret bit
IF (#Code IN (SELECT Code FROM dbo.BlockedProductCodes))
SET #ret = 1
ELSE
SET #ret = 0
RETURN #ret
END
GO
ALTER TABLE Products
ADD CONSTRAINT CheckValidCode
CHECK (dbo.IsCodeBlocked(Code) = 0);
GO
insert Products (Code, Name) values ('xyz', 'Test #1')
go
insert Products (Code, Name) values ('abc', 'Test #2')
-- Fails with "The INSERT statement conflicted with the
-- CHECK constraint 'CheckValidCode'."
go
I am not sure if it is particularly 'safe' or performant. I will also test out the indexed view approach suggested by Damien.
One way you can implement this is by abusing an indexed view:
CREATE TABLE dbo.Products (
Id INT IDENTITY (1, 1) NOT NULL,
Code NVARCHAR(50) NOT NULL,
Name NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Product PRIMARY KEY CLUSTERED (Id ASC)
);
GO
CREATE TABLE dbo.BlockedProductCodes (
Code NVARCHAR(50) NOT NULL,
ReasonCode INT NOT NULL
CONSTRAINT PK_BlockedProductCodes PRIMARY KEY CLUSTERED (Code ASC)
);
GO
CREATE TABLE dbo.Two (
N int not null,
constraint CK_Two_N CHECK (N > 0 and N < 3),
constraint PK_Two PRIMARY KEY (N)
)
GO
INSERT INTO dbo.Two(N) values (1),(2)
GO
create view dbo.DRI_NoBlockedCodes
with schemabinding
as
select
1 as Row
from
dbo.Products p
inner join
dbo.BlockedProductCodes bpc
on
p.Code = bpc.Code
inner join
dbo.Two t
on
1=1
GO
CREATE UNIQUE CLUSTERED INDEX IX_DRI_NoBlockedCodes on dbo.DRI_NoBlockedCodes (Row)
And now we attempt to insert:
INSERT INTO dbo.BlockedProductCodes (Code,ReasonCode) values ('abc',10)
GO
INSERT INTO dbo.Products (Code,Name) values ('abc','def')
And we get:
Msg 2601, Level 14, State 1, Line 42
Cannot insert duplicate key row in object 'dbo.DRI_NoBlockedCodes' with unique index 'IX_DRI_NoBlockedCodes'. The duplicate key value is (1).
The statement has been terminated.
So if that error message is acceptable to you, this could be one way to go. Note, that if you have a numbers table, you can use that instead of my dummy Two table.
The trick here is to construct the view in such a way so that, if there's ever a match between the Products and BlockedProductCodes tables, we produce a multi-row result set. But we've also ensured that all rows have a single constant column value and there's a unique index on the result - so the error is generated.
Note that I've used my convention of prefixing the table name with DRI_ when it exists solely to enforce an integrity constraint - I don't intend that anyone will ever query this view (indeed, as shown above, this view must always in fact be empty)

unique key on two columns commutatively

please suggest me how to apply unique key on two columns comparatively. i.e. suppose we have two columns FK_Col1 and FK_Col2 and if we insert 2 and 6 in both columns then we should not be able to insert again 2 and 6 or 6 and 2 in both columns.
Plaese suggest me how to achieve this.
Thanks in advance
Create a calculated column and a unique constraint on it. The trick is that we want the calculated column to have the same value for both (2),(6) and for (6),(2):
create table #t (a int, b int,
uq_col as (case when a>b then cast(a as varchar)+'|'+cast(b as varchar) else cast(b as varchar)+'|'+cast(a as varchar) end),
constraint uq_t__a_b unique(uq_col))
WHILE creating table
CREATE TABLE table1(
COLUMN1 INT NOT NULL,
COLUMN2 VARCHAR(50) NOT NULL,
CONSTRAINT unique_1 UNIQUE (column1, column2)
)
or
ALTER TABLE table1 ADD CONSTRAINT unique_1 UNIQUE(column1, column2)

Is there a way to retrieve inserted identity as well as some values from the query in an INSERT SELECT?

I have a situation in which I need to insert some values from a query into a table that has an identity PK. For some of the records, I need also to insert values in another table which has a 1-to-1 (partial) relationship:
CREATE TABLE A (
Id int identity primary key clustered,
Somevalue varchar(100),
SomeOtherValue int)
CREATE TABLE B (Id int primary key clustered,
SomeFlag bit)
DECLARE #inserted TABLE(NewId int, OldId)
INSERT INTO A (Somevalue)
OUTPUT Inserted.Id into #inserted(NewId)
SELECT SomeValue
FROM A
WHERE <certain condition>
INSERT INTO B (Id, SomeFlag)
SELECT
i.NewId, B.SomeFlag
FROM #inserted i
JOIN A ON <some condition>
JOIN B ON A.Id = B.Id
The problem is that the query from A in the first INSERT/SELECT returns records that can only be differentiated by the Id, which I cannot insert. Unfortunately I cannot change the structure of the A table, to insert the "previous" Id which would solve my problem.
Any idea that could lead to a solution?
With INSERT ... OUTPUT ... SELECT ... you can't output columns that are not in the target table. You can try MERGE instead:
MERGE INTO A as tgt
USING (SELECT Id, SomeValue FROM A WHERE <your conditions>) AS src
ON 0 = 1
WHEN NOT MATCHED THEN
INSERT (SomeValue)
VALUES (src.SomeValue)
OUTPUT (inserted.Id, src.Id) -- this is your new Id / old Id mapping
INTO #inserted
;
SCOPE_IDENTITY() returns the last identity value generated by the current session and current scope. You could stick that into a #table and use that to insert into B
SELECT SCOPE_IDENTITY() as newid into #c
Though, your INSERT INTO B join conditions implies to me that the value in B is already known ?

SQL Server Identity Column Insert Fails

Hi guys I just have one quick question:
what happens when an insert statement fails on an identity column?
Is it possible that say for example that if I insert a row with an identity column, that identity column will be 1, and insert again but that fails and does not insert and data. Then try to insert again and that identity for that row is now 3?
Any advice will be much appreciated.
Thanks.
It depends on what the cause of the fail on data insert is. If for example the values are invalid (wrong types), then the identity value won't be incremented. However, if the first insert is successful, but is then removed (by a transaction failed and rolled back), then the identity value IS incremented.
-- Next identity value = 1
INSERT INTO Table1 (
field1)
VALUES ('a')
-- Next identity value = 2
BEGIN TRAN
INSERT INTO Table1 (
field1)
VALUES ('b')
-- Next identity value = 3
ROLLBACK TRAN
-- Next identity value = 3, although the insertion was removed.
INSERT INTO Table1 (
field1)
VALUES ('c')
-- Next identity value = 4
The first insert will have identity column value = 1, the second one fails, and the third one will have identity column value = 3.
Just because a column has an IDENTITY specification doesn't necessarily mean it's unique.
If you don't have a unique constraint (or a primary key constraint) on that column, you can definitely insert multiple identical values into rows for that column.
Typically, though, your IDENTITY columns will be the primary key (or at least have a UNIQUE constraint on them) and in that case, attempting to insert a value that already exists will result in an error ("unique constraint violation" or something like that)
In order to be able to insert specific values into an IDENTITY column you need to have the SET IDENTITY_INSERT (table name) ON - otherwise, SQL Server will prevent you from even specifying values for an IDENTITY column.
For illustration - try this:
-- create demo table, fill with values
CREATE TABLE IdentityTest (ID INT IDENTITY, SomeValue CHAR(1))
INSERT INTO IdentityTest(SomeValue) VALUES('A'), ('B'), ('C')
SELECT * FROM IdentityTest -- Output (1)
-- insert duplicate explicit values into table
SET IDENTITY_INSERT IdentityTest ON
INSERT INTO IdentityTest(ID, SomeValue) VALUES(1, 'Z'), (2, 'Y')
SET IDENTITY_INSERT IdentityTest OFF
SELECT * FROM IdentityTest -- Output (2)
-- add unique constraint
TRUNCATE TABLE dbo.IdentityTest
ALTER TABLE IdentityTest ADD CONSTRAINT UX_ID UNIQUE(ID)
INSERT INTO IdentityTest(SomeValue) VALUES('A'), ('B'), ('C')
SET IDENTITY_INSERT IdentityTest ON
INSERT INTO IdentityTest(ID, SomeValue) VALUES(1, 'Z') -- error message (3)
DROP TABLE IdentityTest
Output (1):
ID SomeValue
1 A
2 B
3 C
Output (2):
ID SomeValue
1 A
2 B
3 C
1 Z
2 Y
Error Message (3):
Msg 2627, Level 14, State 1, Line 9
Violation of UNIQUE KEY constraint 'UX_ID'. Cannot insert duplicate key in object 'dbo.IdentityTest'. The duplicate key value is (1).
One way is to prevent the insert if the row already exists.
IF (Not Exists (Select ID From Table Where SomeCol = #SomeVal)
Insert Into Table Values (#SomeVal)

Resources