SQL - Cannot print values from 'inserted' table - sql-server

I have heard that the 'inserted' table automatically stores the last inserted record of any table temporarily.I was able to get the values from this inserted table when using triggers but not manually as
insert into samantha (id , name) values (11,'has')
select *from inserted
I am getting the error message as
Invalid object name 'inserted'.
Can you please give the reason.Thanks in advance

There is inserted table, but it can be only used with output clause, with something like this:
insert into samantha (id , name)
output inserted.*
values (11,'has')
If you have an identity field and you want the latest value from it, you can use SCOPE_IDENTITY() -function too:
insert into samantha (id , name)
values (11,'has')
select SCOPE_IDENTITY()

try use SELECT LAST_INSERT_ID() from samantha

Related

SQL trigger with IDENTITY_INSERT

I have two tables: Table1 is all the companies, Table2 is companies whose name start with A.
Table1 company (companyId int, companyName varchar(50), companySize int)
Table2 companyStartWithA (companyId int, companyName varchar(50), companySize int)
What I want to do is to create a trigger so that when I insert/update/delete something in Table1, it will automatically do the same in Table2
My code:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA
SELECT *
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
And I get an error:
An explicit value for the identity column in table 'companyStartWithA' can only be specified when a column list is used and IDENTITY_INSERT is ON.
What can I do?
Thanks
The problem is the fact that you're not explicitly specifying the column in the INSERT statement, and using a SELECT * to fill the data. Both are big no-no's - you should always explicitly specify the column that you want to insert into, and you should always explicitly specify the columns that you want to select. Doing so will fix this problem:
CREATE TRIGGER A_TRG_InsertSyncEmp
ON company
AFTER INSERT
AS
BEGIN
INSERT INTO companyStartWithA (companyName, companySize)
SELECT companyName, companySize
FROM INSERTED
WHERE inserted.companyName LIKE 'A%'
END
But as Sean Lange absolutely correctly commented - this should really be just a view rather than a separate table.....
CREATE VIEW dbo.CompanyStartsWithA
AS
SELECT companyId, companyName, companySize
FROM dbo.Company
WHERE Name LIKE 'A%'
and then you don't need any messy triggers or anything - just insert into dbo.Company and all companies with a name that starts with an A will be visible in this view....

Triggers after insert

I have a table that has the following columns, and I cannot modify the schema (i.e. I can't modify the table or add an identity field).
What I want is to create a trigger to update one column to treat it as an identity field.
accountno firstname lastname keyField
jku45555 John Doe 123
Now what I want is when I insert the next record, I grab the KeyFieldId of the previous record and update the newly inserted record to be 124 (keep in mind this a Varchar field).
I need the best possible way of doing this, and like I said modifying the table is not an option. Thanks!
You want to do something like this... For a table named "Foo", with two columns, First Name and KeyFieldId (both varchar), this trigger will do what you want:
-------------------------------------------------------------------------
-- These lines will create a test table and test data
--DEBUG: CREATE TABLE Foo (FirstName varchar(20), KeyFieldId varchar(10))
--DEBUG: INSERT INTO Foo VALUES ('MyName', '145')
--
CREATE TRIGGER test_Trigger ON Foo
INSTEAD OF INSERT
AS
BEGIN
DECLARE #maxKeyFieldId int;
SELECT #maxKeyFieldId = MAX(CAST(KeyFieldId AS int)) FROM Foo;
WITH RowsToInsert AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY (CAST(KeyFieldId AS int))) AS RowNum
FROM inserted
) INSERT INTO Foo (FirstName, KeyFieldId)
SELECT FirstName, #maxKeyFieldId + RowNum
FROM RowsToInsert;
END
Things to note here:
Create an INSTEAD OF INSERT trigger
Find the "max" value of the INTEGER value of your KeyFieldID
Create a CTE that selects everything from the 'inserted' collection
Add a column to the CTE for a Row Number
Do the actual INSERT by adding row number to the max KeyFieldID

SQL Server query - how to insert selected values into another table

