Zero As Primary Key In SQL Server 2008 - sql

Is it possible to insert 0 in the primary key field of a table in SQL server 2008?

As long it's a numeric field, yes... follow along at home!
create table TestTable
(
TestColumn int not null primary key
)
insert TestTable values(0)
The primary key restriction only requires that the value be unique and the column not be nullable.
For an identity field:
create table TestTable
(
TestColumn int identity(1, 1) not null primary key --start at 1
)
set identity_insert TestTable on
insert TestTable (TestColumn) values (0) --explicitly insert 0
set identity_insert TestTable off
The identity(1, 1) means "start at one and increment by one each time something is inserted". You could have identity(-100, 10) to start at -100 and increment by 10 each time. Or you could start at 0. There's no restriction.
You can generally answer questions like these for yourself by just trying them and seeing if they work. This is faster and usually more beneficial than asking on StackOverflow.

Yes, it can be zero. The value can be from −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 − 1, the full range of an unsigned integer.
If you expect a lot of records, like up to 4.3 billion, it makes sense to start from the smallest value, and work your way up.
CREATE TABLE TestTable
(
TestColumn INT IDENTITY(−2,147,483,648, 1) NOT NULL PRIMARY KEY --start at 1
)

Related

What happens when Identity seed reaches an existent value in a primary key?

