IN statement error in SQL triggers - sql

I have a trigger that insert value to a another table based on a condition,
in my condition thare is an IN statement within IF condition when im trying to insert multiple values using "INSERT INTO SELECT FROM"
it returns following error
"Subquery returned more than 1 value. This is not permitted when..."
here is my code
ALTER TRIGGER [dbo].[WentOut] ON [dbo].[TB_EVENT_LOG]
AFTER INSERT
AS
BEGIN
DECLARE #AID int
SET NOCOUNT ON;
IF ((SELECT nTNAEvent from inserted) IN(1,2,3))
BEGIN
INSERT INTO Cen.WentOutLog (AutoID, nUserID, nOutDateTime,nOutTNAEvent ,nReaderID) select nEventLogIdn,nUserID, nDateTime,nTNAEvent, nReaderIdn from inserted
END
END
it works for single value but not for multiple value inserting "INSERT INTO SELECT FROM"
thanks in advance

As mentioned by Mitch trigger doesn't fire for each row. If am not wrong this is what you need.
ALTER TRIGGER [dbo].[WentOut]
ON [dbo].[TB_EVENT_LOG]
AFTER INSERT
AS
BEGIN
DECLARE #AID INT
SET NOCOUNT ON;
IF EXISTS(SELECT nTNAEvent
FROM inserted
WHERE nTNAEvent IN ( 1, 2, 3 ))
BEGIN
INSERT INTO Cen.WentOutLog
(AutoID,nUserID,nOutDateTime,nOutTNAEvent,
nReaderID)
SELECT nEventLogIdn,nUserID,nDateTime,nTNAEvent,
nReaderIdn
FROM inserted
WHERE nTNAEvent IN ( 1, 2, 3 )
END
IF EXISTS(SELECT nTNAEvent
FROM inserted
WHERE nTNAEvent IN ( 0 ))
BEGIN
--statement
END
END

Related

Mass update on table. Error 'Msg 512 - Subquery returned more than 1 value. ...'

I am trying to execute a mass update on table based on a condition.
UPDATE POHeader
SET POStatus = 'Cancelled'
WHERE POStatus = 'Draft'
AND Created <= DATEADD(DD, DATEDIFF(DD, '', GETDATE())-29, '')
I even tried these which also return the same error:
UPDATE POHeader
SET POStatus = 'Cancelled'
WHERE POID in (18364, 26401, 27284, 28575, 30532, 30599, 33650,
33780, 33783, 33785, 33895, 35644, 35647, 35678,
37400, 37546, 38750, 38758, 40568, 42045, ......)
Please help as the amount to update is reaching thousands and doing it 1 by 1 is not an option.
UPDATE Trigger
ALTER TRIGGER [dbo].[POHeader_UPDATE]
ON [dbo].[POHeader]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[POHeaderLog]
([ActionDate]
,[Action]
,[POID]
,[CustomerName]
,[CustomerCode]
, ...)
VALUES
(GETDATE()
,'Update'
,(select INSERTED.POID from INSERTED)
,(select INSERTED.CustomerName from INSERTED)
,(select INSERTED.CustomerCode from INSERTED)
, ...)
END
The problem is with the trigger code. SQL Server's trigger operate a statement level, so there will be multiple rows in inserted. if the update statement that fired the trigger affected more than one row - hence the error that you are getting.
You can rewrite the trigger code using the insert ... select syntax:
ALTER TRIGGER [dbo].[POHeader_UPDATE]
ON [dbo].[POHeader]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[POHeaderLog]
([ActionDate]
,[Action]
,[POID]
,[CustomerName]
,[CustomerCode]
, ...)
SELECT
GETDATE()
,'Update'
,POID
,CustomerName
CustomerCode,
, ...
FROM inserted;
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)

Error on create trigger: Column name or number of supplied values does not match table definition

I have been doing this trigger to do a merge when inserted on the same table but apparently I keep getting this error :
Column name or number of supplied values does not match table definition.
My trigger:
create trigger [dbo].[Updated_table1]
on [dbo].[table1]
instead of INSERT
AS
BEGIN
set nocount on;
IF(SELECT COUNT(*) FROM INSERTED) = 0
RETURN;
merge into [dbo].[table1] with (HOLDLOCK) as d
using INSERTED as i
on (i.[primarykey] = d.[primarykey])
when not matched then insert
values ('...','...');
END
Any ideas?
Explicitly mention the Target and Source column names in your insert statement....
Something like this ........
create trigger [dbo].[Updated_table1]
on [dbo].[table1]
instead of INSERT
AS
BEGIN
set nocount on;
IF(SELECT COUNT(*) FROM INSERTED) = 0
RETURN;
merge into [dbo].[table1] with (HOLDLOCK) as d
using INSERTED as i
on (i.[primarykey] = d.[primarykey])
when not matched then
insert (d.Column1,d.Column2,d.Column3,d.Column4,...)
values (i.Column1,i.Column2,i.Column3,i.Column4,...)
END
ALTER TRIGGER tr_Emp_forInsert
On Emp
For Insert
AS
BEGIN
Declare #Id int
select #Id = ID from inserted
insert into EmpAudit
values('New employee with ID = ' + cast (#Id as nvarchar(5)) + ' is added at '
+ cast (Getdate () as nvarchar(20)))
end
Column name or number of supplied values does not match table definition.

Adding a counter to count the number of rows are inserted in table

I'm trying to do an insert statement, but I am checking if the data has been inserted before, and if so, it will not insert the row in the table. After this is complete, I want to return the number of rows that actually were inserted. Can anyone help with adding a counter? I'm using SQL Server 2012.
My query is as follows :
If NOT EXISTS (Select Id from #List where Id = cast(#IG_Id as int))
BEGIN
SET #Sql =
'INSERT INTO '+#List+' (Id,Id,LCode,CellNumber,WorkNumber,HomeNumber)
VALUES ('''+#CId+''','''+#LId+''','''+#LCode+''','''+#MobileNumber+''','''+#BusinessNumber+''','''+ #HomeNumber+''')'
print #Sql END
try this
If NOT EXISTS (Select Id from #List where Id = cast(#IG_Id as int))
BEGIN
INSERT INTO #List (Id,Id,LCode,CellNumber,WorkNumber,HomeNumber)
VALUES (#CId, #LId, #LCode, #MobileNumber, #BusinessNumber, #HomeNumber)
END
SELECT ##ROWCOUNT as NumberOfInsertedRows
actually, since you have only one list of values to insert, ##ROWCOUNT can be only 0 or 1
edit: to show how to insert from another table
INSERT INTO #List (Id,Id,LCode,CellNumber,WorkNumber,HomeNumber)
select Id,Id,LCode,CellNumber,WorkNumber,HomeNumber
from [MyDataSetTable]
where CAST([MyDataSetTable].IG_Id as int) not in (select Id from #List)
SELECT ##ROWCOUNT as NumberOfInsertedRows

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

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