Using SCOPE_IDENTITY() in a constraint - sql-server

I am aware that using IDENT_CURRENT will not always return me the correct identity value (especially true in multi-threaded applications). I wanted to use SCOPE_IDENTITY() instead.
For example this is my Employee table:
create table Employee
(
ID int identity(1,1),
Name varchar(20),
SystemID int,
constraint Employee_PK primary key (ID asc)
)
I have a statement below:
alter table Employee
add constraint Employee_D1 default ident_current('Employee') for SystemID
which I need to modify to use SCOPE_IDENTITY() instead.
I tried the below:
alter table Employee
add constraint Employee_D1 default SCOPE_IDENITITY() for SystemID
This did not give any errors. But upon inserting a row, I did not see this column getting updated with the identity value. What am I doing wrong?
Note that the SystemID must not be readonly, so computed field isn't an option.
My exercise here is to try eliminating entry of wrong IDENTITY value in SystemID in case parallel processes try to insert rows.

Just re-read your answer. SystemID isn't an identity column. I don't think you can use SCOPE_IDENITITY() as it hasn't added the row and retrieved the new Identity value at the point it would need the value to save.
What you will need to do is create a trigger After Insert of the row to update the SystemId value. CREATE TRIGGER

Here's how I'd approach this problem (apologies for the poor field names, I'm not feeling inventive)
CREATE TABLE employees (
id int identity(1,1) NOT NULL
, name varchar(20) NOT NULL
, actual_system_id int NULL
, system_id As Coalesce(actual_system_id, id)
, CONSTRAINT pk_employees PRIMARY KEY (id)
)
;
INSERT INTO employees (name)
VALUES ('John')
, ('Paul')
, ('George')
, ('Ringo')
;
SELECT id
, name
, system_id
FROM employees
;
UPDATE employees
SET actual_system_id = 937
WHERE name = 'George'
;
SELECT id
, name
, system_id
FROM employees
;

Related

Adding AUTO_INCREMENT

I have a table where I've merged 2 tables into one.
One of the tables had an ID (primary key).
Now I got a merged table where some of the ID is 0.
I now try to restore and fill out the 0 with AUTO_INCREMENT so I
get a table with unique numbers (and not lose the one already there )
Someone got a god solution here ?
Firstly, the fact that you have a bunch of 0's in the table implies 2 additional problems:
The "ID" column is not a Primary Key or dose not have a Unique Index on it; meaning that duplicates were inserted
The column is (likely) no longer an IDENTITY.
Firstly, You'll need to get the new values in there. This can be done with an updatable CTE, with ROW_NUMBER and a windowed MAX
First some sample data:
CREATE TABLE dbo.TestTable (ID int NOT NULL);
INSERT INTO dbo.TestTable (ID)
VALUES(1),(2),(3),(0),(0),(0);
And now to UPDATE the rows with 0:
WITH RNs AS(
SELECT ID,
ROW_NUMBER() OVER (PARTITION BY CASE ID WHEN 0 THEN 0 ELSE 1 END ORDER BY (SELECT NULL)) + --If you have a way of determining the order, change the ORDER BY
MAX(ID) OVER () AS [NewID]
FROM dbo.TestTable)
UPDATE RNs
SET ID = [NewID]
WHERE ID = 0;
Now we (probably) need to fix the table and get the IDENTITY column in there. You can't change a column to an IDENTITY, so we'll need to create a new one and ensure it follows the value of the existing ID.
First, therefore, we need to add a CLUSTERED index to the table, so that the new IDENTITY will use that to generate its value:
ALTER TABLE dbo.TestTable ADD CONSTRAINT PK_TestTable PRIMARY KEY CLUSTERED (ID);
Now we can add the new IDENTITY column:
ALTER TABLE dbo.TestTable ADD IdentityID int IDENTITY NOT NULL;
Then we need to DROP the Primary Key we just created, and then the old column:
ALTER TABLE dbo.TestTable DROP CONSTRAINT PK_TestTable ;
ALTER TABLE dbo.TestTable DROP COLUMN ID;
And then, finally, we can rename the new column, and then recreate the Primary Key:
EXEC sys.sp_rename N'dbo.TestTable.IdentityID','ID','COLUMN';
GO
ALTER TABLE dbo.TestTable ADD CONSTRAINT PK_TestTable PRIMARY KEY CLUSTERED (ID);

SQL Server how to populate data to table2 when table1 updated

I'm creating a table to store cars, and another table to store the time when the new car was added to the database, can someone please explain to me how to create the relationship to update time automatically when the car was created.
Create table Cars
(
CarID int Primary Key identity(1,1),
Make varchar(50),
Model varchar(50),
Colour varchar(59)
)
create Table TimeLogs
(
AddedOn SYSDATETIME(),
CarId int unique foreign key references Cars(CarId)
)
I would solve this by not using a second table for what should be a column in the Cars table. The table would be designed more appropriately like this.
Create table Cars
(
CarID int Primary Key identity(1,1),
Make varchar(50),
Model varchar(50),
Colour varchar(59),
AddedOn datetime default SYSDATETIME()
)
To automatically update one table whenever another table is updated, you need to use a TRIGGER.
You needs to use insert trigger for the same, as below
CREATE TRIGGER yourNewTrigger ON yourSourcetable
FOR INSERT
AS
INSERT INTO yourDestinationTable
(col1, col2 , col3, user_id, user_name)
SELECT
'a' , default , null, user_id, user_name
FROM inserted
go

How to set identity constraint on existing column if data already exists in table - sybase ase 15.5

I have a table which already consists a number of records. The table has a column named 'id' of integer type and I have already inserted unique values in id column for all the records in the table.
Now I need to set IDENTITY constraint on the 'id' column so that in any new record added to the table, the value of id column gets inserted automatically incremented from the last value added to the column.
The create table query of the table is like follows:
create table Table1 (
Column1 varchar(255) not null,
Column2 varchar(254) not null,
Column3 int not null,
id int ,
PRIMARY KEY CLUSTERED ( id ) on 'default'
)
I insert data into the table using following query:
Insert into Table1 (Column1, Column2, Column3, id) values("abc","def",12,1)
But when I try to execute following Alter table query on my sybase database it returns an error "Incorrect Syntax near 'IDENTITY'"
ALTER TABLE Table1 MODIFY id int IDENTITY DEFAULT AUTOINCREMENT NOT NULL
Can anyone point me in the right direction about, how to apply IDENTITY constraint on a column which already has data?

How to set "auto insert" foreign key value by using SQL Server?

I have created two tables and also created a relationship between them.
Table students:
create table students
(
[StudentId] NVARCHAR(50) NOT NULL PRIMARY KEY,
[Name] NVARCHAR(50) NOT NULL
);
Table studentprofile:
create table studentprofile
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
[StudentId] NVARCHAR(50) NOT NULL,
[Address] NVARCHAR(50) NOT NULL,
);
and relationship:
alter table studentprofile
add constraint students_studentprofile_FK
foreign key (StudentId)
references students(StudentId)
on delete cascade on update cascade
But, when I wrote this line:
insert into students values('110111', 'Marik')
the value of StudentId (in table studentprofile) wasn't updated automatically. Why?
Can you tell me how to set the value of StudentId (in table studentprofile) can be inserted automatically whenever I insert into table students?
There is no such thing as insert cascade.
You can implement such a thing by using a trigger for insert on your students table, inserting default values (or nulls) into the studentprofile table:
CREATE TRIGGER students_insert ON students AFTER INSERT
AS
INSERT INTO studentprofile(StudentId, Address)
SELECT StudentId, 'NO ADDRESS'
FROM inserted
Note that your Address column is defined as not null and has no default value, this is why I've used the hard coded 'NO ADDRESS' for it.
However, I agree with the comments on your question: you would be better off inserting the data to the student profile using a different insert statement (perhaps inside a transaction with the insert to students).

