Incorrect syntax when working with a variable in IDENTITY - sql

I'm trying to create a new table with a primary key value that is a continuation of a previous table.
My code is:
DECLARE #Table1_NextKey INT
SELECT #Table1_NextKey = MAX(id) + 1
FROM [Copy of Table1]
CREATE TABLE [dbo].Table1
(
[ID] [int] NOT NULL IDENTITY(#Table1_NextKey, 1)
CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
But I get this error:
Msg 102, Level 15, State 1, Line 24
Incorrect syntax near '#Table1_NextKey'
Is there a way to get the Create Table to work with the variable?

You are going about this the wrong way.
What you are clearly trying to do, is copy a table and then you would like to continue the identity values.
In this case, do not declare the seed value differently in the CREATE TABLE, just manually set it afterwards:
CREATE TABLE [dbo].Table1
(
[ID] [int] NOT NULL IDENTITY(1, 1)
CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
-- Do some copying code here
DECLARE #Table1_NextKey INT =
(
SELECT #Table1_NextKey = MAX(id) -- not + 1
FROM Table1
);
DBCC CHECKIDENT (Table1 RESEED, #Table1_NextKey) WITH NO_INFOMSGS;

You can only use literal values for identity, you'll need to dynamically construct your create statement, as follows
declare #sql nvarchar(max)=Concat(N'
CREATE TABLE [dbo].Table1(
[ID] [int] NOT NULL IDENTITY(', #Table1_NextKey, N', 1) CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL)
ON [PRIMARY]')
exec sp_executesql #sql

Don't know why SQL Server is so weird about this but with Stu's help, I got this to work:
DECLARE #Table1_NextKey INT,
#SQL_command varchar(4000)
select #Table1_NextKey=max(id)+1 from [Copy of Table1]
set #SQL_command=
'CREATE TABLE [dbo].Table1(
[ID] [int] NOT NULL IDENTITY(' + convert(varchar(5), #Table1_Nextkey) + ', 1) CONSTRAINT PK_Table1 PRIMARY KEY CLUSTERED,
[PLAN] [nvarchar](255) NULL)
ON [PRIMARY]
GO'

Related

Get Identity of destination table when using **DELETE FROM ... OUTPUT ... INTO**

I use bellow code to archive old data in ArchiveTable and delete archived data from SourceTable
DELETE FROM SourceTable
OUTPUT
DELETED.[ID],
DELETED.[Code],
DELETED.[Title]
INTO ArchiveTable([OldID], [Code], [Title])
WHERE Condition
Structure of tables:
CREATE TABLE [SourceTable](
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Code] [VARCHAR](16) NULL,
[Title] [NVARCHAR](128) NULL,
CONSTRAINT [PK_SourceTable] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
CREATE TABLE [ArchiveTable](
[ID] [INT] IDENTITY(1,1) NOT NULL,
[OldID] [INT] NOT NULL,
[Code] [VARCHAR](16) NULL,
[Title] [NVARCHAR](128) NULL,
CONSTRAINT [PK_ArchiveTable] PRIMARY KEY CLUSTERED ([ID] ASC)
)
GO
I need to return deleted records and ArchiveTable.[ID] to application. I change the code like this:
DELETE FROM SourceTable
OUTPUT
DELETED.[ID],
DELETED.[Code],
DELETED.[Title]
INTO ArchiveTable([OldID], [Code], [Title])
OUTPUT DELETED.*
WHERE Condition
This code return deleted records but I don't know how to get ID of ArchiveTable for this records. Look at ArchiveTable structure, It has OldID column that refer to SourceTable.ID and ID column that it is an Identity column of ArchiveTable. I need to ArchiveTable.ID in final result.
You can use a temporary table
CREATE TABLE #DeletedRows(
[ID] [INT] NOT NULL,
[Code] [VARCHAR](16) NULL,
[Title] [NVARCHAR](128) NULL
)
DELETE SourceTable
OUTPUT
DELETED.[ID],
DELETED.[Code],
DELETED.[Title]
INTO #DeletedRows([ID], [Code], [Title])
WHERE Condition
INSERT ArchiveTable([OldID], [Code], [Title])
OUTPUT INSERTED.*
SELECT [ID], [Code], [Title]
FROM #DeletedRows
DROP TABLE #DeletedRows
A variant with a table variable
DECLARE #DeletedRows TABLE(
[ID] [INT] NOT NULL,
[Code] [VARCHAR](16) NULL,
[Title] [NVARCHAR](128) NULL
)
DELETE SourceTable
OUTPUT
DELETED.[ID],
DELETED.[Code],
DELETED.[Title]
INTO #DeletedRows([ID], [Code], [Title])
WHERE Condition
INSERT ArchiveTable([OldID], [Code], [Title])
OUTPUT INSERTED.*
SELECT [ID], [Code], [Title]
FROM #DeletedRows
I found an interesting variant using DML with OUTPUT in SP and INSERT...EXEC... after that:
Test tables:
CREATE TABLE TestTable(
ID int NOT NULL PRIMARY KEY,
Title varchar(10) NOT NULL
)
CREATE TABLE TestTableLog(
LogID int NOT NULL IDENTITY,
OperType char(1) NOT NULL,
CHECK(OperType IN('I','U','D')),
ID int NOT NULL,
Title varchar(10) NOT NULL
)
DML procedures:
CREATE PROC InsTestTable
#ID int,
#Title varchar(10)
AS
INSERT TestTable(ID,Title)
OUTPUT inserted.ID,inserted.Title,'I' OperType
VALUES(#ID,#Title)
GO
CREATE PROC UpdTestTable
#ID int,
#Title varchar(10)
AS
UPDATE TestTable
SET
Title=#Title
OUTPUT inserted.ID,inserted.Title,'U' OperType
WHERE ID=#ID
GO
CREATE PROC DelTestTable
#ID int
AS
DELETE TestTable
OUTPUT deleted.ID,deleted.Title,'D' OperType
WHERE ID=#ID
GO
Tests:
-- insert test
INSERT TestTableLog(ID,Title,OperType)
EXEC InsTestTable 1,'A'
INSERT TestTableLog(ID,Title,OperType)
EXEC InsTestTable 2,'B'
INSERT TestTableLog(ID,Title,OperType)
EXEC InsTestTable 3,'C'
-- update test
INSERT TestTableLog(ID,Title,OperType)
EXEC UpdTestTable 2,'BBB'
-- delete test
INSERT TestTableLog(ID,Title,OperType)
EXEC DelTestTable 3
GO
-- show resutls
SELECT *
FROM TestTableLog
Maybe it'll be interesting to someone.

SQL Check Constraint with User Defined Function

I am troubleshooting an issue seen in our sql server database recently.
Table 1 has a calculated bit column based off of a user defined function which checks if a record exists in another table and evaluates to 0 if not.
Table 2 is the table searched by the function for Table 1. Table 2 also has a check constraint using a function to see if the bit field in Table 1 is set to 1.
This seems like a circular dependency. The problem is that when inserting a batch of records into Table 2, the constraint fails. Inserting these same records 1 by 1 allows all of the inserts to go through. I can't for the life of me figure out why batch inserts cause it to fail. Any help is appreciated.
CREATE TABLE [dbo].[tPecosPriceCheckStoreSubcategory](
[PecosPriceCheckID] [int] NOT NULL,
[StoreID] [int] NOT NULL,
[SubcategoryID] [int] NOT NULL,
[UndirectedExpectedScans] [int] NULL,
[PriceMin] [decimal](8, 2) NULL,
[PriceMax] [decimal](8, 2) NULL,
[PastPriceVariancePercent] [decimal](5, 2) NULL,
[ChangeDate] [datetime] NOT NULL,
[IsUndirected] [bit] NOT NULL,
[IsDirected] AS ([dbo].[fnPecosPriceCheckStoreSubcategoryIsDirected]([PecosPriceCheckID],[SubcategoryID])),
CONSTRAINT [PK_tPecosPriceCheckStoreSubcategory] PRIMARY KEY CLUSTERED
(
[PecosPriceCheckID] ASC,
[StoreID] ASC,
[SubcategoryID] ASC
)
ALTER TABLE [dbo].[tPecosPriceCheckStoreSubcategory] ADD CONSTRAINT [DF_IsUndirected] DEFAULT ((0)) FOR [IsUndirected]
GO
CREATE FUNCTION [dbo].[fnPecosPriceCheckStoreSubcategoryIsDirected]
(
#PecosPriceCheckID int,
#SubcategoryID int
)
RETURNS bit
AS
BEGIN
declare #isDirected bit
set #isDirected = 0
if (exists (select 1 from tPecosDirectedPriceCheckItem where PecosPriceCheckID = #PecosPriceCheckID and SubcategoryID = #SubcategoryID ))
begin
set #isDirected = 1
end
return #isDirected
END
CREATE TABLE [dbo].[tPecosDirectedPriceCheckItem](
[ID] [int] IDENTITY(1,1) NOT NULL,
[PecosPriceCheckID] [int] NOT NULL,
[PecosItemID] [int] NOT NULL,
[ItemSortOrder] [int] NOT NULL,
[SubcategoryID] [int] NOT NULL,
[ChangeDate] [datetime] NULL,
CONSTRAINT [PK_tPecosDirectedPriceCheckItem] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
ALTER TABLE [dbo].[tPecosDirectedPriceCheckItem] WITH NOCHECK ADD CONSTRAINT [CK_tPecosDirectedPriceCheckItem_CheckPriceCheckSubcategoryDirected] CHECK (([dbo].[fnCheckDirectedItemPriceCheckSubcategory]([PecosPriceCheckID],[SubcategoryID])=(0)))
GO
ALTER TABLE [dbo].[tPecosDirectedPriceCheckItem] CHECK CONSTRAINT [CK_tPecosDirectedPriceCheckItem_CheckPriceCheckSubcategoryDirected]
GO
CREATE FUNCTION [dbo].[fnCheckDirectedItemPriceCheckSubcategory]
(
#PriceCheckID INT,
#SubcategoryID INT
)
RETURNS BIT
AS
BEGIN
DECLARE #isViolation BIT
SET #isViolation =
CASE WHEN EXISTS (SELECT * FROM tPecosPriceCheckStoreSubcategory WHERE SubcategoryID = #SubcategoryID AND PecosPriceCheckID = #PriceCheckID AND IsDirected = 1)
THEN
0
ELSE
1
END
RETURN #isViolation
END

Assigning null values to SqlParameter DateTime

I have a table like this
CREATE TABLE [dbo].[tblVolunteers]
(
[VolID] [int] IDENTITY(1,1) NOT NULL,
[VolFName] [varchar](20) NULL,
[DLExpiration] [smalldatetime] NULL,
CONSTRAINT [PK_tblVolunteers] PRIMARY KEY CLUSTERED
([VolID] ASC),
CONSTRAINT [uniqueUserID] UNIQUE NONCLUSTERED ([UserID] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
And I have a stored procedure to update data on this table
ALTER PROCEDURE [dbo].[volUpdate]
#StaffID INT,
#ModifiedBy VARCHAR(100),
#NickName VARCHAR(20),
#FirstName VARCHAR(20),
#DLExpiration SMALLDATETIME
AS
UPDATE tblVolunteers
SET
VolNickName = #NickName,
VolFName = #FirstName,
DLExpiration = #DLExpiration
WHERE
VolID = #StaffID
In some cases I don't have a valid DLExpiration to update at that time I want to pass null value to table. And I am doing it like this
new SqlParameter("#DLExpiration", null)
But still it throws an error
Procedure or function 'volUpdate' expects parameter '#DLExpiration', which was not supplied.
Can anyone point out What I am doing wrong here?
You need to pass DBNull.Value to your stored procedure:
new SqlParameter("#DLExpiration", DBNull.Value)

Inserted clause returns 0 when used with triggers

I'm trying to get the last inserted rows Id from an inserts statement on the following table using SQL server 2012
[dbo].[Table](
[TableId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[CreatedBy] [nvarchar](50) NULL,
[CreatedDate] [datetime2](7) NOT NULL,
[ModifiedBy] [nvarchar](50) NULL,
[ModifiedDate] [datetime2](7) NULL,
CONSTRAINT [pk_Table] PRIMARY KEY CLUSTERED
(
[TableId] ASC
)
I'm also using an audit triggers on that table that are as follows:
trigger [dbo].[trigger_Table_auditColumnAutoInsert]
on [dbo].[Table]
instead of insert
/**************************************************************
* INSTEAD OF trigger on table [dbo].[Table] responsible
for automatically inserting audit column data
**************************************************************/
as
begin
set nocount on
declare #currentTime datetime2
set #currentTime = GETUTCDATE()
insert into [dbo].[Table]
(
Name,
CreatedBy,
CreatedDate,
ModifiedBy,
ModifiedDate
)
select
Name,
ISNULL(CreatedBy, system_user),
#currentTime,
NULL,
NULL
from inserted
select SCOPE_IDENTITY() as [TableId]
goto EOP -- end of procedure
ErrorHandler:
if (##trancount <> 0) rollback tran
EOP:
end
I used different approaches, but nothing 'SAFE' seems to work.
Using scope identity returns null
insert into dbo.[Table](Name) Values('foo')
select SCOPE_IDENTITY()
Using OUTPUT INSERTED always returns 0 for the identity coloumns; although it returns the other inserted values:
declare #tmpTable table
(
TableId int,
Name nvarchar (50)
)
INSERT INTO [dbo].[Table]([Name])
output inserted.TableId, inserted.Name into #tmpTable
VALUES('foo')
select * from #tmpTable
TableId Name
0 foo
I know of another solution to get the inserted Id from the triggers itself, by executing a dynamic sql command as follows:
declare #tmpTable table (id int)
insert #tmpTable (id )
exec sp_executesql N'insert into dbo.[Table](Name) Values(''foo'')'
select id from #tmpTable
I couldn't figure out why in the first 2 cases it is not working; why the SCOPE_IDENTITY() does not work although the triggers execute in the same transaction? And also why the INSERTED clause returns 0 for the identity column.
It appears that the following requirements apply to your audit column data:
Use the insert value supplied for CreatedBy, or use SYSTEM_USER by default.
Always use GETUTCDATE() for CreatedDate.
If the INSTEAD OF trigger (rather than an AFTER trigger) is not essential to your requirements, then you can use DEFAULT constraints on your audit columns and an AFTER INSERT trigger to enforce requirement #2.
CREATE TABLE [dbo].[Table]
(
[TableId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
[CreatedBy] [nvarchar](50) NOT NULL CONSTRAINT [DF_Table_CreatedBy] DEFAULT SYSTEM_USER,
[CreatedDate] [datetime2](7) NOT NULL CONSTRAINT [DF_Table_CreatedDate] DEFAULT GETUTCDATE(),
[ModifiedBy] [nvarchar](50) NULL,
[ModifiedDate] [datetime2](7) NULL,
CONSTRAINT [pk_Table] PRIMARY KEY CLUSTERED ([TableId] ASC)
)
GO
CREATE TRIGGER Trigger_Table_AfterInsert ON [dbo].[Table]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[Table] SET [CreatedDate]=GETUTCDATE()
FROM [dbo].[Table] AS T
INNER JOIN INSERTED AS I ON I.[TableId]=T.[TableId]
END
GO
Then, both SCOPE_IDENTITY() and OUTPUT INSERTED techniques to get the new TableId value work as expected.
If the INSTEAD OF trigger is essential to your implementation, then SELECT ##IDENTITY is an alternative to SCOPE_IDENTITY.

Can't update column values, it is associated with a clustered index?

I am having some problems when trying to update column values, this column has a clustered index associated to it.
This is the update statement.
UPDATE dbo.VentureXRef
SET RefValue = REPLICATE('0',7 - LEN(RefValue)) + RefValue WHERE LEN(RefValue) < 7
This is the error I get
Cannot insert duplicate key row in
object 'dbo.VentureXRef' with unique
index 'idx_WFHMJVXRef_RefValueByType'.
This is mytable definition
CREATE TABLE [dbo].[VentureXRef]
(
[ID] [int] NOT NULL IDENTITY(1, 1),
[RefValue] [varchar] (30) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[RefValueTypeID] [int] NOT NULL,
[State] [char] (2) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF__WFHMJoint__State__2AC11801] DEFAULT (' '),
[ClientID] [int] NOT NULL,
[DoingBusinessAs] [varchar] (255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Disabled] [bit] NOT NULL CONSTRAINT [DF_VentureXRef_Disabled] DEFAULT (0),
[Username] [varchar] (64) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF_VentureXRef_Username] DEFAULT (user_name()),
[DateDeleted] [datetime] NULL,
[DateLastModified] [datetime] NOT NULL CONSTRAINT [DF_VentureXRef_DateLastModified] DEFAULT (getdate())
) ON [PRIMARY]
GO
CREATE CLUSTERED INDEX [idx_WFHMJVXRef_RefValue] ON [dbo].[VentureXRef] ([RefValue], [State]) WITH (FILLFACTOR=80) ON [PRIMARY]
GO
ALTER TABLE [dbo].[VentureXRef] ADD CONSTRAINT [PK__WFHMJointVenture__28D8CF8F] PRIMARY KEY NONCLUSTERED ([ID]) WITH (FILLFACTOR=80) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [idx_WFHMJVXRef_RefValueByType] ON [dbo].[VentureXRef] ([RefValue], [State], [DateDeleted], [RefValueTypeID]) WITH (FILLFACTOR=80) ON [PRIMARY]
GO
ALTER TABLE [dbo].[VentureXRef] ADD CONSTRAINT [IX_VentureXRef] UNIQUE NONCLUSTERED ([RefValue], [RefValueTypeID], [State], [DateDeleted]) WITH (FILLFACTOR=80) ON [PRIMARY]
GO
ALTER TABLE [dbo].[VentureXRef] ADD CONSTRAINT [fk_WFHMJVXRef_ClientID] FOREIGN KEY ([ClientID]) REFERENCES [dbo].[Client] ([ClientID])
GO
ALTER TABLE [dbo].[VentureXRef] ADD CONSTRAINT [fk_WFHMJVXRef_RefValueTypeID] FOREIGN KEY ([RefValueTypeID]) REFERENCES [dbo].[VentureRefValueType] ([RefValueTypeID])
GO
What is the proper way to do this update statement?
Thanks in advance
YOur problem is you are trying to update it to a value that already exists in the table and so the unique index says it can't.
as mentioned by HILGEm this is a duplicate records problem.To identify records causing duplication you can run below query after substituting your table and database name in place of CTE
use test;
with cte as (
select '123' refvalue union all select '567' union all
select '0000123' union all
select '123456')
select refvalue from cte as a
where
len(refvalue) <7 and
exists(
select 1 from cte as b where
len(refvalue)>=7 and
REPLICATE('0',7 - LEN(a.RefValue)) + a.RefValue =b.refvalue
)