SQL Server If Not Exists insert in a recursive manner - sql

I am new to SQL Server. Working with version 2014.
I have a table with GUID as the key. I have an insert statement
IF NOT EXISTS (select guid from table)
insert into table (,,) values (,,);
In this case, the insert will work if the guid does not exist; if it exists, I need to generate a new guid and perform the insertion. This does not stop with just two levels. I need to check for every guid that is generated and then insert accordingly. How do I do this with a query or, in the worst case, a stored procedure?

Alter the table make the GUID column auto generated. Then you don't have check for its existence every time during insertion.
CREATE TABLE Your_Table
(
Guid_ID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
Column_1 ...
)
If you cannot alter the table then
;with cte as
(
select newid(),value1,value2,..
)
Insert into Your_Table(Guid_ID,col1,col2,..)
Select newid(),value1,value2,..
from cte C
Where not exists (select 1 from Yourtable b where b.Guid_ID = c.Guid_ID )

Related

Update identity column sql [duplicate]

I have a MS SQL 2005 database with a table Test with column ID. ID is an identity column.
I have rows in this table and all of them have their corresponding ID auto incremented value.
Now I would like to change every ID in this table like this:
ID = ID + 1
But when I do this I get an error:
Cannot update identity column 'ID'.
I've tried this:
ALTER TABLE Test NOCHECK CONSTRAINT ALL
set identity_insert ID ON
But this does not solve the problem.
I need to have identity set to this column, but I need to change values as well from time to time. So my question is how to accomplish this task.
You need to
set identity_insert YourTable ON
Then delete your row and reinsert it with different identity.
Once you have done the insert don't forget to turn identity_insert off
set identity_insert YourTable OFF
IDENTITY column values are immutable.
However it is possible to switch the table metadata to remove the IDENTITY property, do the update, then switch back.
Assuming the following structure
CREATE TABLE Test
(
ID INT IDENTITY(1,1) PRIMARY KEY,
X VARCHAR(10)
)
INSERT INTO Test
OUTPUT INSERTED.*
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'
Then you can do
/*Define table with same structure but no IDENTITY*/
CREATE TABLE Temp
(
ID INT PRIMARY KEY,
X VARCHAR(10)
)
/*Switch table metadata to new structure*/
ALTER TABLE Test SWITCH TO Temp;
/*Do the update*/
UPDATE Temp SET ID = ID + 1;
/*Switch table metadata back*/
ALTER TABLE Temp SWITCH TO Test;
/*ID values have been updated*/
SELECT *
FROM Test
/*Safety check in case error in preceding step*/
IF NOT EXISTS(SELECT * FROM Temp)
DROP TABLE Temp /*Drop obsolete table*/
In SQL Server 2012 it is possible to have an auto incrementing column that can also be updated more straightforwardly with SEQUENCES
CREATE SEQUENCE Seq
AS INT
START WITH 1
INCREMENT BY 1
CREATE TABLE Test2
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY,
X VARCHAR(10)
)
INSERT INTO Test2(X)
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'
UPDATE Test2 SET ID+=1
Through the UI in SQL Server 2005 manager, change the column remove the autonumber (identity) property of the column (select the table by right clicking on it and choose "Design").
Then run your query:
UPDATE table SET Id = Id + 1
Then go and add the autonumber property back to the column.
Firstly the setting of IDENTITY_INSERT on or off for that matter will not work for what you require (it is used for inserting new values, such as plugging gaps).
Doing the operation through the GUI just creates a temporary table, copies all the data across to a new table without an identity field, and renames the table.
This can be done using a temporary table.
The idea
disable constraints (in case your id is referenced by a foreign key)
create a temp table with the new id
delete the table content
copy back data from the copied table to your original table
enable previsously disabled constraints
SQL Queries
Let's say your test table have two additional columns (column2 and column3) and that there are 2 tables having foreign keys referencing test called foreign_table1 and foreign_table2 (because real life issues are never simple).
alter table test nocheck constraint all;
alter table foreign_table1 nocheck constraint all;
alter table foreign_table2 nocheck constraint all;
set identity_insert test on;
select id + 1 as id, column2, column3 into test_copy from test v;
delete from test;
insert into test(id, column2, column3)
select id, column2, column3 from test_copy
alter table test check constraint all;
alter table foreign_table1 check constraint all;
alter table foreign_table2 check constraint all;
set identity_insert test off;
drop table test_copy;
That's it.
DBCC CHECKIDENT ( ‘databasename.dbo.orders’,RESEED, 999)
you can change any identity column number with this command,and also you can start that field number from every number you want.for example in my command i ask to start from 1000 (999+1)
hope that it would be enough...good luck
If the column is not a PK you could always create a NEW column in the table with the incremented numbers, drop the original and then alter the new one to be the old.
curious as to why you might need to do this... most I've ever had to futz with Identity columns was to backfill numbers and I just ended up using DBCC CHECKIDENT ( tablename,RESEED,newnextnumber)
good luck!
Identity modifying may fail depending on a number of factors, mainly revolving around the objects/relationships linked to the id column. It seems like db design is as issue here as id's should rarely if ever change (i'm sure you have your reasons and are cascasding the changes). If you really need to change id's from time to time, I'd suggest either creating a new dummy id column that isn't the primary key/autonumber that you can manage yourself and generate from the current values. Alternately, Chrisotphers idea above would be my other suggestion if you're having issues with allowing identity insert.
Good luck
PS it's not failing because the sequential order it's running in is trying to update a value in the list to an item that already exists in the list of ids? clutching at straws, perhaps add the number of rows+1, then if that works subtract the number of rows :-S
If you need to change the IDs occasionally, it's probably best not to use an identity column. In the past we've implemented autonumber fields manually using a 'Counters' table that tracks the next ID for each table. IIRC we did this because identity columns were causing database corruption in SQL2000 but being able to change IDs was occasionally useful for testing.
You can insert new rows with modified values and then delete old rows. Following example change ID to be same as foreign key PersonId
SET IDENTITY_INSERT [PersonApiLogin] ON
INSERT INTO [PersonApiLogin](
[Id]
,[PersonId]
,[ApiId]
,[Hash]
,[Password]
,[SoftwareKey]
,[LoggedIn]
,[LastAccess])
SELECT [PersonId]
,[PersonId]
,[ApiId]
,[Hash]
,[Password]
,[SoftwareKey]
,[LoggedIn]
,[LastAccess]
FROM [db304].[dbo].[PersonApiLogin]
GO
DELETE FROM [PersonApiLogin]
WHERE [PersonId] <> ID
GO
SET IDENTITY_INSERT [PersonApiLogin] OFF
GO
First save all IDs and alter them programmatically to the values you wan't, then remove them from database and then insert them again using something similar:
use [Name.Database]
go
set identity_insert [Test] ON
insert into [dbo].[Test]
([Id])
VALUES
(2)
set identity_insert [Test] OFF
For bulk insert use:
use [Name.Database]
go
set identity_insert [Test] ON
BULK INSERT [Test]
FROM 'C:\Users\Oscar\file.csv'
WITH (FIELDTERMINATOR = ';',
ROWTERMINATOR = '\n',
KEEPIDENTITY)
set identity_insert [Test] OFF
Sample data from file.csv:
2;
3;
4;
5;
6;
If you don't set identity_insert to off you will get the following error:
Cannot insert explicit value for identity column in table 'Test' when
IDENTITY_INSERT is set to OFF.
I saw a good article which helped me out at the last moment .. I was trying to insert few rows in a table which had identity column but did it wrongly and have to delete back. Once I deleted the rows then my identity column got changed . I was trying to find an way to update the column which was inserted but - no luck. So, while searching on google found a link ..
Deleted the columns which was wrongly inserted
Use force insert using identity on/off (explained below)
http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do-i-update-the-value-of-an.aspx
Very nice question, first we need to on the IDENTITY_INSERT for the specific table, after that run the insert query (Must specify the column name).
Note: After edit the the identity column, don't forget to off the IDENTITY_INSERT. If you not done, you cannot able to Edit the identity column for any other table.
SET IDENTITY_INSERT Emp_tb_gb_Menu ON
INSERT Emp_tb_gb_Menu(MenuID) VALUES (68)
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF
http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html

