Identity Insert error is being generated on insert (not in code) - sql-server

I'm attempting to build a table with the following code - No errors when I create the table, I can see the struncture and it shows that IDENTITY_INSERT is set to ON.
CREATE TABLE lt_percent_cs
(
id_key INT IDENTITY PRIMARY KEY,
customer_no INT ,
season INT,
percentage DECIMAL,
created_by VARCHAR(15) NULL,
create_dt DATETIME NULL,
last_updated_by VARCHAR(15) NULL,
last_update_dt DATETIME NULL,
create_loc VARCHAR(16) NULL
) ON [primary]
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].lt_percent_cs
ADD CONSTRAINT [lt_percent_created_by]
DEFAULT (user_name()) FOR [created_by]
GO
ALTER TABLE [dbo].lt_percent_cs
ADD CONSTRAINT [lt_percent_create_dt]
DEFAULT (getdate()) FOR [create_dt]
GO
ALTER TABLE [dbo].lt_percent_cs
ADD CONSTRAINT [lt_percent_create_loc]
DEFAULT [dbo].fs_location() FOR [create_loc]
GO
SET IDENTITY_INSERT lt_percent_cs ON
I get the following error when I attempt to insert data (through application not via code).
Last Error: Database update failed:
dataobject=
sqlca.sqlerrtext=SQLSTATE = 42000
Microsoft OLE DB Provider for SQL Server
Cannot insert explicit value for identity column in table 'lt_percent_cs' when IDENTITY_INSERT is set to OFF.
No changes made to database.
INSERT INTO lt_percent_cs (id_key, customer_no, season, percentage)
VALUES (54891, 80055514, 2017, 50)
sqlca.sqldbcode=544
sqlsyntax:
INSERT INTO lt_percent_cs (id_key, customer_no, season, percentage) VALUES (54891, 80055514, 2017, 50)
row:1 [nvo_ds_database.uf_update.34 (544)]
I should add when I run the script in SQL Server Management Studio, it works without issue and no errors are generated.
INSERT INTO lt_percent_cs (id_key, customer_no, season, percentage)
VALUES (54891, 80055514, 2017, 50)
Any thoughts?

Remove id_key from Insert statement since id_key is identity seeded
INSERT INTO lt_percent_cs (customer_no, season, percentage ) VALUES ( 80055514, 2017, 50 )
Otherwise declare id_key as integer Primary Key
then Insert should work
INSERT INTO lt_percent_cs ( id_key, customer_no, season, percentage ) VALUES ( 54891, 80055514, 2017, 50 )
Since you want bulk insert data and maintain the identity I can suggest alter id_key to integer primary key then bulk insert then alter field back to identity to ON... going forward you don't need to insert id_key

If you want to insert a explicit Id in application, you have to set Identity_insert on and insert in one transaction! I don't know, which application you are using, but this rule is universal.

Related

Inserting to table having issue - Explicit value must be specified for identity column in table

