Insert multiple rows using triggers using three tables - sql

ALTER TRIGGER tr_ItemAccessInsert
ON [dbo].[tbl_InventoryGroup]
AFTER INSERT
AS
BEGIN
DECLARE #ID decimal(18,3), #InventoryID decimal(18,3)
SELECT #ID = [ItemID] FROM [dbo].[tbl_ItemMain]
SELECT #InventoryID = [GroupID] FROM inserted
INSERT INTO tbl_ItemInventoryAccess ([ItemID], [InventoryID], [Value])
VALUES (#ID, #InventoryID, '0.11')
END
this is my query for trigger
i have 10 item in tbl_itemmain so i want to insert all the 10 itemsid in the tbl_inventoryacess please help me with that

You would just use insert . . . select:
insert into tbl_ItemInventoryAccess ([ItemID], [InventoryID], [Value])
select i.??, i.GroupID, '0.11'
from inserted i;
It is unclear how ItemId is determined. I imagine that a table called tbl_ItemMain has more than one row. Perhaps you can just use i.ItemId.

if i am using like
Alter trigger tr_ItemAccessInsert
on [dbo].[tbl_InventoryGroup]
After insert
as begin
Declare #ID decimal(18,3),#InventoryID decimal(18,3)
select #InventoryID=[GroupID] from inserted
insert into tbl_ItemInventoryAccess([ItemID],[InventoryID],[Value]) values((select itemid from tbl_ItemMain) ,#inventoryid,'0')
end
getting an error subquery returned more than one value

Related

Merge not working for insert a record when it's doesn't exist

Can I use Merge to insert a record when it's doesn't exist like below,
MERGE INTO [dbo].[Test] AS [Target]
USING (SELECT DISTINCT [Name] FROM [dbo].[Test]) AS [Source]
ON [Target].[Name] = [Source].[Name]
WHEN NOT MATCHED THEN
INSERT ([Id], [Name])
VALUES (NEWID(), 'Hello');
If the record with value Hello does not exists in table Test, insert it otherwise don't do anything. With above code record is not inserted even I don't have this record in table. And there are no errors.
I know how to accomplish this using insert ... where not exists (...) but am specifically wanting to know how to do it using a merge statement.
The reason your merge statement wasn't working is that you were merging the same table, dbo.Test, back onto itself, so of course there is no missing record.
You can insert a single missing record as follows, where you create a source query to contain the record(s) you wish to insert:
declare #Test table (id uniqueidentifier, [Name] nvarchar(64))
select * from #Test
-- Returns
-- id | Name
-- ----------------------------------------------
MERGE INTO #Test AS [Target]
USING (select 'Hello' [Name]) AS [Source]
ON [Target].[Name] = [Source].[Name]
WHEN NOT MATCHED THEN
INSERT ([Id], [Name])
VALUES (NEWID(), [Name]);
select * from #Test
-- Returns
-- id | Name
-- ----------------------------------------------
-- C1C87CD5-F745-436D-BD8D-55B2AF431BED | Hello
I agree with the answer from Dale K. Its correct.
If I suppose you might have a source_table from where the data needs to get inserted and not to get inserted if the record already exists then you can do the following.
Instead of the MERGE you can
insert
into dbo.Test
(id
,name
)
select top 1
newID()
,'Hello'
from dbo.Test a
where not exists(select 1
from dbo.Test b
where b.name='Hello')

SQL Server : procedure tables cannot insert value null

I want to add 100 storages in a table.
This is my procedure:
CREATE PROCEDURE [add100*sTORAGE]
AS
DECLARE #i int, #start DATETIME, #end DATETIME
SET #start = GETDATE()
SET #i = 1
WHILE #i < 101
BEGIN
INSERT INTO Storage(storage_name)
VALUES (CONCAT('Nume', CONVERT(nvarchar, #i)))
SET #i = #i +1
END
SET #end = GETDATE()
DECLARE #testID INT = (SELECT TOP 1 (TestRunID)
FROM TestRuns
ORDER BY TestRunID DESC)
DECLARE #tableID INT = (SELECT tableID
FROM Tables
WHERE Name = 'Storage')
INSERT INTO TestRunTables (TestRunID, TableID, StartAt, EndAt)
VALUES (#testID, #tableID, #start, #end)
GO
I get an error after its execution:
Msg 515, Level 16, State 2, Procedure add100*sTORAGE, Line 13
Cannot insert the value NULL into column 'TestRunID', table 'OnlineShop.dbo.TestRunTables'; column does not allow nulls. INSERT fails.
When I look in the table, it has been created 99 columns.
I have some empty tables in a relation and this are the inserts of it (maybe here is the cause):
--INSERTS--
-- insert views into "Views"
INSERT INTO Views(Name) VALUES ('View1')
INSERT INTO Views(Name) VALUES ('View2')
INSERT INTO Views(Name) VALUES ('View3')
select * from views
delete from views where ViewID>1
-- insert into "Tests"
INSERT INTO Tests(Name) VALUES ('[add100*Storage-runView1-del100*Storage]')
INSERT INTO Tests(Name) VALUES ('[add100*Product-runView2-del100*Product]')
INSERT INTO Tests(Name) VALUES ('[add100*OrderProduct-runView3- del100*OrderProduct]')
SELECT * FROM Tests
--insert into tables
INSERT INTO Tables(Name) VALUES ('Table1')
INSERT INTO Tables(Name) VALUES ('Table2')
INSERT INTO Tables(Name) VALUES ('Table3')
SELECT * from Tables
-- insert into "testTable"
INSERT INTO TestTables(TestID, TableID, NoOfRows, Position) VALUES (1,1,100,1)
INSERT INTO TestTables(TestID, TableID, NoOfRows, Position) VALUES (3,2,100,1)
INSERT INTO TestTables(TestID, TableID, NoOfRows, Position) VALUES (2,3,100,1)
SELECT * FROM TestTables
-- insert into "testViews"
INSERT INTO TestViews(TestID,ViewID) VALUES (1,1)
INSERT INTO TestViews(TestID,ViewID) VALUES (3,2)
INSERT INTO TestViews(TestID,ViewID) VALUES (2,3)
SELECT * FROM TestViews
What's wrong? Thank you.
The error tells you everything--table TestRunTables has column "TestRunID" which requires that field to have a value. You either need to be sure to insert a value into that field, or alter the column so that it will use a default value when you don't specify it.
This line:
DECLARE #testID INT = (SELECT TOP 1 (TestRunID) FROM TestRuns ORDER BY TestRunID DESC)
will set #testID to null if no records are returned from TestRuns or if the first TestRunID is null. This is probably what you need to fix.

MS SQL Server Last Inserted ID

In my database all tables are using a common table for Sequence(ID_Table).
TABLE_ID has two fields (Common_ID, Table_Name).
If I insert any record in the table, I have to first insert a record in Table_ID(Auto-increment, Table_name) then use that Auto-increment value in my Other Table.
For example, I want to insert in Table_Products which has fields ID(Common_ID), Product_Name, Product_ID(Auto Increment)
I want to do something like this:
INSERT INTO TABLE_ID (Table_NAME), Values (Table_Products)
Get the Inserted ID and use it in Table_Products:
INSERT INTO Table_Products (ID, Product_Name, Product_ID(Auto Increment)
VALUES (ID from TABLE_ID, SomeProduct, Increment)
Try this one -
DECLARE #ID BIGINT
INSERT INTO dbo.TABLE_ID (Table_NAME)
SELECT 'Table_Products'
SELECT #ID = SCOPE_IDENTITY()
INSERT INTO dbo.Table_Products (ID, Product_Name)
SELECT #ID, 'SomeProduct'
You can use an insert statement with the output clause to generate a new Common_ID. Using insert ... select, you can specify that ID in an insert operation:
declare #Common_ID as table(ID int)
insert Table_ID
(Table_Name)
output inserted.Common_ID into #Common_ID
values ('Table_Products')
insert Table_Products
(ID, Product_Name)
select ID
, 'Some Product'
from #Common_ID
Use SCOPE_IDENTITY() after ur insert statementto get the last inserted id.
DECLARE #Product_Id int
INSERT INTO TABLE_ID (Table_NAME) VALUES (Table_Products);
SELECT #Product_Id=SCOPE_IDENTITY();
Insert INTO Table_Products (ID, Product_Name)
VALUES (ID from TABLE_ID, 'SomeProduct')
Dear friend you have to select id of last record inserted
and then pass it in another table so bellow code will help you very well
Insert INTO TABLE_ID (Table_NAME), Values (Table_Products)
DECLARE #ID int;
set #ID = SCOPE_IDENTITY();
Insert INTO Table_Products (ID, Product_Name)
Values (#ID, SomeProduct)
this code will solve your problem i define #ID for your last record id and then insert it in your other table
For MySql use select LAST_INSERT_ID();
All the other answers so far declare intermediary variables for SCOPE_IDENTITY(), but it could be simpler:
INSERT INTO dbo.TABLE_ID (Table_NAME) VALUES 'Table_Products';
INSERT INTO dbo.Table_Products (ID, Product_Name) VALUES (SCOPE_IDENTITY(),'SomeProduct');
You could be also more table-specific using IDENT_CURRENT()
Insert INTO TABLE_ID (Table_NAME), Values (Table_Products)
select #NewID=IDENT_CURRENT('TABLE_ID')
Insert INTO Table_Products (ID, Product_Name, Product_ID
Values (#NewID, SomeProduct, Increment)

Values() constructor in SQL Server 2008 and triggers

I have two tables Employee and Emp_Audit.
On table Employee, I have an AFTER INSERT trigger, which fires when I insert rows into Employee. The function of trigger is to insert the rows into the Emp_Audit table that have been inserted into Employee.
The trigger works fine when I explicitly use 'insert values' for each record to be inserted in Employee as
INSERT INTO Employee_Test VALUES ('Anees',1000);
INSERT INTO Employee_Test VALUES ('Rick',1200);
INSERT INTO Employee_Test VALUES ('John',1100);
INSERT INTO Employee_Test VALUES ('Stephen',1300);
INSERT INTO Employee_Test VALUES ('Maria',1400);
Trigger inserts all these rows inti Emp_Audit -------------GOOD
But when I use values constructor as
insert into dbo.Employee_Test
values ('Kritika', 25000),
('Ritu', 15000),
('Maduri', 7000),
('Dinkar', 7000);
Only the first row ('Kritika', 25000) gets inserted into Emp_Audit
The whole query is as follows:
CREATE TABLE Employee_Test
(
Emp_ID INT Identity,
Emp_name Varchar(100),
Emp_Sal Decimal (10,2)
)
CREATE TABLE Employee_Test_Audit
(
Emp_ID int,
Emp_name varchar(100),
Emp_Sal decimal (10,2),
Audit_Action varchar(100),
Audit_Timestamp datetime
)
-----------------------Trigger------------------------------------
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
declare #empid int;
declare #empname varchar(100);
declare #empsal decimal(10,2);
declare #audit_action nvarchar(200);
select #empid = inserted.Emp_ID
FROM inserted;
select #empname = inserted.Emp_name
from inserted;
select #empsal = inserted.Emp_Sal
from inserted;
set #audit_action = 'Record Inserted after Insert Trigger Fired';
INSERT INTO Employee_Test_Audit
VALUES(#empid, #empname, #empsal, #audit_action, GETDATE());
GO
print('Insert trigger FIRED')
insert into dbo.Employee_Test
values ('Kritika', 25000),
('Ritu', 15000),
('Maduri', 7000),
('Dinkar', 7000);
Yep, what you want is:
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
INSERT INTO Employee_Test_Audit (Emp_ID, Emp_name, Emp_Sal, Audit_Action, Audit_Timestamp)
SELECT Emp_ID,Emp_name,Emp_Sal,
'Record Inserted after Insert Trigger Fired',GETDATE()
from inserted;
Because inserted can contain multiple rows (or no rows), you have to treat it as a table. I've never seen any different behaviour, but there's no guarantee (in your version) that all of the variables would have been assigned values from the same row even.
Also, you really should get into the habit of supplying a column list to the INSERT.
Try this one -
CREATE TRIGGER dbo.trgInsertAfter
ON [dbo].[Employee_Test]
FOR INSERT
AS BEGIN
INSERT INTO dbo.Employee_Test_Audit(Emp_ID, Emp_name, Emp_Sal, ..., ...)
SELECT
i.Emp_ID
, i.Emp_name
, i.Emp_Sal
, 'Record Inserted after Insert Trigger Fired'
, GETDATE()
FROM INSERTED i
END
The reason of why only one record inserted is when you assign value to the variable using select then it don't provide any error and set the value to any arbitrary value in the column.
and also using that method only insert one record. So correct trigger code should be
CREATE TRIGGER trgInsertAfter ON [dbo].[Employee_Test]
FOR INSERT
AS
INSERT INTO Employee_Test_Audit
SELECT Emp_ID,Emp_name,Emp_Sal,
'Record Inserted after Insert Trigger Fired',GETDATE()
from inserted;

Help with T-SQL script: Insert record, then use identity of that insert on another statement?

Just as a preface, I'm not very knowledgeable on T-SQL syntax.
I'd like to create a simple SQL script that will make 3 insert statements.
Insert A
Insert B
Insert C
Insert A statement's identity or "ID" would be needed in insert B statement.
And both the identities Inserts A & B would be needed in Insert C statement.
Pseudo code would look something like:
INSERT INTO tableA
VALUES ('blah', 'blah')
INSERT INTO tableB
VALUES (IDENTITY_FROM_A_INSERT, 'foo')
INSERT INTO tableC
VALUES (IDENTITY_FROM_A_INSERT, IDENTITY_FROM_B_INSERT)
How would I go about writing this script?
Use SCOPE_IDENTITY() after each insert in order to get the identity of the inserted row (in the current session).
I have used two variables to capture the two identities and then insert them into the third table:
DECLARE #Id1 INT
DECLARE #Id2 INT
INSERT INTO tableA VALUES ('blah', 'blah')
SET #Id1 = SELECT SCOPE_IDENTITY()
INSERT INTO tableB VALUES (IDENTITY_FROM_A_INSERT, 'foo')
SET #Id2 = SELECT SCOPE_IDENTITY()
INSERT INTO tableC VALUES (#Id1, #Id2)
scope_identity() is perfect for integer identifiers on single-record insertions (+1 to the other answer btw). However, if you find yourself using a guid/uniqueidentifier (newsequentialid(), newid(), etc) or inserting multiple records at once, you'll need something a little different:
declare #id uniqueidentifier;
-- Table variable for storing your newly inserted identifiers:
declare #NewlyInsertedIds table
(
[Id] uniqueidentifier
);
insert [MyTable]
(
[Blah1]
,[Blah2]
)
-- in the output clause you can access the inserted/deleted pseudo tables:
ouptut inserted.[Id]
into #NewlyInsertedIDs
(
[Id]
)
values
(
'Blah'
,'Blah'
);
select
#id = [Id]
from #NewlyInsertedIds;
Check out the OUTPUT Clause for more information.