SQL Return Inserted Data - sql-server

I want to select back the data I just inserted into the database. I know OUTPUT can be used and we can call INSERTED.[ColumnName] to grab the values that were inserted. Can these values be set to a variable of some kind or given an alias? I do not want to use a TEMP table because I wish to use variables if possible.
It would be nice for the solution to work when the PK is or is not an identity column.
EDIT:
Contacts.PhoneNumberID is a foreign key to PhoneNumber.ID
I want to do both insert statements back to back and I need the ID from PhoneNumber to use for the Contacts.PhoneNumberID
EDIT:
[PhoneNumber].[ID] has a default specified in the database, that is how the ID is being set
Here is what I am looking for:
INSERT INTO [PhoneNumber] (Number)
OUTPUT INSERTED.ID, INSERTED.Number
VALUES ('555-555-5555')
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', {ID From previous insert})
Can we some how alias the insert statement to say:
INSERT INTO [PhoneNumber] (Number)
OUTPUT INSERTED.ID, INSERTED.Number
VALUES ('555-555-5555') as A
I know we cannot actually Alias an insert statement as done above, I am looking for the proper way to do this.
Then you could do this:
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', A.ID)
I am going for a final result of something similar to this:
INSERT INTO [PhoneNumber] (Number)
OUTPUT INSERTED.ID, INSERTED.Number
VALUES ('555-555-5555') as A
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', A.ID)
Reason I am trying to do this:
I wish to put both insert statements in a transaction block, if one of them fails then I can rollback and not commit anything.

