How to get last inserted row from a table? - sql

I tried below query but results in more than one row and [SCOPE_IDENTITY] as NULL.What are the alternates?
SELECT TOP 1000
[RTID],xxx,xxx
FROM [RouteTiming]
GO
SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];
GO
SELECT ##IDENTITY AS [##IDENTITY];
GO

Depending on the server version (SQL Server 2005+) you can use the OUTPUT clause:
INSERT INTO tablename (column names)
OUTPUT --this is where you put your select statement to get returned IDs etc.
VALUES (values in here, or you can use a select statememt as per usual)
MSDN Article: OUTPUT Clause (Transact-SQL)
If you are inside a stored procedure or a function, you can use INSERTED table (there is also a DELETED table) which is stored in memory until the scope is completed.
Once you have performed your insert, you can join the inserted table just like any other as long as it is within the same scope. I believe the inserted table has been around since SQL Server 2000, but it is definitely in 2005+.
MSDN Examples: Use the inserted and deleted Tables

Related

Bulk Insert with Table Valued Parameter not working

Need to insert multiple records into a SQL table. If there are duplicates (already inserted records) then I want to ignore them. For sending multiple records from my code to SQL, I am using table valued parameter.
Below is the query. It works during the first insertion when there are no rows in the table. On subsequent insert, no rows are added.
#tvpNewFMdata is the table valued parameter.
INSERT INTO
[dbo].[FMData]
(
[Id],
[Name],
[Path],
[CreatedDate],
[ModifiedDate]
)
SELECT
fm.Id, fm.Name, fm.Path, GETUTCDATE(), GETUTCDATE()
FROM
#tvpNewFMdata AS fm
WHERE
NOT EXISTS
(
SELECT
tbl.[Id]
FROM
[dbo].[FMdata] AS tbl
WHERE
tbl.Id = fm.Id
)
I am unable to locate as to what the cause that the first time insertion works but not the second time.
Tried with even removing the WHERE NOT EXISTS clause and it was only working in the first insertion. Subsequent insertion is not adding any rows to the table.
Is there an error, or just no rows inserted? If there are just no rows being inserted, even with the removed where clause, it sounds like you might be having problems populating the table value param. Have you watched what you are sending into SQL via a breakpoint or SQL Server Profiler?
Instead of where exists, have you tried a left join to fmData, and only inserting where the fmData row is null?
I agree with Damien, this is not bulk insert.
Sorry. My apologies. It was a mistake in my code. There was no issue in the SPROC. I was parameterizing the function and was passing the wrong table valued parameter.

OUTPUT Clause in Sql Server (Transact-SQL)

I Know that OUTPUT Clause can be used in INSERT, UPDATE, DELETE, or MERGE statement. The results of an OUTPUT clause in a INSERT, UPDATE, DELETE, or MERGE statements can be stored into a target table.
But, when i run this query
select * from <Tablename> output
I didn't get any error. The query executed as like select * from tablename with out any error and with same no. of rows
So what is the exact use of output clause in select statement. If any then how it can be used?
I searched for the answer but i couldn't find a answer!!
The query in your question is in the same category of errors as the following (that I have also seen on this site)
SELECT *
FROM T1 NOLOCK
SELECT *
FROM T1
LOOP JOIN T2
ON X = Y
The first one just ends up aliasing T1 AS NOLOCK. The correct syntax for the hint would be (NOLOCK) or ideally WITH(NOLOCK).
The second one aliases T1 AS LOOP. To request a nested loops join the syntax would need to be INNER LOOP JOIN
Similarly in your question it just ends up applying the table alias of OUTPUT to your table.
None of OUTPUT, LOOP, NOLOCK are actually reversed keywords in TSQL so it is valid to use them as a table alias without needing to quote them, e.g. in square brackets.
OUTPUT clause return information about the rows affected by a statement. OUTPUT Clause is used along with INSERT, UPDATE, DELETE, or MERGE statements as you mentioned. The reason it is used is because these statements themselves just return the number of rows effected not the rows effected. Thus the usage of OUTPUT with INSERT, UPDATE, DELETE, or MERGE statements helps the user by returning actual rows effected.
SELECT statement itself returns the rows and SELECT doesn't effect any rows. Thus the usage of OUTPUT clause with SELECT is not required or supported. If you want to store the results of a SELECT statement into a target table use SELECT INTO or the standard INSERT along with the SELECT statement.
EDIT
I guess I misunderstood your question. AS #Martin Smith mentioned its is acting an alias in the SELECT statement you mentioned.
IF OBJECT_ID('tempdelete') IS NOT NULL DROP TABLE tempdelete
GO
IF OBJECT_ID('tempdb..#asd') IS NOT NULL DROP TABLE #asd
GO
CREATE TABLE tempdelete (
name NVARCHAR(100)
)
INSERT INTO tempdelete VALUES ('a'),('b'),('c')
--Creating empty temp table with the same columns as tempdelete
SELECT * INTO #asd FROM tempdelete WHERE 1 = 0
DELETE FROM tempdelete
OUTPUT deleted.* INTO #asd
SELECT * FROM #asd
This is how you can put all the deleted records in to a table. The problem with that is that you have to define the table with all the columns matching the table from which you are deleting. This is how i do it.

