Pages

Wednesday, 28 October 2015

Identity

IDENTITY:
It creates an identity column in a table. This property is used with the CREATE TABLE and ALTER TABLE Transact-SQL statements.

Syntax
IDENTITY [ ( seed , increment) ]

Arguments
Seed
Is the value that is used for the very first row loaded into the table.
Initial seed and increment can be any integer value

Increment
Is the incremental value that is added to the identity value of the previous row that was loaded.
You must specify both the seed and increment or neither. If neither is specified, the default is (1,1).

Remarks
If an identity column exists for a table with frequent deletions, gaps can occur between identity values. If this is a concern, do not use the IDENTITY property. However, to ensure that no gaps have been created or to fill an existing gap, evaluate the existing identity values before explicitly entering one with SET IDENTITY_INSERT ON.

Use DBCC CHECKIDENT to check the current identity value and compare it with the maximum value in the identity column.

When the IDENTITY property is used with CREATE TABLE, Microsoft® SQL Server™ uses the NOT FOR REPLICATION option of CREATE TABLE to override the automatic incrementing of an identity column. Usually, SQL Server assigns each new row inserted in a table a value that is some increment greater than the previous highest value. However, if the new rows are replicated from another data source, the identity values must remain exactly as they were at the data source.

Identity Data types :
The identity must only contain integer values but the column can be of any numeric datatype (bigint, int, tinyint, numeric, decimal). But, we need to make sure identity column are not reaching the limit of their base data type.

An IDENTITY column of tinyint data type can go up to 255.
Smallint can go up to 32767
Int can go up to 2147483647 and
Bigint can go up to 9223372036854775807.

Example :
If you created an IDENTITY column of smallint datatype, its values can go upto 32767.
If you try to insert anymore rows, you will get the following error:

Arithmetic overflow error converting IDENTITY to data type smallint.

So, We need to monitor these IDENTITY columns, to avoid getting into such problems. If you can see in advance, that an IDENTITY column is reaching its limit, then we could do something about it, before it reaches the limit.


IDENT_SEED
Returns the seed value (returned as numeric (@@MAXPRECISION,0)) specified during the creation of an identity column in a table or a view that has an identity column.

Syntax
IDENT_SEED ('table_or_view' )

Arguments
'table_or_view'
Is an expression specifying the table or view to check for a valid identity seed value.  table_or_view can be a character string constant enclosed in quotation marks, a variable, a function, or a column name.  table_or_view is char, nchar, varchar, or nvarchar.

Return Types
Numeric

Examples
This example returns 1 for the jobs table in the pubs database because the jobs table includes an identity column with a seed value of 1.

USE pubs
SELECT TABLE_NAME, IDENT_SEED (TABLE_NAME) AS IDENT_SEED
FROM INFORMATION_SCHEMA.TABLES
WHERE IDENT_SEED (TABLE_NAME) IS NOT NULL

Here is the result set:
TABLE_NAME                                                   IDENT_SEED 
------------------------------------------------------------ -----------
jobs                                                                           1          




IDENT_INCR
Returns the increment value (returned as numeric (@@MAXPRECISION,0)) specified during the creation of an identity column in a table or view that has an identity column.

Syntax
IDENT_INCR ( 'table_or_view' )

Arguments
'table_or_view'
Is an expression specifying the table or view to check for a valid identity increment value. table_or_view can be a character string constant enclosed in quotation marks, a variable, a function, or a column name. table_or_view is char, nchar, varchar, or nvarchar.

Return Types
Numeric

Examples
This example returns 1 for the jobs table in the pubs database because the jobs table includes an identity column with an increment value of 1.

USE pubs
SELECT TABLE_NAME, IDENT_INCR (TABLE_NAME) AS IDENT_INCR
FROM INFORMATION_SCHEMA.TABLES
WHERE IDENT_INCR (TABLE_NAME) IS NOT NULL

Here is the result set:
TABLE_NAME                                                  IDENT_INCR  
------------------------------------------------------------ -----------
jobs                                                         1          




SET IDENTITY_INSERT
Allows explicit values to be inserted into the identity column of a table.

Syntax
SET IDENTITY_INSERT [ database. [ owner. ] ] { table } { ON | OFF }

Arguments
database
Is the name of the database in which the specified table resides.
owner
Is the name of the table owner.
table
Is the name of a table with an identity column.

