Create a SQL Trigger to alter multiple rows into another table? - sql

I'm using databases to connect with PowerApps and PowerBI and I had a question about triggers.
I have a table (Table A) that contains three columns: ID, TotalQty & Date. I would like to create a trigger based on the three main row actions: Insert, Delete & Update.
Example: New row is inserted into Table A from PowerApps (ID = 1000000 & TotalQty = 3 & Date = Today)
This should fire the trigger three times to insert a row into Table B (with rows ID, QrderQty, and Date):
ID = 1000000, OrderQty = 1 of 3, Date = Today
ID = 1000000, OrderQty = 2 of 3, Date = Today
ID = 1000000, OrderQty = 3 of 3, Date = Today
Similarly, if the date column is updated on Table A for this row, I need the three corresponding rows to update their respective date values as well. Or if the row in Table A is deleted, I need the three rows to be removed.
Could anybody give me an example query of this?

You need to create a Trigger first this link contains some tutorial on how to create a trigger.
Then according to your question you need to do some kind of loop for generating values for the OrderQty, I have done a while loop in this answer that exists as part of TSQL
Assuming that you create TableA and TableB with following schemas:
create table [dbo].[TableA]
(
ID integer not null,
TotalQty integer not null,
Date Date not null
)
go
create table [dbo].[TableB]
(
ID integer not null,
OrderQty nvarchar(10) not null,
Date Date not null
)
go
You can create the trigger as follows to do the job for you:
CREATE TRIGGER [dbo].[InsertFromAToB]
ON [dbo].[TableA]
AFTER INSERT
AS
BEGIN
Declare #counter as integer;
set #counter=1;
Declare #qty as integer;
set #qty = (Select TotalQty from inserted);
While(#counter <= #qty)
Begin
Insert into TableB(ID,OrderQty,Date) select ID,(CONVERT(nvarchar(10),#counter) + ' of ' + Convert(nvarchar(10),#qty)) as OrderQty,Date From inserted
set #counter=#counter+1;
END
END

Related

SQL Server trigger if update() with condition

I have a table in SQL Server that has 3 columns: ID, NAME, VALUE.
This table has 2 rows with ID=1 and ID=2.
(The value of ID doesn't change).
Every moment of time the value of column VALUE changes. Every time the column VALUE changes, I want to insert this updated value into a table (Device1 for ID=1, Device1 for ID=2).
I created a trigger for updating as if update(VALUE) begin...but it doesn't do the work.
Is there a way to add a condition in if update(VALUE) to work in each row
I used this query
Create Trigger insertIntoDevices
On ITEMS
For Update
As
If Update(VALUE)
Begin
Insert Into table device1
Where ID = 1
Insert Into table device2
Where ID = 2
End
With this query each update in column VALUE inserts VALUE into device1 and device1 and that duplicates values in my tables device1 and device2.
Table creation on the below ;
CREATE TABLE TestTable(
ID INT IDENTITY(1,1),
Name VARCHAR(5),
VALUE NVARCHAR(50)
)
GO
CREATE TABLE device1(
VALUE NVARCHAR(50)
)
GO
CREATE TABLE device2(
VALUE NVARCHAR(50)
)
GO
Insertion for ID=1 and ID=2
GO
INSERT INTO TestTable(Name,Value)
VALUES('Test1','test1'),('TEST2','test2')
Firstly,To find new values for each row you can use 'inserted' but it can be include non-changed data. For example: ID =1,Name='test1' and VALUE='test1' and updation of name column will be also included in inserted.
Secondly,To find old values for each row you can use 'deleted'.
After that we find the values that only includes updation for VALUE.
To Sump Up,
Finding Inserted rows and deleted rows will give us the result of each rows new and old values. We used intersection (INNER JOIN ) to find only changed values.
CREATE TRIGGER [dbo].[insertIntoDevices]
ON [dbo].[TestTable]
AFTER UPDATE
AS
BEGIN
DECLARE #InsertedTable table (
InsertedID INT,
InsertedName VARCHAR(5),
InsertedVALUE NVARCHAR(50)
)
DECLARE #DeletedTable table (
DeletedID INT,
DeletedName VARCHAR(5),
DeletedVALUE NVARCHAR(50)
)
INSERT INTO #InsertedTable(InsertedID,InsertedName,InsertedVALUE)
SELECT ID,[Name],[Value] FROM inserted;
INSERT INTO #DeletedTable(DeletedID,DeletedName,DeletedVALUE)
SELECT ID,Name,Value FROM deleted;
INSERT INTO device1(VALUE)
SELECT UpdatedValue = it.InsertedVALUE
FROM #InsertedTable as it
INNER JOIN #DeletedTable as dt ON it.InsertedID = dt.DeletedID AND ISNULL(dt.DeletedVALUE,'') <> ISNULL(it.InsertedVALUE,'')
WHERE it.InsertedID = 1
INSERT INTO device2(VALUE)
SELECT UpdatedValue = it.InsertedVALUE
FROM #InsertedTable as it
INNER JOIN #DeletedTable as dt ON it.InsertedID = dt.DeletedID AND ISNULL(dt.DeletedVALUE,'') <> ISNULL(it.InsertedVALUE,'')
WHERE it.InsertedID = 2
END
To test I used the updation queries on the below;
--Example 1
UPDATE TestTable
SET Value='selam'
WHERE ID = 1
--Example 2
UPDATE TestTable
SET Value='hi'
WHERE ID = 2

Generating Random Number to autoincrement

I have a number formate as follows 1500 and after an insert of a record, i want the number to go up to 1501.
here is my table:
CREATE TABLE QuoteTable2
(
QuoteID int IDENTITY (1,1) NOT NULL
, QNumber varchar(1500),
);
here is my trigger:
create TRIGGER tr_no ON quotetable2
AFTER INSERT
AS
BEGIN
UPDATE QuoteTable2
SET QNumber = inserted.QNumber +1
FROM inserted
WHERE quotetable2.QuoteID = inserted.QuoteID;
END
GO
my results are always the same number as below:
QuoteID QNumber
1 1501
1 1501
how can i modify the trigger to increment by 1 each time? in the example the quoteID and Qnumber are both the same - sorry for the formatting
You are updating the value from the inserted value, which is 1500, so it is always 1501.
You need to get the value from the source table QuoteTable2 not from the inserted:
UPDATE q
SET q.QNumber = q.QNumber +1
FROM QuoteTable2 as q
INNER JOIN inserted AS i ON q.QuoteID = i.QuoteID;
I suggest to declare that column as a IDENTITY column instead so that it will automatically be incremented.
you can try the next code:
ALTER TRIGGER tr_no ON quotetable2
AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT = (SELECT COUNT(1) FROM quotetable2)
UPDATE QuoteTable2
SET QNumber = inserted.QNumber + #COUNT -1
FROM inserted
WHERE quotetable2.QuoteID = inserted.QuoteID;
END
GO
i count the rows on the table and use the value to get the increment, regards

SQL Server 2008: Sql Insert/Update into another table using insertion IDs output from another table

I have a procedure for insert in multiple dependent tables (update in case record exist). I have input parameters as comma separated string which I am reading in table.
After 1st insertion I am getting InsertedIds in another table variable.
I am struggling over how to do insert in 2nd table. I have following input parameters for 2nd table:
Declare #IdsToBeUpdated table (primary key identity pkey, id int) -- values are 1,-1,3,-1
Declare #CommentsTobeInserted table( primary key identity pkey, comment varchar (max)) -- values are 'com1', 'com2', 'com3'
-1 input in table #IdsToBeUpdated depicts insertion for the corresponding rows in all input tables and value other than -1 depicts that records at that pkey value in all other tables (#CommentsTobeInserted table as in example) have to be updated.
So after first insertion I am getting the inserted ids for rows with -1 value. #InsertedIds = 4,5
So my Ids list logically would become.. 1,4,3,5.
But I am stuck now how to insert/update records in second table respectively.
2nd table would be like follows:
Pkey Primary key identity, commentIds(coming from inserted ids and #IdsToBeUpdated), comments.
I have added one more InsertedIds column in #CommentsTobeInserted. If I could fill it with right InsertedId against correct row, I guess I would be able to do insert/update in 2nd table. And where the value is Id in new column I would do insert, where it's null, I would perform update using #IdsToBeUpdated table.
But currently none of my approach is working. I am new to SQL. Any help would be highly appreciated.
Following is some portion of script for better understanding. I have added first insertion script as well.
USE [Demo]
GO
/****** Object: StoredProcedure [dbo].[USP_NewRequest_Insert] Script Date: 2/11/2016 2:50:34 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[USP_NewRequest_Insert]
-----------------------------------
--------- SomeInput parameters
---------for first insertion omitted
--------------------------------
#IdsToBeUpdated varchar(MAX), --Values are 23|-1|32|-1|-1
#CommentList AS VARCHAR(MAX), --Values 'C2'|'C4'|'C5'|'C6'|'C7'
#MCodeList VARCHAR(MAX), --Values 'M2'|'M4'|'M5'|'M6'|'M7'
#CustomerIdsList VARCHAR(MAX), ----Values 'Cust2'|'Cust4'|'Cust5'|'Cust6'|'Cust7'
#ReturnValue AS INT OUTPUT,
------------------Data is in the order it has to be inserted.. where IDs exist in #IdsToBeUpdated, updation would be done. For -1 values, insertion.
AS
BEGIN
BEGIN TRANSACTION
--------------------------Split input strings aand insert in Table variable----------------------------
declare #MCodes Table (pkey int primary key identity, MCode varchar(20))
insert into #MCodes select s.Item from [dbo].UDF_SplitString(#MCodeList, '|') s
declare #CusCodes Table (pkey int primary key identity, CusCode varchar(200))
insert into #CusCodes select s.Item from [dbo].UDF_SplitString(#CustomerIdsList, '|') s
declare #ReqDetailsIds Table (pkey int primary key identity, Id Int)
insert into #ReqDetailsIds select Convert(INT,RTRIM(LTRIM(s.Item))) from [dbo].UDF_SplitString(#IdsToBeUpdated, '|') s
where s.Item is not null and RTRIM(LTRIM(s.Item)) <>''
declare #ProductComments Table (pkey int primary key identity, Comment Varchar(max), insertedId int null)
insert into #ProductComments(Comment) select s.Item from [dbo].UDF_SplitString(#CommentList, '|') s
DECLARE #intErrorCode int;
------------------------------------------------------------------------------------------------------------
-----------------First Insertion which returns inserted IDs for 2nd insertion
------------------------------------------------------------------------------------------------------------------
---Insert/Update product details in [RequestDetails]
Declare #InsertedIDList Table (pkey int primary key identity, ID int); --------Table to read inserted Ids. Used in query below
-----------------------Insert query in case Detail id = -1
INSERT INTO [dbo].[RequestDetails]
[MCode]
,[CustomerIds]
,[ExpectedVolume]------Some parameters coming for first insertion in input
,[StatusCode])
Output INSERTED.ReqDetailId Into #InsertedIDList(ID)
SELECT A.MCode, B.CusCode, E.Vol,1
FROM #MCodes A
JOIN #CusCodes B ON B.pkey = A.pkey
JOIN #ExpectedVols E ON E.pkey = A.pkey
JOIN #ReqDetailsIds G ON G.pkey = A.pkey
WHERE G.Id = -1 --If id = -1, insert
---------------------------Update Query for rest records
UPDATE [dbo].[RequestDetails]
SET [MCode] = upd.MCode
,[CustomerIds] = upd.CusCode
,[ExpectedVolume] = upd.ExVol
,[StatusCode] = 1
FROM(
SELECT A.MCode, B.CusCode, E.ExVol, G.Id
FROM #MCodes A
JOIN #CusCodes B ON B.pkey = A.pkey
JOIN #ExpectedVols E ON E.pkey = A.pkey
JOIN #ReqDetailsIds G ON G.pkey = A.pkey
WHERE G.Id <> -1
) upd
WHERE upd.Id = dbo.RequestDetails.ReqDetailId
IF(##Error<>0)
BEGIN
SET #intErrorCode = ##Error
GOTO ERROR
END
ELSE
BEGIN
SET #ReturnValue=1
END
---------------------------------------------------------------------------
----------------------------Now similarly I have to do insert/update in Comments Table. But
----------------------------Comments table has RequestDetails Id column as foreign key. So
----------------------------now the challange is to add the rows with Inserted ID where value was = -1
----------------------------in input. We have got the IDs corresponding to -1 values from above insertion
----------------------------in the #InsertedIDList Table variable
-----------------------------------------------------------------------------------------
----------------------------Following is what I have tried so far. But I am not able to insert
----------------------------correct InsertedId against correct record.
----------------------------------------------------------------------------------------
-----------------------Here I tried to insert the new generated ids against corresponding comments in table variable.
-----------------------So that I can perform insert where value is not null. As NULL would be inserted where new ID has not been created
-----------------------and corresponding updated ID exists in input (Values not equal to -1)
-------------------------------------------------------------------------------------------------
Update #ProductComments set insertedId = i.ID from ---------This query is not working
(select A.pkey, B.id as detailId, row_number() over (order by (select 0)) as row_num from
#ProductComments A
JOIN #ReqDetailsIds B ON B.pkey = A.pkey) as mappedNewIds right join
#InsertedIDList i on i.pkey = mappedNewIds.row_num
where mappedNewIds.pkey = [#ProductComments].pkey
----Insert in CommentsTable for New Comments against request
---------------------------------
INSERT INTO [dbo].CommentsTable
( ReqDetailId, Comments, CreatedOn )
SELECT A.insertedId, A.Comment, GETDATE()
FROM #ProductComments A
where A.insertedId is not null
-----Update Query
------------------------------------------------------------------------------------------
UPDATE [dbo].[CommentsTable]
SET [ReqDetailId] = upd.Id
,[Comments] = upd.Comment
,[CreatedOn] = GetDate()
FROM(
SELECT A.Comment, B.Id
FROM #ProductComments A
JOIN #ReqDetailsIds B ON B.pkey = A.pkey
WHERE A.insertedId is not null
) upd
WHERE upd.Id = dbo.CommentsTable.ReqDetailId
END
select * from CommentsTable;
---------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
IF(##Error<>0)
BEGIN
SET #intErrorCode = ##Error
GOTO ERROR
END
ELSE
BEGIN
SET #ReturnValue=1
END
COMMIT TRANSACTION
ERROR:
IF (#intErrorCode <> 0) BEGIN
SET #ReturnValue = 0;
ROLLBACK TRANSACTION
END
END

After Insert trigger Header and Detail tables

I have a program that captures orders into two SQL tables. One is a header table with order info that has OrderID as auto increment PK. The other is a details table which captures vendor, part_number, and quantity data.
I have an after insert trigger on the header table which is suppose to update a table in another database with order info and a total quantity of parts in that order.
Everything works fine except when the trigger goes to calculate the total number of parts in the details table. What is happening is the trigger fires before the data is written to the details table and always returns NULLs for the total quantity of parts. What's the best workaround for this? Am I using a wrong trigger?
OrderHeader Table
ID int
TransCode int
CustID int
StoreID int
Date datetime
OrderDetail
OrderID int
MFG nchar(3)
PartNumber nchar(35)
Qty int
ALTER TRIGGER [dbo].[trig_Update_PRIME]
on [Cleansweep].[dbo].[OrderHeader]
after insert
AS
BEGIN
declare #ID as int
declare #DateInput as date
declare #CustID as int
declare #transcode as int
declare #storeID as int
declare #TotItems as int
select #ID = (select ID from inserted)
select #DateInput = (select date from inserted)
select #CustID = (select CustID from inserted)
select #transcode = (select TransCode from inserted)
select #storeID = (select StoreID from inserted)
set #TotItems = ( select SUM(qty) FROM [Cleansweep].[dbo].[OrderDetail] where OrderID = #ID )
if #transcode = 0
begin
insert into PRIME.dbo.PRIME_RepCalls (Customer, Cores)
values (#CustID, #TotItems)
end
if #transcode = 1
begin
insert into PRIME.dbo.PRIME_RepCalls (Customer, NewReturns)
values (#CustID, #TotItems))
end
END
I belive that there two insert process in your DB - first one is when insert into Header table, and the second when is insert to Details table.
If you do insert Header first - than your trigger works before details of your documents were inserted in Db. That's why SUM can return NULL

Select data, setting a calculated value into a column

I'm selecting data from a table within a trigger (FOR UPDATE). Some rows I'm selecting have been updated by a transaction, that initiated the trigger, and some rows are not. I'd like to write somewhere in the dataset a flag for every row, which value would be calculated as "id IN (SELECT [id] FROM INSERTED)". This flag would show, is a row updated with the last transaction or not.
Is it possible in SQL?
Sure, I can do 2 separate queries, with 2 different conditions, but the trigger perfomance is real bottleneck...
Here's an example for SQL Server:
if object_id('TriggerTest') is not null
drop table TriggerTest
create table TriggerTest (id int identity, name varchar(50), inLastUpdate bit)
insert TriggerTest (name) values ('joe'), ('barrack'), ('george'), ('dick')
go
create trigger dbo.TriggerTestDelete
on TriggerTest
after update
as begin
declare #date datetime
set #date = GETDATE()
update dbo.TriggerTest
set inLastUpdate =
case when id in (select id from inserted) then 1
else 0
end
end
go
update TriggerTest set name = name where id in (1,2)
update TriggerTest set name = name where id in (1,3)
select * from TriggerTest
This prints:
id name inLastUpdate
1 joe 1
2 barrack 0
3 george 1
4 dick 0