SCOPE_IDENTITY for multiple records

The below query inserts many records in a transaction. I want to fetch the newly created incremental identifier and use it in next INSERT statement
For a single record I can use like below
SELECT #new_emp_id= SCOPE_IDENTITY()
What about SCOPE_IDENTITY for multiple records? Or we can insert it into temp table and loop through it?
INSERT EmployeeBenifits(EmployeeId,BenifitID,StartdateTime,EndDateTime)
SELECT #new_emp_id,BenifitID,GetDate(),#PassedEndDate FROM Benifits
INSERT EmployeeBenifitDetails(EmpBenId,Desc)
SELECT EmpBenId,'Created Details' FROM #NewlyInsertedEmplBenifits
You should have a look at the OUTPUT clause:
INSERT INTO dbo.EmployeeBenefits(EmployeeId, BenefitID, StartdateTime, EndDateTime)
OUTPUT Inserted.EmployeeBenefitId, Inserted.EmployeeID, Inserted.BenefitID -- or whatever you want to return here
SELECT
#new_emp_id, BenefitID, GetDate(), #PassedEndDate
FROM
dbo.Benefits
Basically, the OUTPUT clause can return a result set of columns for each row that has been inserted (also works with the DELETE and UPDATE statements).
See MSDN documentation for more details
You can also send the OUTPUT rows to a temporary table (or table variable) to be further processed later on.

SQL INSERT INTO returning autoincrement field

I'm a long time desktop app C++ programmer new to SQL. I need to insert into a table with an autoincrment field, and have that sql statement return the new value for the autoincrement field.
Something LIKE:
INSERT INTO Entrys ('Name','Description')
VALUES ('abc','xyz')
SELECT Entrys.EntryID WHERE EntryID=[THE ONE JUST INSERTED!]
Sorry for being a noob.
Assuming that you're using SQL Server, you can use scope_identity to return "the last identity value inserted into an identity column in the same scope. 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."
INSERT INTO Entrys ('Name','Description') VALUES ('abc','xyz');
SELECT SCOPE_IDENTITY()
select scope_identity
insert into table values ('string value');select scope_identity()
Details here
In SQL Server, you can also use the OUTPUT clause on your INSERT statement:
INSERT INTO Entrys('Name', 'Description')
OUTPUT Inserted.EntryID
VALUES ('abc','xyz')
This will output the newly created IDENTITY field value.
In MySQL you can use LAST_INSERT_ID()
As #marc_s said for SQL Server, in PostgreSQL you can obtain the same behaviour with:
INSERT INTO Entrys ('Name','Description')
VALUES ('abc','xyz')
RETURNING EntryID;
RETURNING is also really useful when you're inserting several tuples and you want all the generated IDs for each of the rows.

Trigger event is fired only once for Microsoft SQL Server 2005 DB if more than one rows updated?

I have a table MyTable with a trigger defined like this:
ALTER TRIGGER [MyTableInsertDeleteUpdate]
ON [dbo].[MyTable]
AFTER INSERT,DELETE,UPDATE
AS
DECLARE #id int;
BEGIN
SELECT #id = ins.id FROM inserted ins;
IF (#id IS NOT NULL)
BEGIN
-- insert a new record to audit table
PRINT 'inserted/updated id: ' + CAST(#id AS VARCHAR);
END
END
I realize that if more than one rows are updated like this,
UPDATE MyTable SET name = 'test rows' WHERE id in (1, 2, 3);
the tigger is called only once and only the firstone in [inserted] is updated. Actually, [inserted] may have more than one rows (3 in this case if id 1, 2,3 exist). In order words, the trigger is not fired on each row. Is that right?
I am using Microsoft SQL Server 2005.
Yeah the trigger is fired once per statement (not once per row) that makes the changes you are subscripting to. It will even fire if no rows where affected.
http://msdn.microsoft.com/en-us/library/ms189799(SQL.90).aspx
As Hojou said, your trigger will fire once per statement rather than once per affected row. This is different to databases like Interbase and Firebird, and threw me when I first started using SQL Server.
The whole point of the inserted and deleted 'virtual' tables is because the events are record-SET based, not row-based.
There are any number of tutorials out there that cover writing sql to process the inserted/deleted tables, but watch out for the shovelware ones. I've seen more than a couple of so-called tutorials that have just been copy/pasted from another database platform and won't actually work in SQL Server as they claim to (one of the top hits for 'SQL Server trigger example' in Google gets it completely wrong for UPDATE statements).
This is a reasonable introduction to Triggers and the concepts required to make sense of the inserted and deleted tables, with an explanation of why you will be missing events in your own example. The Microsoft docs themselves are reasonably useful once you get past their dull, lifeless structure and writing-style.
To insert records to an audit table from an insert you would do something like this in the trigger:
insert auditable (field1, field2, insert_date, insertedBy)
select field1, field2, getdate(), user_Name() from inserted
No fooling around with setting variables just a a plain insert based on a select statment.
Personally I would have a separate trigger for inserts, updates and deletes as you want differnt code for each.