Remarks
At any time, only one table in a session can have the IDENTITY_INSERT property set to ON. If a table already has this property set to ON, and a SET IDENTITY_INSERT ON statement is issued for another table, Microsoft® SQL Server™ returns an error message that states SET IDENTITY_INSERT is already ON and reports the table it is set ON for.
If the value inserted is larger than the current identity value for the table, SQL Server automatically uses the new inserted value as the current identity value.

The setting of SET IDENTITY_INSERT is set at execute or run time and not at parse time.

Permissions
Execute permissions default to the sysadmin fixed server role, and the db_owner and db_ddladmin fixed database roles, and the object owner.



@@IDENTITY
Returns the last-inserted identity value.

Syntax
@@IDENTITY
Return Types
Numeric
Remarks
After an INSERT, SELECT INTO, or bulk copy statement completes, @@IDENTITY contains the last identity value generated by the statement. If the statement did not affect any tables with identity columns, @@IDENTITY returns NULL. If multiple rows are inserted, generating multiple identity values, @@IDENTITY returns the last identity value generated.

If the statement fires one or more triggers that perform inserts that generate identity values, calling @@IDENTITY immediately after the statement returns the last identity value generated by the triggers. If a trigger is fired after an insert action on a table that has an identity column, and the trigger inserts into another table that does not have an identity column, @@IDENTITY will return the identity value of the first insert.

The @@IDENTITY value does not revert to a previous setting if the INSERT or SELECT INTO statement or bulk copy fails, or if the transaction is rolled back.

@@IDENTITY, SCOPE_IDENTITY, and IDENT_CURRENT are similar functions in that they return the last value inserted into the IDENTITY column of a table.

@@IDENTITY and SCOPE_IDENTITY will return the last identity value generated in any table in the current session. However, SCOPE_IDENTITY returns the value only within the current scope; @@IDENTITY is not limited to a specific scope.

IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope. For more information, see IDENT_CURRENT.

The scope of the @@IDENTITY function is the local server on which it is executed. This function cannot be applied to remote or linked servers. To obtain an identity value on a different server, execute a stored procedure on that remote or linked server and have that stored procedure, which is executing in the context of the remote or linked server, gather the identity value and return it to the calling connection on the local server.

SCOPE_IDENTITY (Transact-SQL)
Applies To: SQL Server 2014, SQL Server 2016 Preview
Returns the last identity value inserted into an identity column in the same scope.
A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
SCOPE_IDENTITY()
Numeric (38,0)
SCOPE_IDENTITY, IDENT_CURRENT, and @@IDENTITY are similar functions because they return values that are inserted into identity columns.
IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the value generated for a specific table in any session and any scope.

SCOPE_IDENTITY and @@IDENTITY return the last identity values that are generated in any table in the current session. However, SCOPE_IDENTITY returns values inserted only within the current scope; @@IDENTITY is not limited to a specific scope.

For example, there are two tables, T1 and T2, and an INSERT trigger is defined on T1. When a row is inserted to T1, the trigger fires and inserts a row in T2. This scenario illustrates two scopes: the insert on T1, and the insert on T2 by the trigger.
USE tempdb;
GO
CREATE TABLE TZ (
   Z_id  int IDENTITY(1,1)PRIMARY KEY,
   Z_name varchar(20) NOT NULL);

INSERT TZ
   VALUES ('Lisa'),('Mike'),('Carla');


CREATE TABLE TY (
   Y_id  int IDENTITY(100,5)PRIMARY KEY,
   Y_name varchar(20) NULL);

INSERT TY (Y_name)
   VALUES ('boathouse'), ('rocks'), ('elevator');

/*Create the trigger that inserts a row in table TY
when a row is inserted in table TZ.*/
CREATE TRIGGER Ztrig
ON TZ
FOR INSERT AS
   BEGIN
   INSERT TY VALUES ('')
   END;


/*FIRE the trigger and determine what identity values you obtain
with the @@IDENTITY and SCOPE_IDENTITY functions.*/
INSERT TZ VALUES ('Rosalie');

SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];
GO

SELECT @@IDENTITY AS [@@IDENTITY];
GO

Assuming that both T1 and T2 have identity columns, @@IDENTITY and SCOPE_IDENTITY will return different values at the end of an INSERT statement on T1. @@IDENTITY will return the last identity column value inserted across any scope in the current session. This is the value inserted in T2. SCOPE_IDENTITY() will return the IDENTITY value inserted in T1. This was the last insert that occurred in the same scope.