Insert data from one table to another table while the target table has a primary key

In SQL Server I have a table as RawTable (temp) which gets fed by a CVS, let's say it has 22 columns in it. Then, I need to copy existing records (ONLY FEW COLUMNs NOT ALL) into another table as Visitors which is not temporary table.
Visitor table has an ID column as INT and that is primary key and incremental.
RawData table
id PK, int not null
VisitorDate Varchar(10)
VisitorTime Varchar(11)
Visitors table
VisitorID, PK, big int, not null
VisitorDate, Varchar(10), null
VisitorTime Varchar(11), null
So I did:
insert into [dbo].[Visitors] ( [VisitorDate], [VisitorTime])
select [VisitorDate], [VisitorTime]
from RawTable /*this is temp table */
Seems SQL Server doesn't like this method so it throws
Msg 515, Level 16, State 2, Line 1
Cannot insert the value NULL into column 'VisitorID', table 'TS.dbo.Visitors'; column does not allow nulls. INSERT fails. The statement has been terminated.
How can I keep Sql Server not to complain about the primary key? this column as you know better will be fed by sql server itself.
Any idea?
Just because your visitors table has an ID column that is the primary key doesn't mean that the server will supply your ID values for you. if you want SQL to provide the ID's then you need to alter the table definition and make the visitorsId column an IDENTITY column.
Otherwise, you can psuedo-create these id's during the insert with the ROW_NUMBER function -
DECLARE #maxId INT;
SELECT #maxId = (SELECT MAX(visitorsId) FROM dbo.visitors);
INSERT INTO [dbo].[Visitors] ( [visitorsId],[VisitorDate], [VisitorTime])
SELECT #maxId + ROW_NUMBER() OVER (ORDER BY visitorDate), [VisitorDate], [VisitorTime]
from RawTable /*this is temp table */

