SQL auto incremente sql column with missing numbers. - sql

I have a a table with about 10000 records and an identity column that doesn't do auto increment, I want to change this. Normally I would drop the column and re-add it with the identity on but the problem is that this column is used as a foreign key in a lot of my other tables and there are some numbers in the primary column that are missing. I know that I cant change the column to start auto incrementing but is there a way to have the new auto incremented column copy the same numbers as the original and start from the end of that?

You should be able to do something like below. Table_1 is the table I wish to update to now include an identity column whereas the column was just a simple int before. Notice when it is creating the tmp_Table_1 it is creating an identity column that is setting the identity seed to 889 since the largest int id i had before was 888. The script then takes all the data in the existing table and inserts into into the tmp table, then drops the old table and renames the tmp table back to Table_1. By setting the identity seed to 889 the next row of data you insert will insert with an id of 890 automatically. Does this make sense?
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Table_1
(
id int NOT NULL IDENTITY (889, 1),
name nchar(10) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Table_1 SET (LOCK_ESCALATION = TABLE)
GO
SET IDENTITY_INSERT dbo.Tmp_Table_1 ON
GO
IF EXISTS(SELECT * FROM dbo.Table_1)
EXEC('INSERT INTO dbo.Tmp_Table_1 (id, name)
SELECT id, name FROM dbo.Table_1 WITH (HOLDLOCK TABLOCKX)')
GO
SET IDENTITY_INSERT dbo.Tmp_Table_1 OFF
GO
DROP TABLE dbo.Table_1
GO
EXECUTE sp_rename N'dbo.Tmp_Table_1', N'Table_1', 'OBJECT'
GO
ALTER TABLE dbo.Table_1 ADD CONSTRAINT
PK_Table_1 PRIMARY KEY CLUSTERED
(
id
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
COMMIT

Related

How to copy table data and structure with Identity column and its value to another table in the same db(just change table name)

I have trouble in copying table data and structure to another table since I want to keep the Id column of Identity column and keep its oridinal value instead of starting from 1
I use below sql to insert all data except the ID column from MY_TABLE to MY_TABLE_NEW since it has error saying that
Only when the column list is used and IDENTITY_INSERT is ON, an explicit value can be specified for the identity column in the table'My_TABLE_NEW'.
But I have set it like below SQL:
IF NOT EXISTS (select * from sys.objects where name = 'My_TABLE_NEW')
BEGIN
CREATE TABLE [dbo].[My_TABLE_NEW]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[OBJECT_ID] [int] NOT NULL,
[YEAR_MONTH] [int] NOT NULL,
CONSTRAINT [PK_My_TABLE_NEW]
PRIMARY KEY CLUSTERED ([ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'My_TABLE_NEW')
BEGIN
SET IDENTITY_INSERT My_TABLE_NEW ON
INSERT INTO My_TABLE_NEW
SELECT [ID]
,[OBJECT_ID]
,[YEAR_MONTH]
FROM My_TABLE
SET IDENTITY_INSERT My_TABLE_NEW OFF
END
GO
What is the problem?
Try your insert with the column names:
INSERT INTO My_TABLE_NEW ([ID], [OBJECT_ID], [YEAR_MONTH])
SELECT [ID]
,[OBJECT_ID]
,[YEAR_MONTH]
FROM My_TABLE
From the documentation:
When an existing identity column is selected into a new table, the new column inherits the IDENTITY property, unless one of the following conditions is true:
The SELECT statement contains a join, GROUP BY clause, or aggregate function.
Multiple SELECT statements are joined by using UNION.
The identity column is listed more than one time in the select list.
The identity column is part of an expression.
The identity column is from a remote data source.
That means you can copy the table with SELECT INTO while retaining the identity column and can just add the PK after.
SELECT *
INTO My_TABLE_NEW
FROM My_TABLE
Here is a demo with fiddle.
You can use the built-in tool sp_rename for this, as long as you are just renaming the table not trying to create a copy of it.
EXEC sp_rename 'My_TABLE', 'My_TABLE_NEW'
GO;
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-rename-transact-sql?view=sql-server-ver15
If you want to create a copy, then you just have to do the following:
SELECT *
INTO My_TABLE_NEW
FROM My_TABLE
Note: If you do this, you will have to re-add any key constraints, computed value columns, etc.

Adding a uniqueidentifier column and adding the default to generate new guid

I have the following SQL command:
ALTER TABLE dbo.UserProfiles
ADD ChatId UniqueIdentifier NOT NULL,
UNIQUE(ChatId),
CONSTRAINT "ChatId_default" SET DEFAULT newid()
I want to be able to make this column unique, and I want it to be able to generate a new guid every time a row is added to the table. This column is not an IDENTITY column because I already have one. This is something separate. How would I go about adding this column to a table with users already in it.
see this sample:
create table test (mycol UniqueIdentifier NOT NULL default newid(), name varchar(100))
insert into test (name) values ('Roger Medeiros')
select * from test
for add a not null field on a populated table you need this.
alter table test add mycol2 UniqueIdentifier NOT NULL default newid() with values
CREATE UNIQUE NONCLUSTERED INDEX IX_test ON dbo.test
(
mycol
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Don't use newid() as default, instead use newsequentialid(). newid() creates a lot of fragmentation and that's bad for indexes.
As far as adding the new column to a table with existing data, simply do this:
ALTER TABLE your_table
ADD your_column UNIQUEIDENTIFIER DEFAULT newsequentialid() NOT null

How can I avoid failing an entire INSERT batch due to 1 NULL

I have a table with a primary key and a stored procedure I use to insert to that table. I have no control over the stored procedure and cannot change it. Sometimes the procedure returns many records and 1 record with a NULL value for the primary key column. At the moment, the entire batch of new rows fails to insert.
How can I configure my code or the table to fail only on the 1 row with the NULL value, but allow the other rows to be inserted?
Here is some test code:
IF OBJECT_ID('tempdb..#tbl') IS NOT NULL
DROP TABLE #tbl
CREATE TABLE #tbl (
col INT NOT NULL,
CONSTRAINT PK_tbl PRIMARY KEY (col ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
SET XACT_ABORT OFF
--Imagine this is the procedure that cannot be edited
insert into #tbl (col) values
(null), (1), (2)
--Ideally, the table would have 1 and 2
select * from #tbl
Assuming we're not really talking about a #temporary table, you could create an instead of insert trigger.
CREATE TRIGGER dbo.PreventNullsOnTableName
ON dbo.TableName
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.TableName SELECT col1 FROM inserted WHERE col1 IS NOT NULL;
END
GO
You may also want to use GROUP BY col1 to prevent PK violations, but that depends on whether you want to handle that gracefully or raise an error.
You could also remove the NOT NULL constraint and instead of having a PRIMARY KEY, create a unique filtered index WHERE col1 IS NOT NULL.
Don't have NOT NULL on col INT. It can still be PK but it will only allow one null. Then you can delete the null row.
OK I was wrong the PK cannot be null. But you can have a null unique non clustered index. It is fundamentally a PK but not clustered. If the insert has at most one null then the insert will succeed and you can then delete the 1 row that is null.

Trigger to change autoincremented value

I have a simple table with tax rates
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TaxRates](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_TaxRates] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
If user deleted record I want to not change autoincrementer while next insert.
To have more clearance.
Now I have 3 records with id 0,1 and 2. When I delete row with Id 2 and some time later I add next tax rate I want to have records in this table like before 0,1,2.
There shouldn't be chance to have a gap like 0,1,2,4,6. It must be trigger.
Could you help with that?
You need to accept gaps or don't use IDENTITY
id should have no external meaning
You can't update IDENTITY values
IDENTITY columns will always have gaps
In this case you'd update the clustered Pk which will be expensive
What about foreign keys? you'd need a CASCADE
Contiguous numbers can be generated with ROW_NUMBER() at read time
Without IDENTITY (whether you load this table or another) won't be concurrency-safe under load
Trying to INSERT into a gap (by an INSTEAD OF trigger) won't be concurrency-safe under load
(Edit) History tables may have the deleted values anyway
An option, if the identity column has become something passed around in your organization is to duplicate that column into a non-identity column on the same table and you can modify those new id values at will while retaining the actual identity field.
turning identity_insert on and off can allow you to insert identity values.

Alter Table Add Column Syntax

I'm trying to programmatically add an identity column to a table Employees. Not sure what I'm doing wrong with my syntax.
ALTER TABLE Employees
ADD COLUMN EmployeeID int NOT NULL IDENTITY (1, 1)
ALTER TABLE Employees ADD CONSTRAINT
PK_Employees PRIMARY KEY CLUSTERED
(
EmployeeID
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
What am I doing wrong? I tried to export the script, but SQL Mgmt Studio does a whole Temp Table rename thing.
UPDATE:
I think it is choking on the first statement with "Incorrect syntax near the keyword 'COLUMN'."
Just remove COLUMN from ADD COLUMN
ALTER TABLE Employees
ADD EmployeeID numeric NOT NULL IDENTITY (1, 1)
ALTER TABLE Employees ADD CONSTRAINT
PK_Employees PRIMARY KEY CLUSTERED
(
EmployeeID
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
This is how Adding new column to Table
ALTER TABLE [tableName]
ADD ColumnName Datatype
E.g
ALTER TABLE [Emp]
ADD Sr_No Int
And If you want to make it auto incremented
ALTER TABLE [Emp]
ADD Sr_No Int IDENTITY(1,1) NOT NULL
The correct syntax for adding column into table is:
ALTER TABLE table_name
ADD column_name column-definition;
In your case it will be:
ALTER TABLE Employees
ADD EmployeeID int NOT NULL IDENTITY (1, 1)
To add multiple columns use brackets:
ALTER TABLE table_name
ADD (column_1 column-definition,
column_2 column-definition,
...
column_n column_definition);
COLUMN keyword in SQL SERVER is used only for altering:
ALTER TABLE table_name
ALTER COLUMN column_name column_type;
It could be doing the temp table renaming if you are trying to add a column to the beginning of the table (as this is easier than altering the order). Also, if there is data in the Employees table, it has to do insert select * so it can calculate the EmployeeID.