For this purpose you need to use IDENT_CURRENT('your_table) function. It returns the last IDENTITY value produced in a table, regardless of the connection that created the value, and regardless of the scope of the statement that produced the value.
IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope.
So your code will look like this:
Declare #last_ident numeric(38,0)
INSERT INTO [PhoneNumber] (Number)
VALUES ('555-555-5555')
SELECT #last_ident = IDENT_CURRENT('PhoneNumber')
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', #last_ident)
More information you can find here
EDIT:
If you need to get non Identity field you should use OUTPUT then
Declare #tbl table(ID int)
INSERT INTO [PhoneNumber] (Number)
OUTPUT INSERTED.ID INTO #tbl
VALUES ('555-555-5555')
Declare #id int
select #id = ID from #tbl
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName',#id)

You can get the latest inserted from SCOPE_IDENTITY().
So your code could look like that:
DECLARE #id AS INT;
INSERT INTO [PhoneNumber] (Number)
VALUES ('555-555-5555')
SELECT #id = SCOPE_IDENTITY();
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', #id)
For DECLARE #id AS INT; you need to change the type of the variable to fit the data type PhoneNumberID column

You could also use Sequence.
Declare #newId int = NEXT VALUE FOR [PhoneNumber_Seq];
Insert into [PhoneNumber] (ID, Number)
values(#newId, '555-555-55555')
INSERT INTO [Contacts] (Name,PhoneNumberID)
VALUES ('SomeName', #newId)

Related

Get inserted timestamp

in our T-SQL database We have some timestamp column, every time we insert or update a record we select the timestamp from the record the same key we inserted or updated.
We want avoid the double search: for update and for select, we tried something like this:
declare #table table(id int, val timestamp not null)
declare #table2 table(val timestamp)
insert #table(id)
output inserted.val into #table2
values (1)
but it does not compile, i have an error in Italian, something like 'a timestamp column can not be set explicitly'
any hint?
The problem is that TIMESTAMP is a data type that is automatically generated and only exposed as read-only. It's based around an incrementing number within the system.
SQL Server: Cannot insert an explicit value into a timestamp column
Try this:
DECLARE #table TABLE(id INT, val TIMESTAMP NOT NULL)
DECLARE #table2 TABLE(val DATETIME)
INSERT #table (id)
OUTPUT inserted.val INTO #table2(val)
VALUES (1)
SELECT
t.id,
t.val,
CONVERT( TIMESTAMP, t2.val ) AS table2_timestamp
FROM
#table AS t,
#table2 AS t2

SQL insert select ##Identity

How to use the ##IDENTITY when I use INSERT SELECT ?
DECLARE #ENTITYID AS BIGINT
INSERT INTO Quiz_QuizQuestion
SELECT #ENTITYID,
#DIFICULTLEVELCODE,
ENTITYID,
#QuizEntityId,
Title,
[Description],
[Description],
Duration
FROM Education_Question
WHERE EntityID = 1 --THIS SELECT RETURN JUST 1 RECORD
SET #ENTITYID = ##IDENTITY
SELECT #ENTITYID // NULL
You need not insert ##IDENTITY into the table in your scenario - you have to CREATE table with IDENTITY field like this:
CREATE TABLE Quiz_QuizQuestion
(
EntityId int IDENTITY NOT NULL,
...
)
GO
DECLARE #ENTITYID AS BIGINT
INSERT INTO Quiz_QuizQuestion
SELECT
#DIFICULTLEVELCODE,
ENTITYID,
#QuizEntityId,
Title,
[Description],
[Description],
Duration
FROM Education_Question
WHERE EntityID = 1 --THIS SELECT RETURN JUST 1 RECORD
SET #ENTITYID = SCOPE_IDENTITY()
SELECT #ENTITYID // NULL
This is copied verbatim from the MSDN page about ##IDENTITY:
"After an INSERT, SELECT INTO, or bulk copy statement completes, ##IDENTITY contains the last identity value generated by the statement. If the statement did not affect any tables with identity columns, ##IDENTITY returns NULL. If multiple rows are inserted, generating multiple identity values, ##IDENTITY returns the last identity value generated." (link). I don't know if you need more information than that.
##identity only gives the last value inserted in an IDENTITY field.
You need to create a IDENTITY field instead :)
try this:
--Create Table
--CREATE TABLE TableName (Col_A INT IDENTITY (1,1), Col_B NVARCHAR(10))
INSERT INTO TableName VALUES ('TEST01')
SELECT ##IDENTITY

SQL Server understand SCOPE_IDENTITY()

I have this piece of code in a stored procedure:
BEGIN
SET #UserId = NULL;
IF (#Username IS NOT NULL)
BEGIN
EXECUTE SP_ADD_USER #Username, #UserId OUTPUT;
END
EXECUTE SP_ADD_ALERT #Name, #AlertType, #AlertId OUTPUT;
INSERT INTO AlertLogs (Datastamp, AlertID, UserID, NotificationMessage)
VALUES (#Datastamp, #AlertId, #UserId, #EmailMessage);
SET #AlertLogId = SCOPE_IDENTITY();
END
#AlertLogId is an output parameter that I want to be assigned to the result of the last insert in AlertLogs table. Do I have to include
INSERT INTO AlertLogs (Datastamp, AlertID, UserID, NotificationMessage)
VALUES (#Datastamp, #AlertId, #UserId, #EmailMessage);
in a new block (a new begin/end scope) in order for SCOPE_IDENTITY() to work correctly ?
(and not report for example the last ID of an inserted record done in SP_ADD_ALERT for example ?)
In your query, SCOPE_IDENTITY() is going to return the last entered identity value into the database, for this scope.
In this instance, it will be the identity for the AlertLogs table, if this has an identity.
A scope is a module: a stored procedure, trigger, function, or batch.
Therefore, two statements are in the same scope if they are in the
same stored procedure, function, or batch.
http://msdn.microsoft.com/en-us/library/ms190315.aspx
You can also use an OUTPUT clause in your insert statement. This means you don't need to worry about scope and you make other (non-identity) information available from the inserted table.
Consider this simple table:
CREATE TABLE [dbo].[SampleTable](
[ID] [int] IDENTITY(1,1) NOT NULL,
[InsertDate] [datetime] NOT NULL,
[Name] [nvarchar](100) NULL
) ON [PRIMARY]
With this default added:
ALTER TABLE [dbo].[SampleTable]
ADD CONSTRAINT [DF_SampleTable_Inserted]
DEFAULT (getdate()) FOR [InsertDate]
You can get values for both the default and the identity from the insert operation.
DECLARE #InsertedDetails TABLE (ID int, InsertDate DateTime);
INSERT INTO SampleTable ([Name])
OUTPUT inserted.ID, inserted.InsertDate
INTO #InsertedDetails
VALUES ('Fred');
DECLARE #ID int;
DECLARE #InsertDate datetime;
SELECT #ID = ID, #InsertDate = InsertDate FROM #InsertedDetails;
PRINT #ID;
PRINT #InsertDate;
Here I've just pulled the values out of the table variable and printed them.

Error when using INSERT INTO with SELECT

I'm trying to compile this stored procedure on MSSQL:
ALTER PROCEDURE [dbo].[sp_Notice_insert]
#type text,
#message text
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO tbl_Notices (id, type, message)
VALUES (NewID(), #type, #message);
DECLARE #noticeid uniqueidentifier;
SET #noticeid = SCOPE_IDENTITY();
INSERT INTO tbl_NoticesInbox (userid, noticeid)
(SELECT id, #noticeid FROM tbl_User WHERE role='Staff');
END
GO
It should insert a "notice" into one table then insert a "notification" into the inbox table, for every 'Staff' user. But when compiling I get this error:
Operand type clash: numeric is incompatible with uniqueidentifier
The 'role' field is nbarchar(10) so I tried N'Staff' as the value too but I get the same error. It doesn't say which types are actually clashing. What am I doing wrong?
The problem is that SCOPE_IDENTITY() returns the last value entered into an IDENTITY column within the current scope, and therefore by default returns a numeric value.
It looks to me like you want to create a NEWID() and use that both to insert the header and related records:
DECLARE #noticeid uniqueidentifier;
SET #noticeid = NEWID();
INSERT INTO tbl_Notices (id, type, message)
VALUES (#noticeid , #type, #message);
INSERT INTO tbl_NoticesInbox (userid, noticeid)
(SELECT id, #noticeid FROM tbl_User WHERE role='Staff');

What happens if I Select SCOPE_IDENTITY() after an insert fails (SQL Server 2005)

The MSDN docs weren't entirely clear on this one. or perhaps I'm not reading them well enough.
If I do an insert (which may insert zero rows), followed by
;SELECT SCOPE_IDENTITY()
And then call the command by ExecuteScalar()...
What will the result be if the Insert doesn't insert any rows?
I want to stop if it fails so that I don't continue on inserting child records to a bad, or wrong parent ID.
If no Identity is inserted SCOPE_IDENTITY() will return null, you can check for the condition you specify by assigning SCOPE_IDENTITY() to a variable and then checking the variables contents.
Illustration
Create Proc SomeInsertToFail(#ID int OUTPUT)
as
Begin
Select #ID = Scope_Identity()
End
Declare #SOMEID int
Exec SomeInsertToFail #SOMEID OUTPUT
Select #SOMEID --This will yield null
It depends upon whether there has been a SUCCESSFUL insert within the current scope.
declare #tb table (i int identity, ky varchar(100));
insert into #tb values('Success');
insert into #tb select ky from #tb where ky = 'Failure';
select SCOPE_IDENTITY(); -- returns 1
select * from #tb
NULL
source: did a SELECT scope_identity() on a blank query (aka no insert)

Resources