Here's what I am trying to do.
This is the select statement
select Id
from tblUsersPokemons
where UserId = 1 and PokemonPlace = 'bag'
Now I want to insert those returned Ids into another table like this:
foreach all returned Ids
insert into tblNpcBattleUsersPokemons values (Id, 1)
How can I do that ?
Like this:
insert into tblNpcBattleUsersPokemons
select Id, 1 from tblUsersPokemons where UserId=1 and PokemonPlace='bag'
This can be done in a single sql call
insert into tblNpcBattleUsersPokemons (id, [whatever the name of the other column is])
select Id, 1 from tblUsersPokemons where UserId=1 and PokemonPlace='bag'
I've used the longhand here because it does not make any assumption about the ordering of columns in the destination table, which can change over time and invalidate your insert statement.
You can insert the set retrieved by a SELECT into another existing table using the INSERT...SELECT syntax.
For example:
INSERT INTO tblNpcBattleUsersPokemons (Id, Val) -- not sure what the second column name was
SELECT Id FROM tblUsersPokemons WHERE UserID = 1 and PokemonPlace='bag';

One Stored Procedure to insert one table and retrieve ID and insert multiple tables

I have 3 tables and columns. ex: Green (userID, Name, Address), Red (userID, TemproraryAddress), Blue (userID, WorkPlace).
I want to insert data into Green while userID is auto incremented int and unique id. After inserting those details want to retrieve userID and insert into Red and Blue Tables in one stored procedure
Note: This example table is to show a sample scenario, not for real world usage...
SQL has a very nice OUTPUT feature.
In this scenario, specify your identity column with an auto incrementing int or default value (such as newid()), do the insert and then use the output as input for your other input queries.
The output table has all the values just inserted and can be queried just as any other table, with the difference being it has your new value immediately available after commit.
INSERT INTO
tblInsertedID(ID)
SELECT * FROM
(INSERT
INTO tblDir(Dir)
OUTPUT inserted.ID
VALUES ('C:\NewDir\')
) InnerTable
DECLARE #userID INT;
INSERT dbo.Green(Name, Address) SELECT #name, #address;
SELECT #userID = SCOPE_IDENTITY();
INSERT dbo.Red(UserID, TemporaryAddress) SELECT #userID, #something;
INSERT dbo.Blue(UserID, WorkPlace) SELECT #userID, #something_else;
Use SCOPE_IDENTITY() to insert value in a variable for user is and then use this variable value in Red/Blue tables.

SQL Server: is it possible to get recently inserted identity column value without table variable

Let's say I have a table
my_table(id int identity(1,1) not null primary key, data varchar(100))
I want to write a procedure that inserts a new row into that table and returns id.
I tried
DECLARE #new_id INT;
SELECT #new_id = id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id)
That code doesn't work (I got "A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed in a SELECT statement that is not the immediate source of rows for an INSERT statement."). However, if I use a table variable, I can do
DECLARE #new_id INT;
DECLARE #tmp_table TABLE(int id);
INSERT INTO #tmp_table
SELECT id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id);
// OR
INSERT INTO my_table(data) OUTPUT inserted.id INTO #tmp_table VALUES ('test') ;
SELECT #new_id = id FROM #tmp_table;
Is it possible to achieve the same functionality without using table variable ?
UPDATE
Thanks for quick responses, +1 to everyone for solution with SCOPE_IDENTITY.
That's probably my fault, I should have asked the question clearly - I do use MERGE (an example would be much longer, so I posted INSERT instead) , not INSERT so SCOPE_IDENTITY doesn't really work for me.
A bit shorter version than nesting in a insert statement is using output...into.
declare #tmp_table table(actiontaken nvarchar(10), id int);
merge my_table
using (values ('test')) as S(data)
on 0=1
when not matched then
insert (data) values (S.data)
output $action, inserted.id into #tmp_table;
I do believe that you should use a table variable from the merge. The output may contain more than one row.
Yes, you can just return SCOPE_IDENTITY after the insert (this is safer than ##IDENTITY due to the scoping differences).
i.e.
INSERT my_table (data) VALUES ('test')
SELECT SCOPE_IDENTITY()
SELECT SCOPE_IDENTITY() will get the last inserted identity value in the scope.
If you use
select ##identity
you will get the last value entered into the identity column from anywhere.
If you want the value entered into the column from the script that just ran, you should use
select SCOPE_IDENTITY()
If you just want the last value inserted into the identity column for a given table from any statement in any session, you should use
select IDENT_CURRENT('tablename')
select ##identity or select SCOPE_IDENTITY() will return the value you're looking for

Resources