How can I update the data row by row by the loop after insert those records into another table in mssql? - sql

Does anyone know how can I update the data row by row by the loop after insert those records into another table in mssql?
Example:
I have the following table (tableA)
ID Name is_Feeded
1 Alvin 0
2 Ben 0
3 Lee 1
4 David 0
I want to insert those table from tableA to tableB then update the column is_Feeded to 1 in tableA through a loop?
Anyone know how can I do it in mssql?

Assuming SQL Server 2005 or higher, you can do this in a single statement.
UPDATE A
OUTPUT
inserted.ID,
inserted.Name
INTO
dbo.TableB (ID, Name)
SET
A.is_Feeded = 1 -- is fed?
FROM
dbo.tableA A
WHERE
A.is_Feeded = 0
;
A trigger is also possible, but I don't recommend using one if you can avoid it. If you must to use a trigger (such as perhaps a case where you can't control updates to tableA) then:
CREATE TRIGGER TableA_U ON dbo.TableA FOR UPDATE
AS
INSERT dbo.tableB (ID, Name)
SELECT
I.ID,
I.Name
FROM
inserted I
;
To me it is more natural to insert to tableB based on an update to tableA than to update tableA in response to an insert to tableB.

I would write a trigger for tableB. After you insert a row there, the trigger can update the specific value in tableA