The SCOPE_IDENTITY () function will return the null value if the function is invoked before any INSERT statements into an identity column occur in the scope.
Failed statements and transactions can change the current identity for a table and create gaps in the identity column values. The identity value is never rolled back even though the transaction that tried to insert the value into the table is not committed. For example, if an INSERT statement fails because of an IGNORE_DUP_KEY violation, the current identity value for the table is still incremented.



IDENT_CURRENT (Transact-SQL)
Applies To: SQL Server 2014, SQL Server 2016 Preview
Returns the last identity value generated for a specified table or view. The last identity value generated can be for any session and any scope.
IDENT_CURRENT (‘table_name’)
table_name
Is the name of the table whose identity value is returned. table_name is varchar, with no default.
Numeric (38,0)
Returns NULL on error or if a caller does not have permission to view the object.
In SQL Server, a user can only view the metadata of securables that the user owns or on which the user has been granted permission. This means that metadata-emitting, built-in functions such as IDENT_CURRENT may return NULL if the user does not have any permission on the object. For more information, see Metadata Visibility Configuration.
IDENT_CURRENT is similar to the SQL Server 2000 identity functions SCOPE_IDENTITY and @@IDENTITY. All three functions return last-generated identity values. However, the scope and session on which last is defined in each of these functions differ:
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.

@@IDENTITY returns the last identity value generated for any table in the current session, across all scopes.

SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.

When the IDENT_CURRENT value is NULL (because the table has never contained rows or has been truncated), the IDENT_CURRENT function returns the seed value.
Failed statements and transactions can change the current identity for a table and create gaps in the identity column values. The identity value is never rolled back even though the transaction that tried to insert the value into the table is not committed. For example, if an INSERT statement fails because of an IGNORE_DUP_KEY violation, the current identity value for the table is still incremented.

Be cautious about using IDENT_CURRENT to predict the next generated identity value. The actual generated value may be different from IDENT_CURRENT plus IDENT_INCR because of insertions performed by other sessions.



DBCC CHECKIDENT:
Checks the current identity value for the specified table and, if it is needed, changes the identity value. You can also use DBCC CHECKIDENT to manually set a new current identity value for the identity column.
Syntax:
                DBCC CHECKIDENT
(
    table_name
        [ , { NORESEED | { RESEED [ ,new_reseed_value ] } } ]
)
[ WITH NO_INFOMSGS ]

table_name
Is the name of the table for which to check the current identity value.
The table specified must contain an identity column.
Table names must comply with the rules for identifiers.

noreseed
Specifies that the current identity value should not be changed.

reseed
Specifies that the current identity value should be changed.

new_reseed_value
Is the new value to use as the current value of the identity column.

With no_infomsgs
Suppresses all informational messages.

DBCC CHECKIDENT (table_name, NORESEED)
Current identity value is not reset. DBCC CHECKIDENT returns the current identity value and the current maximum value of the identity column. If the two values are not the same, you should reset the identity value to avoid potential errors or gaps in the sequence of values.

DBCC CHECKIDENT ( table_name )   or  DBCC CHECKIDENT ( table_name, RESEED )
If the current identity value for a table is less than the maximum identity value stored in the identity column, it is reset using the maximum value in the identity column.

DBCC CHECKIDENT ( table_name, RESEED,new_reseed_value )
Current identity value is set to the new_reseed_value. If no rows have been inserted into the table since the table was created, or if all rows have been removed by using the TRUNCATE TABLE statement, the first row inserted after you run DBCC CHECKIDENT usesnew_reseed_value as the identity. Otherwise, the next row inserted uses new_reseed_value + the current increment value.
If the table is not empty, setting the identity value to a number less than the maximum value in the identity column can result in one of the following conditions:

·         If a PRIMARY KEY or UNIQUE constraint exists on the identity column, error message 2627 will be generated on later insert operations into the table because the generated identity value will conflict with existing values.

·         If a PRIMARY KEY or UNIQUE constraint does not exist, later insert operations will result in duplicate identity values.
Exceptions
The current identity value is larger than the maximum value in the table.
Execute DBCC CHECKIDENT (table_name, NORESEED) to determine the current maximum value in the column, and then specify that value as the new_reseed_value in a DBCC CHECKIDENT (table_name, RESEED,new_reseed_value) command.                            
Or
Execute DBCC CHECKIDENT (table_name, RESEED,new_reseed_value) with new_reseed_value set to a very low value, and then run DBCC CHECKIDENT (table_name, RESEED) to correct the value.

