INSERT record to SQL table with IDENTITY column - sql

i have this sql table
CREATE TABLE Notes(
NoteID [int] IDENTITY(1,1) NOT NULL,
NoteTitle [nvarchar](255) NULL,
NoteDescription [nvarchar](4000) NULL
) CONSTRAINT [PK_Notes] PRIMARY KEY CLUSTERED
(
NoteID ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
And i want to copy records from a temporary table INCLUDING the NoteID(using sql query)..
this is my script:
SET IDENTITY_INSERT Notes OFF
INSERT INTO Notes (NoteID, NoteTitle,NoteDescription)
SELECT NoteID, NoteTitle,NoteDescription from Notes_Temp
SET IDENTITY_INSERT Notes ON
with this script, i'm getting an error:
Cannot insert explicit value for identity column in table 'Notes' when IDENTITY_INSERT is set to OFF.
is there other way of insert records to a table with identity column using sql query?

Change the OFF and ON around
SET IDENTITY_INSERT Notes ON
INSERT INTO Notes (NoteID, NoteTitle,NoteDescription)
SELECT NoteID, NoteTitle,NoteDescription from Notes_Temp
SET IDENTITY_INSERT Notes OFF

SET IDENTITY_INSERT Notes ON
INSERT INTO Notes
/*Note the column list is REQUIRED here, not optional*/
(NoteID, NoteTitle,NoteDescription)
SELECT NoteID, NoteTitle,NoteDescription from Notes_Temp
SET IDENTITY_INSERT Notes OFF
You're inserting values for NoteId that is an identity column.
You can turn on identity insert on the table like this so that you can specify your own identity values.

Presumably you are using SQL Server (you don't say) and have misunderstood the meaning and purpose of IDENTITY_INSERT. In general, you are not allowed to explicitly set the value of an IDENTITY column, but by setting IDENTITY_INSERT to ON for a table you can temporarily permit such inserts.

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.

Update / Insert records to a table with a MERGE Statement

I did this 3 years ago with DB2 but can't remember how.
All I want to do is Update/Insert a record into a table. Rather than test for its existence and changing my DML, I want to do this with a parameterized insert/update(merge) T-SQL statement. I believe the procedure compiler optimizer will make this the most efficient method.
USE [MY_DB]
GO
/****** Object: Table [dbo].[map_locations] Script Date: 10/11/2015 9:29:26 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[map_locations](
[loc_min_lat] [varchar](5) NOT NULL,
[loc_min_lng] [varchar](6) NOT NULL,
[loc_id] [int] NULL,
[center] [varchar](20) NOT NULL CONSTRAINT [DF__map_locs__call___5E4ADDA8] DEFAULT (''),
CONSTRAINT [PK__map_map_locs__79C80F94] PRIMARY KEY CLUSTERED
(
[map_locations_lat] ASC,
[map_locations_lng] ASC,
[center] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
Simply put, I want to be able to insert a record into the above table if it does not violate the PK but update it if the record (from a PK perspective) exists.
I have been researching and all the MS SQL examples are for two table merges. I am passing in a record via parameters.
I am working in Delphi XE10 (not that that should matter) and the database is MS SQL 2012.
Any help appreciate.
When you say "rather than", I assume you're using Sql Server 2008 or later and are wanting to use its Merge command (apologies for the earlier version of this answer).
Here's a sample TransactSql script (tested and working, but using my table structure) which assumes you know the PK in advance:
declare #id int
select #id = 1
merge table1 as dest
using (values (#id, 'name1'))
as source (id, name)
on dest.id = #id
when matched then
update
set name = source.name
when not matched then
insert ( id, name)
values ( source.id, source.name);
select * from table1
From a Delphi app, you'd want to write that as a parameterized query, or, better, a parameterized call to a stored proc on the server.
These days, no Delphi-tagged q about Sql seems complete without a mention of Sql-Injection, but using a parameterized query should minimise the risk of that.

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

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.

sometimes Identity isn't working

I have a following table
CREATE TABLE [dbo].[test_table]
(
[ShoppingCartID] [int] IDENTITY(1,1) NOT NULL,
[CartTimeoutInMinutes] [int] NOT NULL,
[MaximumOrderLimitPerUser] [int] NOT NULL,
[MaximumOrderLimitPerSession] [int] NOT NULL,
CONSTRAINT [PK_test_table] PRIMARY KEY CLUSTERED
(
[ShoppingCartID] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)
ON [PRIMARY]
GO
Sometimes Identity isn't working, it's start with 0 and sometimes its start with 1.
Thank you in advance.
How are you putting the data in there? If you are using regular INSERT it should start at 1. You can, however, bulk-insert into the table, or otherwise use identity-insert; in which case all bets are off:
create table test (
id int not null identity(1,1),
name varchar(20) not null)
set identity_insert test on
insert test (id, name) values (0, 'abc')
insert test (id, name) values (27, 'def')
set identity_insert test off
select * from test
with output:
id name
----------- --------------------
0 abc
27 def
Or is the problem relating to ##IDENTITY (in which case: use SCOPE_IDENTITY() instead).
Possible
Are you using DBCC CHECKIDENT? This is invoked by some data compare tools (eg Red Gate) and has the following behaviour:
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 uses new_reseed_value as the identity. Otherwise, the next row inserted uses new_reseed_value + the current increment value.
Or: are you using SET IDENTITY_INSERT?
These assume you are looking at the table, rather then using ##IDENTITY (as Mark suggested)