I'm getting ready to release a stored procedure that gets info from other tables, does a pre-check, then inserts the good data into a (new) table. I'm not used to working with keys and new tables as much, and my insert into this new table I'm creating is having this error message having to do with the insert/key:
Msg 545, Level 16, State 1, Line 131
Explicit value must be specified for identity column in table 'T_1321_PNAnnotationCommitReport' either when IDENTITY_INSERT is set to ON or when a replication user is inserting into a NOT FOR REPLICATION identity column.
BEGIN
...
BEGIN
IF NOT EXISTS (SELECT * FROM sys.tables where name = N'T_1321_PNAnnotationCommitReport')
BEGIN
CREATE TABLE T_1321_PNAnnotationCommitReport (
[id] [INT] IDENTITY(1,1) PRIMARY KEY NOT NULL, --key
[progressnote_id] [INT] NOT NULL,
[form_id] [INT] NOT NULL,
[question_id] [INT],
[question_value] [VARCHAR](max),
[associatedconcept_id] [INT],
[crte_date] [DATETIME] DEFAULT CURRENT_TIMESTAMP,
[create_date] [DATETIME] --SCHED_RPT_DATE
);
print 'test';
END
END --if not exists main table
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport ON;
...
INSERT INTO dbo.T_1321_PNAnnotationCommitReport--(progressnote_id,form_id,question_id,question_value,associatedconcept_id,crte_date, create_date) **I tried with and without this commented out part and it's the same.
SELECT progressnote_id,
a.form_id,
question_id,
questionvalue,
fq.concept_id,
getdate(),
a.create_date
FROM (
SELECT form_id,
progressnote_id,
R.Q.value('#id', 'varchar(max)') AS questionid,
R.Q.value('#value', 'varchar(max)') AS questionvalue,
create_date
FROM
#tableNotes t
OUTER APPLY t.form_questions.nodes('/RESULT/QUESTIONS/QUESTION') AS R(Q)
WHERE ISNUMERIC(R.Q.value('#id', 'varchar(max)')) <> 0
) a
INNER JOIN [CKOLTP_DEV]..FORM_QUESTION fq ON
fq.form_id = a.form_id AND
fq.question_id = a.questionid
--select * from T_1321_PNAnnotationCommitReport
SET IDENTITY_INSERT T_1321_PNAnnotationCommitReport OFF;
END
Any ideas?
I looked at some comparable inserts we do at work, insert into select and error message, and insert key auto-incremented, and I think I'm doing what they do. Does anyone else see my mistake? Thanks a lot.
To repeat my comment under the question:
The error is literally telling you the problem. You turn change the IDENTITY_INSERT property to ON for the table T_1321_PNAnnotationCommitReport and then omit the column id in your INSERT. If you have enabled IDENTITY_INSERT you need to supply a value to that IDENTITY, just like the error says.
We can easily replicate this problem with the following batches:
CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
SomeValue varchar(20));
GO
SET IDENTITY_INSERT dbo.MyTable ON;
--fails
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
GO
If you want the IDENTITY value to be autogenerated, then leave IDENTITY_INSERT set to OFF and omit the column from the INSERT (like above):
SET IDENTITY_INSERT dbo.MyTable OFF; --Shouldn't be needed normally, but we manually changed it before
--works, as IDENTITY_INSERT IS OFF
INSERT INTO dbo.MyTable (SomeValue)
VALUES('abc');
If you do specifically want to define the value for the IDENTITY, then you need to both set IDENTITY_INSERT to ON and provide a value in the INSERT statement:
SET IDENTITY_INSERT dbo.MyTable ON;
--works
INSERT INTO dbo.MyTable (ID,SomeValue)
VALUES(10,'def');
GO
SELECT *
FROM dbo.MyTable;
IDENTITY_INSERT doesn't mean "Get the RDBMS to 'insert' the value" it means that you want to want to tell the RDBMS what value to INSERT. This is covered in the opening sentence of the documentation SET IDENTITY_INSERT (Transact-SQL):
Allows explicit values to be inserted into the identity column of a table.
(Emphasis mine)

IDENTITY vs SEQUENCE OBJECT IN SQLSERVER

I'm moving my configuration tables from Development environment to Test environment.
I'm using Identity as a primary key for the configuration tables.
Identity has option SET IDENTITY_INSERT [TABLE_NAME] [ON|OFF] that lets you insert values in the Identity column.
Here is an example for the same:
CREATE TABLE test_Identity (
[ID] int Identity (1,1),
[Product Name] nvarchar(50)
)
SET IDENTITY_INSERT test_Identity ON
INSERT test_Identity ([ID], [Product Name]) VALUES (1,'PRODUCT1')
SET IDENTITY_INSERT #test_Identity OFF
The above code lets me insert values specific values in the Identity column.
Now is there a way to insert specific values while using a SEQUENCE OBJECT in SQL Server?
Thanks in Advance !!!
There is no equivalent to identity_insert for sequences. Just insert the desired values normally.
A sequence is just tied to a column with a default constraint and supplies a default value if you don't override it.
There is nothing special about a column with a sequence default it is treated the same as any other column and can have explicit values inserted or be updated.

How to design audit dimension in the data mart using SQL Server 2012