All rows are deleted from the table.
Execute DBCC CHECKIDENT (table_name, RESEED,new_reseed_value) with new_reseed_value set to the desired starting value.

Changing the Seed Value
The seed value is the value inserted into an identity column for the very first row loaded into the table. All subsequent rows contain the current identity value plus the increment value where current identity value is the last identity value generated for the table or view. For more information, see Creating and Modifying Identifier Columns.

You cannot use DBCC CHECKIDENT to perform the following tasks:
·         Change the original seed value that was specified for an identity column when the table or view was created.
·         Reseed existing rows in a table or view.

To change the original seed value and reseed any existing rows, you must drop the identity column and recreate it specifying the new seed value. When the table contains data, the identity numbers are added to the existing rows with the specified seed and increment values. The order in which the rows are updated is not guaranteed
Caller must own the table, or be a member of the sysadmin fixed server role, the db_owner fixed database role, or the db_ddladmin fixed database role.
Some notes about DBCC CHECKIDENT
·         You need to be a db_owner (dbo) of the database. If you are not a dbo, you would need permission to execute on behalf of dbo using WITH EXECUTE AS
·         Reseed as (n – 1). So if you wanted a value of 5 as your next value, reseed using 4
·         Setting a value which is less than values which are already in the table will result in unique constraint violations as soon as the value inserted hits a value which already exists in the table.
·         Data type limits apply, you cannot exceed the max value of a TINYINT for example when reseeding.

·         Running it on an empty table produces a change in behaviour. The following demonstrates this….
DBCC CHECKIDENT('Table_1', RESEED, 0);
Now after running that DBCC statement and then adding a row, you would expect the next value to be a 1 but it’s not….
INSERT INTO Table_1(DateAdded)
      VALUES(GETDATE());
       
DBCC CHECKIDENT ('Table_1', NORESEED)
Checking identity information: current identity value ‘0’, current column value ‘0’.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

This is normal behaviour however. If the table is empty, then the next value is the reseed value as opposed to the reseed value plus the increment value.

Scenarios when you might use DBCC CHECKIDENT
It’s already clear what the function of this is but when might you use it?

I’m nervous at the thought of this being called in a production environment but in a dev environment, sure it could come in handy if you need to reset things to a known state.

TRUNCATE TABLE is a command which will enable you to delete all rows from a table and at the same time, reset the identity value. However you need permission to be able to do this and it will only work if the table is not referenced by a foreign key constraint. This is when DBCC CHECKIDENT is useful.



Adding Identity Property to an existing column in a table.
How difficult is it to add an Identity property to an existing column in a table? Is there any T-SQL that can perform this action?
For most, the answer to the above two questions is an absolute NO! There is no straightforward T-SQL like ALTER TABLE… or MODIFY COLUMN to add an Identity Property to an existing column in a table.
However, there is an easy way to accomplish this action. It can be done through SSMS.
The below is sample script generated while doing through SSMS.
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT

BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_example1
(
eid INT NOT NULL IDENTITY (1, 1)
) ON [PRIMARY]
GO

SET IDENTITY_INSERT dbo.Tmp_example1 ON
GO