Reordering Identity primary key in sql server

Yes i am very well aware the consequences. But i just want to reorder them. Start from 1 to end.
How do I go about reordering the keys using a single query ?
It is clustered primary key index
Reordering like
First record Id 1
second record Id 2
The primary key is Int
Drop PK constraint
Drop Identity column
Re-create Identity Column
Re-Create PK
USE Test
go
if(object_id('IdentityTest') Is not null)
drop table IdentityTest
create table IdentityTest
(
Id int identity not null,
Name varchar(5),
constraint pk primary key (Id)
)
set identity_insert dbo.IdentityTest ON
insert into dbo.IdentityTest (Id,Name) Values(23,'A'),(26,'B'),(34,'C'),(35,'D'),(40,'E')
set identity_insert dbo.IdentityTest OFF
select * from IdentityTest
------------------1. Drop PK constraint ------------------------------------
ALTER TABLE [dbo].[IdentityTest] DROP CONSTRAINT [pk]
GO
------------------2. Drop Identity column -----------------------------------
ALTER table dbo.IdentityTest
drop column Id
------------------3. Re-create Identity Column -----------------------------------
ALTER table dbo.IdentityTest
add Id int identity(1,1)
-------------------4. Re-Create PK-----------------------
ALTER TABLE [dbo].[IdentityTest] ADD CONSTRAINT [pk] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
--------------------------------------------------------------
insert into dbo.IdentityTest (Name) Values('F')
select * from IdentityTest
IDENTITY columns are not updatable irrespective of SET IDENTITY_INSERT options.
You could create a shadow table with the same definition as the original except for the IDENTITY property. Switch into that (this is a metadata only change with no movement of rows that just affects the table's definition) then update the rows and switch back though.
A full worked example going from a situation with gaps to no gaps is shown below (error handling and transactions are omitted below for brevity).
Demo Scenario
/*Your original table*/
CREATE TABLE YourTable
(
Id INT IDENTITY PRIMARY KEY,
OtherColumns CHAR(100) NULL
)
/*Some dummy data*/
INSERT INTO YourTable (OtherColumns) VALUES ('A'),('B'),('C')
/*Delete a row leaving a gap*/
DELETE FROM YourTable WHERE Id =2
/*Verify there is a gap*/
SELECT *
FROM YourTable
Remove Gaps
/*Create table with same definition as original but no `IDENTITY`*/
CREATE TABLE ShadowTable
(
Id INT PRIMARY KEY,
OtherColumns CHAR(100)
)
/*1st metadata switch*/
ALTER TABLE YourTable SWITCH TO ShadowTable;
/*Do the update*/
WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY Id) AS RN
FROM ShadowTable
)
UPDATE CTE SET Id = RN
/*Metadata switch back to restore IDENTITY property*/
ALTER TABLE ShadowTable SWITCH TO YourTable;
/*Remove unneeded table*/
DROP TABLE ShadowTable;
/*No Gaps*/
SELECT *
FROM YourTable
I don't think there is any way to do this in a single query. Your best bet is to copy the data to a new table, drop and recreate the original table (or delete the data and reseed the identity) and reinsert the data in the original order using the previous identity as the ordering (but not re-inserting it).
CREATE TABLE Table1_Stg (bla bla bla)
INSERT INTO Table1_Stg (Column2, Column3,...) SELECT Column2, Column3,... FROM Table1 ORDER BY Id
Here the Id column is excluded from the SELECT column list.
Or, you can do:
SELECT * INTO Table1_Stg FROM Table1 ORDER BY Id
DROP Table1
sp_rename Table1_stg Table1
Please lookup the usage for sp_rename as I am doing this from memory.
Hope this helps.
EDIT: Please save a script with all your indexes and constraints if any on Table1.
EDIT2: Added second method of creating table and inserting into table.
UPDATE tbl SET id = (SELECT COUNT(*) FROM tbl t WHERE t.id <= tbl.id);
This last statement is genius. Just had to remove the primary key from the table design first and make sure under the design option Identity Specifications is set to no. Once you run the query set these options back.

Resources