Goal
I aim to create SSIS (ETL) Template that enables audit functionality (Audit Dimension). I've discovered a few ways to implement audit dimension that are described below with some reference links below:
SEQUENCE
Primary Key
Best way to get identity of inserted row?
Environment:
There are millions of rows in a fact tables and packages run a few
times a day.
Incremental ETL gets thousands of rows.
SQL Server 2012 BI edition is used for the BI solution.
Simplified Schema of DimAudit table:
CREATE TABLE [dw].[DimAudit] (
[AuditKey] [int] IDENTITY(1 ,1) NOT NULL,
[ParentAuditKey] [int] NOT NULL,
[TableName] [varchar] (50) NOT NULL DEFAULT ('Unknown'),
[PackageName] [varchar] (50) NOT NULL DEFAULT ('Unknown'),
[ExecStartDate] [datetime] NOT NULL DEFAULT ( getdate()),
[ExecStopDate] [datetime] NULL,
[SuccessfulProcessingInd] [char] (1) NOT NULL DEFAULT ('N'),
CONSTRAINT [PK_dbo.DimAudit] PRIMARY KEY CLUSTERED
(
[AuditKey] ASC
)
) ON [PRIMARY]
ALTER TABLE [dw].[DimAudit] WITH CHECK ADD CONSTRAINT [FK_DimAudit_ParentAuditKey] FOREIGN KEY( [ParentAuditKey])
REFERENCES [dw]. [DimAudit] ( [AuditKey])
GO
ALTER TABLE [dw].[DimAudit] CHECK CONSTRAINT [FK_DimAudit_ParentAuditKey]
GO
Primary Key Option:
Primary key is generated in the audit table and then AuditKey is queried.
Task: Master SQL Audit Generates Key (SQL Task)
INSERT INTO [dw].[DimAudit]
(ParentAuditKey
,[TableName]
,[PackageName]
,[ExecStartDate]
,[ExecStopDate]
,[SuccessfulProcessingInd])
VALUES
(1
,'Master Extract Package'
,?
,?
,?
,'N')
SELECT AuditKey
FROM [dw].[DimAudit]
WHERE TableName = 'Master Extract Package' and ExecStartDT = ?
/*
Last Parameter: ParameterSystem::StartTime
Result Set populates User::ParentAuditKey
*/
Task: Master SQL Audit End (SQL Task)
UPDATE [dw]. [DimAudit]
SET ParentAuditKey = AuditKey
,ExecStopDT = SYSDATETIME()
,SuccessfulProcessingInd= 'Y'
WHERE AuditKey = ?
/*
Parameter: User::ParentAuditKey
*/
SEQUENCE Option:
The sequence option does not select primary key (AuditKey) but uses logic below to create next available AuditKey.
CREATE SEQUENCE dbo . AuditID as INT
START WITH 1
INCREMENT BY 1 ;
GO
DECLARE #AuditID INTEGER ;
SET #AuditID = NEXT VALUE FOR dbo. AuditID ;
Best way to get identity of inserted row?
It feels risky using identity options as ETL packages could be executed in parallel.
Question
What is the recommended practice for audit dimension table and managing keys?
Sequence & primary key options do the job; however, I have concerns about the selecting primary key option because package could be executed the same millisecond (in theory) and therefore, a few primary keys would exist. So, Sequence sounds like the best option.
Is anything better I could do to create Audit Dimension for a data mart?
You could use the OUTPUT syntax:
INSERT INTO [dw].[DimAudit]
(ParentAuditKey
,[TableName]
,[PackageName]
,[ExecStartDate]
,[ExecStopDate]
,[SuccessfulProcessingInd])
OUTPUT inserted.AuditKey
VALUES
(1
,'Master Extract Package'
,?
,?
,?
,'N')
or SCOPE_IDENTITY() which is what I'm personally using:
INSERT INTO Meta.AuditDim (
Date,
UserName,
Source,
SourceType,
AuditType,
ExecutionId,
ExecutionHost,
ParentAuditKey,
FileID
)
VALUES (
GETDATE(),
CURRENT_USER,
#Source,
#SourceType,
#AuditType,
#ExecutionId,
#ExecutionHost,
#ParentAuditKey,
#FileID
);
SELECT AuditKey FROM Meta.AuditDim WHERE AuditKey = SCOPE_IDENTITY();

Using Identity Insert on a linked server