IF EXISTS(SELECT * FROM dbo.example1)
EXEC('INSERT INTO dbo.Tmp_example1 (eid)
SELECT eid FROM dbo.example1 WITH (HOLDLOCK TABLOCKX)')
GO

SET IDENTITY_INSERT dbo.Tmp_example1 OFF
GO
DROP TABLE dbo.example1
GO
EXECUTE sp_rename N'dbo.Tmp_example1', N'example1', 'OBJECT'
GO
COMMIT




Removing Identity Property from an existing column in a table.
Same is the case when you want to remove Identity column property from a column.
BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT

BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_example1
(
eid INT NOT NULL
) ON [PRIMARY]
GO

IF EXISTS(SELECT * FROM dbo.example1)
EXEC('INSERT INTO dbo.Tmp_example1 (eid)
SELECT eid FROM dbo.example1 WITH (HOLDLOCK TABLOCKX)')
GO

DROP TABLE dbo.example1
GO

EXECUTE sp_rename N'dbo.Tmp_example1', N'example1', 'OBJECT'
GO
COMMIT

Add the identity column to existing table:

ALTER TABLE MyTable ADD ID INT IDENTITY(1,1) NOT NULL

SELECT *, IDENTITY(INT,1,1) AS id INTO #tbl FROM sysobjects

Detecting Identity Columns And Their Properties

The existance of an identity column on a table can be checked via
SELECT OBJECTPROPERTY(OBJECT_ID('<tablename>'),'TableHasIdentity')
Which will return 1 if an identity exists on the table.
Similarly ...
SELECT COLUMNPROPERTY(OBJECT_ID('<tablename>'),'<columnname>','IsIdentity')
... Will show if a column has the identity property.
A more useful way of obtaining this information is by using the catalog view sys.identity_columns which returns a row for each column in the database with an identity property.
SELECT TableName = OBJECT_NAME(OBJECT_ID) ,
       ColumnName = name ,
       OriginalSeed = seed_value ,
       Step = increment_value ,
       LastValue = last_value ,
       IsNotForReplication = is_not_for_replication
FROM sys.identity_columns
We can also reset the current seed to it's original value via a truncate table.
Note - a delete does not do this.
From SQL Server 2012 version, when SQL Server instance is restarted, then table's Identity value is jumped and the actual jumped value depends on identity column data type. If it is integer (int) data type, then jump value is 1000 and if big integer (bigint), then jump value is 10000. From our application point of view, this increment is not acceptable for all the business cases specially when the value shows to the client. This is the special case/issue ships with only SQL Server 2012 and older versions have no such issue.
Method 01: (Using IDENTITY)

ALTER TABLE #Employee
ADD ID INT IDENTITY(1,1)
GO
SELECT * FROM #Employee
GO
--Droping the column for next examples
ALTER TABLE #Employee
drop column ID


Method 02: (Using local variable)

ALTER TABLE #Employee
ADD ID INT
GO
DECLARE @i INT = 0
UPDATE #Employee
SET @i = ID = @i + 1
SELECT * FROM #Employee

--OR--

GO
DECLARE @i INT = 0
UPDATE #Employee SET ID = NULL
UPDATE #Employee SET Id = @i , @i = @i + 1
SELECT * FROM #Employee

Method 03: (Using CTE)

UPDATE #Employee SET ID = NULL
;WITH CTE AS (
SELECT ROW_NUMBER() OVER(ORDER BY Hiredate) AS ID, Name FROM #Employee
)
UPDATE a
SET ID = b.ID
FROM #Employee a
INNER JOIN CTE b ON a.Name = b.name
SELECT * FROM #Employee


Method 04: (Using SEQUENCE)

UPDATE #Employee SET ID = NULL
GO
CREATE SEQUENCE idnum
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO CYCLE
GO
UPDATE #Employee
SET id = NEXT value FOR idnum
SELECT * FROM #Employee
GO
DROP SEQUENCE idnum --Droping the sequence


If a table is having only one identity column how can we insert records into this table?
Consider table customer which is created with below statement in Sql server
create table customer
( id int identity(1,1))

Now to insert  records into this table we can do it in two ways:
INSERT INTO customer DEFAULT VALUES

SET IDENTITY_INSERT dbo.customer ON
INSERT INTO customer (id)
values (1),(2),(3)

Disadvantages of Identity Column:
·         Honestly, identity columns are bad relational design and are not ANSI SQL. They have no meaning to the data in the table, and are hard to read if you are looking at a table that uses it as a foreign key.
·         An Identity column is not guaranteed to be unique nor consecutive.
·         If any insert failure is there then also it can change the current seed value.
·         If we truncate a table (but not delete), It will update the current seed to the original seed value.
·         Moreover, once a table with an identity column is populated, deleting all the rows in the table and reinserting new rows does not cause the numbering to restart from 1. Numbering continues from the last generated number of the table.

Advantages of Identity Column:
A non-SQL based solution to the problem of having an default unique value assigned to a row. SQL Server prefetches identity values into cache and adds them automatically to rows as they're inserted into tables that have a type Identity column. There's no concurrency issues, no deadlocking in high-insert situations, and no possibility of duplicate values.

A high performance Unique identifier; SQL server's optimizer is tuned to work well with Unique indexes based on the identity value.

The flexibility to insert into the identity field a specific value in the case of a mistaken row deletion. (You can never update however). You accomplish this by:
set identity_insert [datababase]..[table] on
go
Note however that the System will not verify the uniqueness of the value you specifically insert (unless of course you have a unique index existing on the identity column).            

That said, using a Surrogate Key (i.e. an identity column) does have some advantages. Indexes can be faster on INT columns compared to a varchar column, and they take up less space on disk and in RAM when you start using it as a foreign key in other tables (Thus speeding up queries on the child tables.)

No comments:

Post a Comment