First copy data from tableA to tableB
INSERT INTO tableB
SELECT Name, id FROM tableA;
then set is feeded:
UPDATE tableA SET is_feeded = true
and finally you should do this in one transaction (syntax depends on your DB system, e.g. MySQL: http://dev.mysql.com/doc/refman/5.0/en/commit.html)

you should directly add update field is_feeded when inserting data to TABLEB.

CREATE PROCEDURE xxxxx
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON ;
DECLARE #iOK INT ;
SET #iOK = 0 ;
BEGIN TRY
BEGIN TRANSACTION -- Start the transaction
--start Inserting --
INSERT INTO tableB
SELECT Name ,
id
FROM tableA ;
UPDATE tableA
SET is_feeded = true
-- If we reach here, success!
COMMIT
SET #iOK = 1 ;
END TRY
BEGIN CATCH
-- Whoops, there was an error
IF ##TRANCOUNT > 0
ROLLBACK
-- Raise an error with the details of the exception
DECLARE #ErrMsg NVARCHAR(4000) ,
#ErrSeverity INT
SELECT #ErrMsg = ERROR_MESSAGE() ,
#ErrSeverity = ERROR_SEVERITY()
RAISERROR(#ErrMsg, #ErrSeverity, 1)
END CATCH
SELECT #iOK ;
END

Related

How to check column value on insert trigger like Update trigger

I have a update trigger for update status column value change and update other table record and it is working fine. Here is my code
CREATE TRIGGER [dbo].[trgAfterUpdate] ON [dbo].[recharge_request]
FOR UPDATE
AS
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
IF UPDATE (status)
BEGIN
IF #status='Failure'
--My Update Statement
ELSE IF #status='Success'
--My Update Statement
END
Now I'm want to create an insert trigger also for check status column value and perform other table operation. because in some case status column value will not been update to I need to perform some operation on insert if column value is 'Success' or 'Fail'. status column possible values are 'Success', 'Fail', 'Pending' and 'Process'. any help will be appreciated. Thanks in advance!
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
you are not handling cases where multiple rows are being updated.
You need to treat the inserted and deleted as a table that may contains more than 1 row
IF UPDATE (status)
BEGIN
update t
set ....
from inserted i
inner join some_table t on i.somecol = t.anothercol
where t.status = 'Failure'
update t
set ....
from inserted i
inner join some_table t on i.somecol = t.anothercol
where t.status = 'Success'
. . . . . -- other status value
END
My Issue has been resolved here is solution:
CREATE TRIGGER [dbo].[trgAfterInsert] ON [dbo].[recharge_request]
AFTER INSERT
AS
BEGIN
DECLARE #status varchar(50);
SELECT #status=i.status FROM inserted i;
IF #status='Success'
BEGIN
--My Update statement
END
END

Alternative to Iteration for INSERT SELECT UPDATE in a sequence

I have a table with around 17k unique rows for which I need to run these set of statements in sequence
INSERT INTO TABLE1 using MASTERTABLE data (MASTERTABLE have 6 column)
SELECT value of column ID (Primary Key) of newly inserted row from TABLE1
Update that ID value in TABLE2 using a Stored Procedure
I have tried:
while loop: took around 3 hours to complete the execution
cursor: cancelled the query after executing it overnight
In my understanding I can not use JOIN as I need to execute the statements in a sequence
The questions is not detailed enough. The general idea I would like to use something like this
-- create a output table to hold new id, and key columns to join later
DECLARE #OutputTbl TABLE (ID INT, key_Columns in MASTERTABLE)
INSERT INTO TABLE1
OUTPUT INSERTED.ID, MASTERTABLE.key_columns INTO #OutputTbl
SELECT *
FROM MASTERTABLE
UPDATE T2
SET ID = o.ID
FROM TABLE2 t2
INNER JOIN OutputTbl o
ON t2.key_column = o.key_column
Maybe you can consider a TRIGGER on TABLE1 from which to call the stored procedure on TABLE2, and then you can call your INSERT as you wish/need.. one by one or in blocks..
DROP TRIGGER TR_UPD_TABLE2
GO
CREATE TRIGGER TR_UPD_TABLE2 ON TABLE1 AFTER INSERT
AS
BEGIN
SET NOCOUNT ON
DECLARE #columnID INT = NULL
IF (SELECT COUNT(*) FROM INSERTED)=1 BEGIN
-- SINGLE INSERT
SET #columnID = (SELECT columnID FROM INSERTED)
EXEC TableTwoUpdateProcedure #columnID
END ELSE BEGIN
-- MASSIVE INSERT (IF NEEDED)
SET #columnID = 0
WHILE #columnID IS NOT NULL BEGIN
SET #columnID = (SELECT MIN(columnID) FROM INSERTED WHERE columnID > #columnID)
IF #columnID IS NOT NULL BEGIN
EXEC TableTwoUpdateProcedure #columnID
END
END
END
END

If else expression compare not working

i want to perform a compare if #accid2 not equal #accid then roll back action, else perform insert.
My result of this trigger is even that is not match but it still insert into my table.
here is my code:
ALTER TRIGGER [dbo].[TG_checkacctypehtl]
ON [dbo].[Accommodation_Hotel] INSTEAD OF INSERT
AS
DECLARE #accid NVARCHAR(50), #accid2 NVARCHAR(50),#hid NVARCHAR(50),#fsp NVARCHAR(50), #fc NVARCHAR(50), #sr NVARCHAR(50);
SELECT #hid = i.hotel_id FROM INSERTED i;
SELECT #fsp = i.facillities_swimming_pool FROM INSERTED i;
SELECT #fc = i.facillities_catering FROM INSERTED i;
SELECT #sr = i.star_rating FROM INSERTED i;
SELECT #accid2 = i.accommodation_id FROM INSERTED i;
SELECT #accid = accommodation_id FROM [dbo].[Accommodation] WHERE accommodation_type= 'hotel' AND accommodation_id=#accid2;
BEGIN
BEGIN TRAN
SET NOCOUNT ON
PRINT #accid2
PRINT #accid
IF(#accid2 != #accid)
BEGIN
RAISERROR('Record Not Inserted, Accommodation ID is not a Hotel Id',16,1); ROLLBACK; END
ElSE BEGIN
INSERT INTO [dbo].[accommodation_hotel] (hotel_id,facillities_swimming_pool,facillities_catering,star_rating,accommodation_id)
VALUES (#hid,#fsp,#fc,#sr,#accid2);COMMIT;
END
END
*print is for check the value i get.
is that my logic error or my syntax error?
I would rewrite the whole trigger something like this...
ALTER TRIGGER [dbo].[TG_checkacctypehtl]
ON [dbo].[Accommodation_Hotel]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[accommodation_hotel] (hotel_id,facillities_swimming_pool,facillities_catering,star_rating,accommodation_id)
SELECT i.hotel_id
,i.facillities_swimming_pool
,i.facillities_catering
,i.star_rating
,i.accommodation_id
FROM inserted i
WHERE EXISTS ( SELECT 1
FROM [dbo].[Accommodation] a
WHERE a.accommodation_type= 'hotel'
AND a.accommodation_id = i.accommodation_id)
IF EXISTS (SELECT 1 FROM inserted i
WHERE NOT EXISTS ( SELECT 1
FROM [dbo].[Accommodation] a
WHERE a.accommodation_type= 'hotel'
AND a.accommodation_id = i.accommodation_id)
)
BEGIN
RAISERROR('Records with invalid Accommodation ID is not a Hotel Id not inserted',16,1);
END
END
Insert the rows with valid accommodation ids and raise an error if there are any rows with invalid Hotel Ids, Also no need for all those variables.
Also triggers are fired for each transaction, not for each row. Your code assume there will only be one rows inserted ever in the table at a time.
Should be IF(#accid2 <> #accid)

SQL Server after update trigger

I have a problem with this trigger. I would like it to update the requested information
only to the row in question (the one I just updated) and not the entire table.
CREATE TRIGGER [dbo].[after_update]
ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE(),
CHANGED_BY=USER_NAME(USER_ID())
How do I tell the trigger that this applies only to the row in question?
Here is my example after a test
CREATE TRIGGER [dbo].UpdateTasadoresName
ON [dbo].Tasadores
FOR UPDATE
AS
UPDATE Tasadores
SET NombreCompleto = RTRIM( Tasadores.Nombre + ' ' + isnull(Tasadores.ApellidoPaterno,'') + ' ' + isnull(Tasadores.ApellidoMaterno,'') )
FROM Tasadores
INNER JOIN INSERTED i ON Tasadores.id = i.id
The inserted special table will have the information from the updated record.
Try this (update, not after update)
CREATE TRIGGER [dbo].[xxx_update] ON [dbo].[MYTABLE]
FOR UPDATE
AS
BEGIN
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE()
,CHANGED_BY = USER_NAME(USER_ID())
FROM inserted
WHERE MYTABLE.ID = inserted.ID
END
you can call INSERTED, SQL Server uses these tables to capture the data of the modified row before and after the event occurs.I assume in your table the name of the key is Id
I think the following code can help you
CREATE TRIGGER [dbo].[after_update]
ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
UPDATE dbo.[MYTABLE]
SET dbo.[MYTABLE].CHANGED_ON = GETDATE(),
dbo.[MYTABLE].CHANGED_BY = USER_NAME(USER_ID())
FROM INSERTED
WHERE INSERTED.Id = dbo.[MYTABLE].[Id]
END
You should be able to access the INSERTED table and retrieve ID or table's primary key. Something similar to this example ...
CREATE TRIGGER [dbo].[after_update] ON [dbo].[MYTABLE]
AFTER UPDATE AS
BEGIN
DECLARE #id AS INT
SELECT #id = [IdColumnName]
FROM INSERTED
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE(),
CHANGED_BY=USER_NAME(USER_ID())
WHERE [IdColumnName] = #id
Here's a link on MSDN on the INSERTED and DELETED tables available when using triggers: http://msdn.microsoft.com/en-au/library/ms191300.aspx
It is very simple to do that,
First create a copy of your table that your want keep the log for
For example you have Table dbo.SalesOrder with columns SalesOrderId, FirstName,LastName, LastModified
Your Version archieve table should be dbo.SalesOrderVersionArchieve with columns SalesOrderVersionArhieveId, SalesOrderId, FirstName,LastName, LastModified
Here is the how you will set up a trigger on SalesOrder table
USE [YOURDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Karan Dhanu
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE TRIGGER dbo.[CreateVersionArchiveRow]
ON dbo.[SalesOrder]
AFTER Update
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.SalesOrderVersionArchive
SELECT *
FROM deleted;
END
Now if you make any changes in saleOrder table it will show you the change in VersionArchieve table
try this solution.
DECLARE #Id INT
DECLARE #field VARCHAR(50)
SELECT #Id= INSERTED.CustomerId
FROM INSERTED
IF UPDATE(Name)
BEGIN
SET #field = 'Updated Name'
END
IF UPDATE(Country)
BEGIN
SET #field = 'Updated Country'
END
INSERT INTO CustomerLogs
VALUES(#Id, #field)
// OR
-- If you wish to update existing table records.
UPDATE YOUR_TABLE SET [FIELD]=[VALUE] WHERE {CONDITION}
I didn't checked this with older version of sql server but this will work with sql server 2012.
Try this script to create a temporary table TESTTEST and watch the order of precedence as the triggers are called in this order: 1) INSTEAD OF, 2) FOR, 3) AFTER
All of the logic is placed in INSTEAD OF trigger and I have 2 examples of how you might code some scenarios...
Good luck...
CREATE TABLE TESTTEST
(
ID INT,
Modified0 DATETIME,
Modified1 DATETIME
)
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_0] ON [dbo].TESTTEST
INSTEAD OF INSERT,UPDATE,DELETE
AS
BEGIN
SELECT 'INSTEAD OF'
SELECT 'TT0.0'
SELECT * FROM TESTTEST
SELECT *, 'I' Mode
INTO #work
FROM INSERTED
UPDATE #work SET Mode='U' WHERE ID IN (SELECT ID FROM DELETED)
INSERT INTO #work (ID, Modified0, Modified1, Mode)
SELECT ID, Modified0, Modified1, 'D'
FROM DELETED WHERE ID NOT IN (SELECT ID FROM INSERTED)
--Check Security or any other logic to add and remove from #work before processing
DELETE FROM #work WHERE ID=9 -- because you don't want anyone to edit this id?!?!
DELETE FROM #work WHERE Mode='D' -- because you don't want anyone to delete any records
SELECT 'EV'
SELECT * FROM #work
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='I'))
BEGIN
SELECT 'I0.0'
INSERT INTO dbo.TESTTEST (ID, Modified0, Modified1)
SELECT ID, Modified0, Modified1
FROM #work
WHERE Mode='I'
SELECT 'Cool stuff would happen here if you had FOR INSERT or AFTER INSERT triggers.'
SELECT 'I0.1'
END
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='D'))
BEGIN
SELECT 'D0.0'
DELETE FROM TESTTEST WHERE ID IN (SELECT ID FROM #work WHERE Mode='D')
SELECT 'Cool stuff would happen here if you had FOR DELETE or AFTER DELETE triggers.'
SELECT 'D0.1'
END
IF(EXISTS(SELECT TOP 1 * FROM #work WHERE Mode='U'))
BEGIN
SELECT 'U0.0'
UPDATE t SET t.Modified0=e.Modified0, t.Modified1=e.Modified1
FROM dbo.TESTTEST t
INNER JOIN #work e ON e.ID = t.ID
WHERE e.Mode='U'
SELECT 'U0.1'
END
DROP TABLE #work
SELECT 'TT0.1'
SELECT * FROM TESTTEST
END
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_1] ON [dbo].TESTTEST
FOR UPDATE
AS
BEGIN
SELECT 'FOR UPDATE'
SELECT 'TT1.0'
SELECT * FROM TESTTEST
SELECT 'I1'
SELECT * FROM INSERTED
SELECT 'D1'
SELECT * FROM DELETED
SELECT 'TT1.1'
SELECT * FROM TESTTEST
END
GO
CREATE TRIGGER [dbo].[tr_TESTTEST_2] ON [dbo].TESTTEST
AFTER UPDATE
AS
BEGIN
SELECT 'AFTER UPDATE'
SELECT 'TT2.0'
SELECT * FROM TESTTEST
SELECT 'I2'
SELECT * FROM INSERTED
SELECT 'D2'
SELECT * FROM DELETED
SELECT 'TT2.1'
SELECT * FROM TESTTEST
END
GO
SELECT 'Start'
INSERT INTO TESTTEST (ID, Modified0) VALUES (9, GETDATE())-- not going to insert
SELECT 'RESTART'
INSERT INTO TESTTEST (ID, Modified0) VALUES (10, GETDATE())--going to insert
SELECT 'RESTART'
UPDATE TESTTEST SET Modified1=GETDATE() WHERE ID=10-- gointo to update
SELECT 'RESTART'
DELETE FROM TESTTEST WHERE ID=10-- not going to DELETE
SELECT 'FINISHED'
SELECT * FROM TESTTEST
DROP TABLE TESTTEST
First off, your trigger as you already see is going to update every record in the table. There is no filtering done to accomplish jus the rows changed.
Secondly, you're assuming that only one row changes in the batch which is incorrect as multiple rows could change.
The way to do this properly is to use the virtual inserted and deleted tables: http://msdn.microsoft.com/en-us/library/ms191300.aspx
Trigger
special kind of stored procedure
automatically execured/fired when some event Insert/Update/Delete Occures
use when we want some event to happen automatically on certain desirable scenarios
triggers makes use of 2 tables inserted/deleted table in ssms(memory)
ONLY availabe in context of trigger(CANNOT ACCESS Outside the Trigger
when we insert/delete using trigger, a copy of row is maintained in the inserted/deleted table
inserted table - contains updated data |
deleted table - contains old data
Trigger to Update "ModifiedOn" Date Automatically when record in table is modified(UPDATED)
CREATE TRIGGER [dbo].[Trg_TableName_UpdateModifiedOn]
ON [dbo].[TableName]
AFTER UPDATE
AS
BEGIN
UPDATE [dbo].[TableName]
SET [ModifiedOn] = GetDate()
FROM [inserted]
WHERE [inserted].[PrimaryKey] = [dbo].[TableName].[PrimaryKey];
END;
CREATE TRIGGER [dbo].[after_update] ON [dbo].[MYTABLE]
AFTER UPDATE
AS
BEGIN
DECLARE #ID INT
SELECT #ID = D.ID
FROM inserted D
UPDATE MYTABLE
SET mytable.CHANGED_ON = GETDATE()
,CHANGED_BY = USER_NAME(USER_ID())
WHERE ID = #ID
END

How to restrict insertion of value that already exists in other table

I have 2 tables. I need to check before insertion in one table if the value exist in other table.
I suggest that, you should first check the records that is going to be inserted in each request.
Create Proc Testing
as
Set NoCount ON
Set XACT_ABORT ON
Begin Try
Begin Tran
IF Not Exists(SELECT 1 FROM Table2 i JOIN Table1 t ON i.key = t.key)
Begin
//Your insert statement
END
Commit Tran
End Try
Begin Catch
Rollback Tran
End Catch
IF NOT EXISTS ( SELECT * FROM TableA WHERE Col1 = #Value)
INSERT INTO TableB(Col1) SELECT #Value
Using an INSERT trigger perhaps?
I'm not very sure about the syntax.
CREATE TRIGGER InsertTableTrigger ON Table1 FOR INSERT
AS
BEGIN
IF EXISTS ( SELECT 1 FROM Inserted i JOIN Table1 t ON i.key = t.key )
BEGIN
RAISERROR('Transaction Failed.',16,1)
ROLLBACK TRAN "insert on Table1"
END
END
GO
Inserted is used to access the inserting values.