I have created a linked server object in SQL management studio on our on premise SQL box and I can insert into it as following syntax:
insert into [Azure].[budget].dbo.Bill
I want to set identity insert and have tried the following:
SET IDENTITY_INSERT [Azure].[budget].dbo.Bill ON
insert into [Azure].[budget].dbo.Bill
This is yielding the error that there are too many prefixes. Why can I insert into it without the identity insert and is it possible to do this any other way?
I have then changed the identity insert part to be SP as follows:
EXEC [Azure].[budget].dbo.sp_executesql N'SET IDENTITY_INSERT Bill ON'
insert into [Azure].[budget].dbo.Bill
But I am getting a warning about not having permission on the BillID field
You can't use SET IDENTITY INSERT directly in linked server.
You need to use dynamic SQL to SET IDENTITY_INSERT ON
sp_executesql N'SET IDENTITY_INSERT [Azure].[budgetenergy].dbo.Bill ON;insert into [Azure].[budget].dbo.Bill ....';
You can INSERT an identity value into a table with an identity column on a linked server with the "SWITCH TO" trick.
If you haven't used the "SWITCH TO" trick to add and remove identity on a column, it's very quick, even on large tables!
Conceptually you simply create a new SCHEMA exactly like the table you are wanting to INSERT to without the identity defined. Then switch the table to that SCHEMA and do your INSERT. Then switch back to the SCHEMA with the identity defined.
The sample below has been tested on a linked server in AZURE.
All the caveats of using "SWITCH TO" apply (indexes must be the same, drop and recreate foreign keys, etc)
To test, you can run the full script below on an Linked Azure SQL Server database. You'll need to do a find/replace with [LINKED_SERVER_NAME] and [DATABASE_NAME], replacing with your values. On a non-Azure DB you may need to add "ON PRIMARY" to the table creations.
--Let's setup the example by creating a table with an IDENTITY column on the Linked Server
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--INSERT some data into the table
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] ([Name]) VALUES ('Jay')
-- Looks good
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- Create a TABLE with an identical schema, without the identity defined
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] NOT NULL,
[Name] [nchar](10) NULL
)
'
) AT [LINKED_SERVER_NAME]
--Now Use the "SWITCH TO" to move the data to the new table
EXEC('
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
'
) AT [LINKED_SERVER_NAME]
--Drop the old table (It should now be empty, but you may want to verify that if you are unsure here)
EXEC('
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
'
) AT [LINKED_SERVER_NAME]
--Rename the new table back to the old table name
-- NOTE the lack of database and owner identifiers in the new name
-- NOTE the use of double single qoutes (ESCAPED single quotes)
EXEC('
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
-- Now do your IDENTITY INSERTs !!!!
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (888,'Travis')
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (999,'Jay')
--Verify they got put in
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
--Now let's switch it back to our SCHEMA with an IDENTITY
EXEC('
CREATE TABLE [DATABASE_NAME].[dbo].[Example_Table_temp](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nchar](10) NULL
)
ALTER TABLE [DATABASE_NAME].[dbo].[Example_Table] SWITCH TO [DATABASE_NAME].[dbo].[Example_Table_temp]
DROP TABLE [DATABASE_NAME].[dbo].[Example_Table]
EXEC sp_rename ''[DATABASE_NAME].[dbo].Example_Table_temp'',''Example_Table''
'
) AT [LINKED_SERVER_NAME]
--Data is still there
SELECT * FROM [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table]
GO
-- And note you can no longer INSERT the IDENTITY
INSERT INTO [LINKED_SERVER_NAME].[DATABASE_NAME].[dbo].[Example_Table] (ID,[Name]) VALUES (45,'Travis')
GO

SQL insert default value

SQL Server 2000
Say if I have a table like
CREATE TABLE [Message] (
[MessageIdx] [int] IDENTITY (1, 1) NOT NULL ,
[Message] [varchar] (1024) COLLATE Latin1_General_CI_AS NOT NULL ,
[column1] ... ,
[column2] ... ,
... ,
[ValidUntil] [datetime] NULL ,
CONSTRAINT [PK_Message] PRIMARY KEY CLUSTERED
(
[MessageIdx]
) WITH FILLFACTOR = 90 ON [PRIMARY]
) ON [PRIMARY]
GO
Since there're too many columns, so I am trying to insert value without specify column names explicitly. I want to insert a new row with all columns except 'MessageIdx' and 'ValidUntil' not specified. Therefore, I definitely don't want to type all column names.
I tried below statement but it causes error. How can I do that? Thanks.
insert into message values (DEFAULT,'blah',something, ..., DEFAULT);
EDIT: AFAIN, SQL 2005 server you can skip the identity column when inserting. So that will be
insert into message values ('blah',something, ..., DEFAULT);
But is there any work around for SQL server 2000?
you have to specify column names if you use set identity_insert
but you can do this
set identity_insert caconfig..fxmessage on;
insert into message (MessageIdx,[Message],[ValidUntil)
values (1,'blah',GETDATE());
set identity_insert caconfig..fxmessage off;
I assume what you really want is this, it will generate the identity value for you
insert into message ([Message],[ValidUntil) values ('blah',GETDATE());
Don't be lazy. Do it the correct way, which is to specify the column list (excluding the identity column).
Use getdate(), and for IDENTITY columns (if using uniqueidentifier which I see you're not), you can use newid(), and set them in the design-view of the table in the default value. After that you'd simply go:
INSERT INTO Message (Message) VALUES ('blah');

Resources