sql current date constraint

I need to add a constraint to one table in my database. The table name is Experience. And there is a column named ToDate. Every time the select statement executes like following.
select ToDate from Experience
It should return current date.
So every time select statement executes, the ToDate column get updated with current date.
I know I can do this with some type of sql trigger but is there a way to do it by sql constraint.
like
alter table add constraint...
Any help will be appreciated.
Thanks
You can use a computed column. That's specified like colname as <expression>:
create table t1(id int, dt as getdate());
insert t1 values (1);
select * from t1;
To add contraint ...
create table tbl (id int identity, dt datetime, colval varchar(10))
ALTER TABLE dbo.tbl
ADD CONSTRAINT col_dt_def
DEFAULT GETDATE() FOR dt;
Example of inserting to the table ..
insert into dbo.tbl(colval)
select 'somevalue'
select * from dbo.tbl
The result will be ..
id dt colval
1 2014-08-19 13:31:57.577 somevalue
You cannot use a constraint, because a constraint is basically a rule on what can go in the table, how the table can relate to others, etc. It has no bearing on the data in the table once it goes into the table. Now if I am understanding you correctly, you want to update the ToDate column whenever you select that column. Now you can't use a trigger either as mentioned here and here. They suggest a stored procedure where you would use an update followed by an insert. This is probably my preferred SQL method to go with if you have to use it repeated, which you seem to have to do. Though Andomar's answer is probably better.
Try this link code make help full
http://www.sqlatoms.com/queries/how-to-use-the-getdate-function-in-sql-server-3/
CREATE TABLE ProductOrders
(
OrderId int NOT NULL PRIMARY KEY IDENTITY,
ProductName nvarchar(50) NOT NULL,
OrderDate datetime NOT NULL DEFAULT GETDATE()
)

add an identity column to existing table as the primary key and change order