I have an identity column that is also the primary key, of INT datatype. Due to the issue discussed here (cache loss), the identity has gaps and I chose to reseed to the previous value. In concrete terms, I have a situation that looks like this:
Table1
ID_PK Field1
---------------
28 'd'
29 'e'
30 'h'
1029 'f'
1030 'g'
I looked around and couldn't find a clear answer to what happens when I make an insertion and the seed reaches the existent value that would break the constraint. Suppose I were to insert values 'x' and 'y' in two separated queries to the table, I can think of the following possibilities:
The identity will be reseeded before the first insertion and I will have both values inserted correctly.
The first insertion will fail, then the column will be reseeded, and only then the second insertion would succeed.
Neither will work and I will have to explicitly call DBCC CHECKIDENT to reseed before inserting values in the table
So, which is it? Or none of the above? Would this behavior be different if I inserted a multi-row result query into Table1? Thanks in advance
For completeness anyway, here's a script you can use to test:
USE Sandbox;
GO
CREATE TABLE test(ID int IDENTITY(1,1) PRIMARY KEY CLUSTERED, string char(1));
GO
INSERT INTO test (string)
VALUES ('a'),('b'),('c'),('d');
GO
SELECT *
FROM test;
GO
DELETE FROM test
WHERE string IN ('b','c');
GO
SELECT *
FROM test;
GO
DBCC CHECKIDENT ('dbo.test', RESEED, 1);
GO
INSERT INTO test (string)
VALUES ('e'),('f');
GO
SELECT *
FROM test;
GO
INSERT INTO test (string)
VALUES ('g');
GO
SELECT *
FROM test;
GO
DROP TABLE test;
Running this script will give you the answer you need. If you wonder why I have used 1 as the RESEED value, this is explained in the documentation:
The following example forces the current identity value in the
AddressTypeID column in the AddressType table to a value of 10.
Because the table has existing rows, the next row inserted will use 11
as the value, that is, the new current increment value defined for the
column value plus 1.
In my script, this means that the next row to be inserted after the RESEED will have a value of 2 for its IDENTITY, not 1 (as rows already existing in the table (ID's 1 and 4)).
As several have said in the comments though, there's really no need to use RESEED on an IDENTITY column. If you need to maintain a sequence, you should (unsurprisingly) be using a SEQUENCE: CREATE SEQUENCE (Transact-SQL)
It depends:
Scenario 1
You get duplicates in the IDENTITY column, as no unique index or PK constraint.
create table I (
id int identity(1,1) not null,
i int null
)
Scenario 2
You get the following error as the inserted value conflicts with the Primary Key constraint:
Msg 2627, Level 14, State 1, Line 1 Violation of PRIMARY KEY
constraint 'PK__I__3213E83FE0B0E009'. Cannot insert duplicate key in
object 'dbo.I'. The duplicate key value is (11). The statement has
been terminated.
create table I (
id int identity(1,1) not null primary key,
i int null
)
This proves that IDENTITY on it's own does not guarantee uniqueness, only a UNIQUE CONSTRAINT does that.
To close, turns out it's (2).
First insertion fails, reseed is automatic to the highest value, and only next insertion suceeds. Multi-value insertions behave the same if any of the values would break the primary key constraint.

Two identity columns in SQL Server 2008

I am creating a table in SQL Server with three columns. I want the first two columns to increment counts one by one. I used the first column as identity column that automatically increments 1 when row is inserted. I tried to do the same with second column (but SQL Server does not allow two identity columns per table). I found another way i-e using Sequence but since I am using SQL Server 2008, it does not have this feature.
How can I achieve my task?
I am using the first identity column in reports and I reset it when some count is achieved; for example when it reaches 20, I reset it to 1 (Edited). The second incremental column will be used by me for sorting the data and i do not intend to reset it.
create table tblPersons
(
IDCol int primary key identity(1,1),
SortCol int primary key identity(1,1),
Name nvarchar(50)
)
PS : I cannot copy the values of IDCol to SortCol because when I reset the IDCol to 20 from my code, the SortCol will copy the same values (instead it should continue to 21,22,23 and so on)
If you plan on incrementing both columns always at the same time, then one workaround here might be to just use a single auto increment column, but use the remainder of that counter divided by 20 for the second value:
CREATE TABLE tblPersons (
IDCol int PRIMARY KEY IDENTITY(1,1),
Name nvarchar(50)
)
SELECT
IDCol,
IDCol % 20 AS SortCol -- this "resets" to zero upon reaching 20
FROM tblPersons;
As an alternative solution, you can use Computed Column
create table tblPersons
(
SortCol int primary key identity(1,1),
IDCol AS CASE WHEN (SortCol % 20) = 0 THEN 20 ELSE (SortCol % 20) END ,
Name nvarchar(50)
)

Set IDENTITY to begin with Alphabets

I have created a table and set its PK to IDENTITY(1,1).
But I want the PK to begin/start with alphabets e.g CRMSON0, CRMSON1, CRMSON2... and so on.
But I wasn't able to find the solution for Microsoft SQL Server.
on Microsoft website, details I could find were about IDENTITY(seed,increment) or IDENTITY(data type,seed,increment).
Can anyone suggest?
You can create computed column composed from CRMSON + ID value:
CREATE TABLE #table1 (ID INT IDENTITY(0,1)
,col INT
,col_pk AS CONCAT('CRMSON', ID) PRIMARY KEY);
INSERT INTO #table1(col) VALUES(3), (4);
SELECT *
FROM #table1;
LiveDemo
The best solution is to use
an ID INT IDENTITY(1,1) column to get SQL Server to handle the automatic increment of your numeric value
a computed, persisted column to convert that numeric value to the value you need
So try this:
CREATE TABLE dbo.YourTable
(ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
CrimsonID AS 'CRIMSON' + CAST(ID AS VARCHAR(10) PERSISTED,
.... your other columns here....
)
Now, every time you insert a row into YourTable without specifying values for ID or CrimsonID:
INSERT INTO dbo.YourTable(Col1, Col2, ..., ColN)
VALUES (Val1, Val2, ....., ValN)
then SQL Server will automatically and safely increase your ID value, and CrimsonID will contain values like Crimson1, Crimson2,...... and so on - automatically, safely, reliably, no duplicates.
That'll work fine - but as others have already pointed out - I would NOT recommend using this column as the clustered, primary key - use the ID column for that, it's ideally suited for such a task! The CrimsonID is bad for mainly two reasons: it's a variable length string, and it's much too wide compared to an int

Unique constraint on two fields, and their opposite

I have a data structure, where I have to store pairs of elements. Each pair has exactly 2 values in it, so we are employing a table, with the fields(leftvalue, rightvalue....).
These pairs should be unique, and they are considered the same, if the keys are changed.
Example: (Fruit, Apple) is the same as (Apple, Fruit).
If it is possible in an efficient way, I would put a database constraint on the fields, but not at any cost - performance is more important.
We are using MSSQL server 2008 currently, but an update is possible.
Is there an efficient way of achieving this?
Two solutions, both really about changing the problem into an easier one. I'd usually prefer the T1 solution if forcing a change on consumers is acceptable:
create table dbo.T1 (
Lft int not null,
Rgt int not null,
constraint CK_T1 CHECK (Lft < Rgt),
constraint UQ_T1 UNIQUE (Lft,Rgt)
)
go
create table dbo.T2 (
Lft int not null,
Rgt int not null
)
go
create view dbo.T2_DRI
with schemabinding
as
select
CASE WHEN Lft<Rgt THEN Lft ELSE Rgt END as Lft,
CASE WHEN Lft<Rgt THEN Rgt ELSE Lft END as Rgt
from dbo.T2
go
create unique clustered index IX_T2_DRI on dbo.T2_DRI(Lft,Rgt)
go
In both cases, neither T1 nor T2 can contain duplicate values in the Lft,Rgt pairs.
If you always store the values in order but store the direction in another column,
CREATE TABLE [Pairs]
(
[A] NVarChar(MAX) NOT NULL,
[B] NVarChar(MAX) NOT NULL,
[DirectionAB] Bit NOT NULL,
CONSTRAINT [PK_Pairs] PRIMARY KEY ([A],[B])
)
You can acheive exaclty what you want with one clustered index, and optimize your lookups too.
So when I insert the pair 'Apple', 'Fruit' I'd do,
INSERT [Pairs] VALUES ('Apple', 'Friut', 1);
Nice and easy. Then I insert 'Fruit', 'Apple',
INSERT [Pairs] VALUES ('Apple', 'Fruit', 0); -- 0 becuase order is reversed.
The insert fails because this is a primary key violation. To further illustrate, the pair 'Coconuts', 'Bananas' would be stored as
INSERT [Pairs] VALUES ('Bananas', 'Coconuts', 0);
For additional lookup performance, I'd add the index
CREATE NONCLUSTERED INDEX [IX_Pairs_Reverse] ON [Pairs] ([B], [A]);
If you can't control inserts to the table, it may be necessary to ensure that [A] and [B] are inserted correctly.
CONSTRAINT [CK_Pairs_ALessThanB] CHECK ([A] < [B])
But this may be an unnecessary performance hit, depending on how controlled your inserts are.
One way would be to create a computed column that combines the two values and put a unique constraint upon it:
create table #test (
a varchar(10) not null,
b varchar(10) not null,
both as case when a > b then a + ':' + b else b + ':' + a end persisted unique nonclustered
)
so
insert #test
select 'apple', 'fruit'
insert #test
select 'fruit', 'apple'
Gives
(1 row(s) affected)
Msg 2627, Level 14, State 1, Line 3
Violation of UNIQUE KEY constraint 'UQ__#test_____55252CB631EC6D26'. Cannot insert duplicate key in object 'dbo.#test'.
The statement has been terminated.
Unique constraint on two/more fields is possible but on their opposite no...
SQL Server 2005 Unique constraint on two columns
Unique constraint on multiple columns
How do I apply unique constraint on two columns SQL Server?
http://www.w3schools.com/sql/sql_unique.asp

SQL Server Database unique number generation on any record insertion

I have like 11 columns in my database table and i am inserting data in 10 of them. i want to have a unique number like "1101 and so on" in the 11th column.
Any idea what should i do?? Thanks in advance.
SQL Server 2012 and above you can generate Sequence
Create SEQUENCE RandomSeq
start with 1001
increment by 1
Go
Insert into YourTable(Id,col1...)
Select NEXT VALUE FOR RandomSeq,col1....
or else you can use Identity
Identity(seed,increment)
You can start the seed from 1101 and increment the sequence by 1
Create table YourTable
(
id INT IDENTITY(1101,1),
Col varchar(10)
)
If you want to have that unique number in a different field then you can manipulate that field with primary key and insert that value.
If you want in primary key value, then open the table in design mode, go to 'Identity specification', set 'identity increment' and 'identity seed' as you want.
Alternatively you can use table script like,
CREATE TABLE Persons
(
ID int IDENTITY(12,1) PRIMARY KEY,
FName varchar(255) NOT NULL,
)
here the primary key will start seeding from 12 and seed value will be 1.
If you have your table definition already in place you can alter the column and add Computed column marked as persisted as:
ALTER TABLE tablename drop column column11;
ALTER TABLE tablename add column11 as '11'
+right('000000'+cast(ID as varchar(10)), 2) PERSISTED ;
--You can change the right operator value from 2 to any as per the requirements.
--Also replace ID with the identity column in your table.
create table inc
(
id int identity(1100,1),
somec char
)