I have a table that has over 7 million records in it. The table does not have a primary key. I would like to add a new identity column and set this as the primary key. I tried adding the column using SSMS, then I set it as the primary key. I called this new column Id.
This almost worked, however I wanted to change the default order of the table to be based another column, for instance a date time column in descending order. Is this possible? Perhaps I need to use a temp table and the ROW_NUMBER() function.
However, I am not very good at SQL. Can someone help?
I also need to have a rollback script so I can get back to the original table.
Here is one more idea:
Step1 - Create temporary clustered index on "date time column in descending order"
CREATE CLUSTERED INDEX ix_YourTableTEMP ON YourTable (DateTimeColumn DESC)
Step2 - Add identity column. Now the IDs should be in order of previously created index - although I don't think there is 100% guarantee on this.
ALTER TABLE YourTable ADD IdColumn INT IDENTITY(1,1)
Step3 - Drop temporary index
DROP INDEX ix_YourTableTEMP ON YourTable
Step4 - Create new clustered PK on new column
ALTER TABLE YourTable
ADD CONSTRAINT PK_YourTable PRIMARY KEY CLUSTERED (IdColumn)
The Link Martin Smith has given is probably the best answer, but here is an alternative:
-- CREATE TABLE WITH SOME DATA IN
CREATE TABLE T (X INT);
INSERT T VALUES (1), (2), (3);
-- CREATE A CLONE OF THIS TABLE, ADDING AN IDENTITY COLUMN
-- USING ORDER BY TO AFFECT THE ORDER OF THE INSERT
SELECT ID = IDENTITY(INT, 1, 1),
T.*
INTO T_Clone
FROM T
ORDER BY X DESC;
-- DROP ORIGINAL TABLE
DROP TABLE T;
-- RENAME CLONE TABLE TO ORIGINAL TABLE NAME
EXECUTE SP_RENAME 'dbo.T_Clone', 'T', 'OBJECT';
-- SELECT FROM TABLE TO CHECK RESULTS
SELECT *
FROM T;
To rollback:
ALTER TABLE T DROP COLUMN ID;
EDIT
It has been pointed out that SELECT ID = IDENTITY(INT, 1, 1).. INTO.. FROM .. ORDER BY ... does not guarantee the order of the insert. So it would appear that the fail safe option is to create your clone table using CREATE TABLE syntax and adding the IDENTITY column:
CREATE TABLE T_Clone
( ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY,
<your columns>
);
INSERT T_Clone (<your columns>)
SELECT <your columns>
FROM T
ORDER BY ...;
Then carry on with the Drop and rename as above. I can find no documentation to say this method is not reliable for ordering the insert, if it proves to still not be reliable you could use:
SET IDENTITY_INSERT T_Clone ON;
INSERT T_Clone (ID, <your columns>)
SELECT ROW_NUMBER() OVER(ORDER BY ...),
<your columns>
FROM T;
SET IDENTITY_INSERT T_Clone OFF;
Then reseed T_CLone after the insert.

How do I insert into a table and get back the primary key value?

I have a primary key set up to auto increment.
I am doing multiple queries and I need to retrieve that primary key value to use as a foreign key in another table (IsIdentity = TRUE).
Is there any elegant way to get back the primary key value when I do an insert query? Right now I am requerying and getting the highest value in that column which seems really hacky.
Any suggestions?
If you are using SQL Server 2005 or later, you can use the OUTPUT clause.
create table T(
pk int identity primary key,
dat varchar(20)
);
go
insert into T
output inserted.pk
values ('new item');
go
drop table T;
The output can be directed to a table as well as to the client. For example:
create table T(
pk int identity primary key,
dat varchar(20)
);
create table U(
i int identity(1001,1) primary key,
T_pk int not null,
d datetime
);
go
insert into T
output inserted.pk, getdate()
into U(T_pk,d)
values ('new item'), ('newer item');
go
select * from T;
select * from U;
go
drop table T, U;
Beginning with SQL Server 2008, you can use "composable DML" for more possibilities.
insert into YourTable values (...)
get the new PK with scope_identity()
select scope_identity()
INSERT INTO YourTable (1, 2, etc.)
OUTPUT inserted.yourIDcolumn
VALUES (value1, value2, value...)
Note: This is for MS SQL 2005 and greater
SCOPE_IDENTITY() is probably what you want. It returns the ID of the last record inserted by the same code context in which it executes.
IDENT_CURRENT('tablename') is subject to concurrency issues. That is, there's no guarantee that another record won't be inserted between the INSERT and the call to IDENT_CURRENT.
I must confess, I'm not sure to what source of amazement the VillageIdiot's outburst refers, but I myself am quite astonished that this question does not appear to be a duplicate at all.
holy crap!!!
just call SCOPE_IDENTITY() function:
insert into your_talble(col1,col2) values('blah','more blah')
select scope_identity()
because selecting highest value will return error if any other statement make an insert. the function scope_identity() returns the identity created in current context (that is by your statement)
You should use scope_identity(). And I recommend to wrap insert statement and scope_identity() into transaction.