Table insertion by Trigger - sql

Here's the table:
Order [OrderId], [DateTimePlaced], [ProductId], [Quantity]
Invoice [InvoiceId], [invoice_DateTime], [order_Id]
I want SQL Server automatically inserts the data into the Invoice table while I manually insert the data into Order table.
Here is my code:
create trigger invoice_Sync on Order
after insert
as
begin
insert into Invoice (invoice_DateTime,order_Id) select ID,Name,Address
select getdate(),OrderId
from inserted
go
However, after I executed this query, SQL Server gave me an error "The select list for the INSERT statement contains more items than the insert list"
My situation is: The invoice Id is set to be automatically incremented, So I think I should not manually put the Invoice Id into this trigger.
Any suggestions?

You have an extra SELECT there:
create trigger invoice_Sync on Order
after insert
as
begin
insert into Invoice (invoice_DateTime,order_Id)
--select ID,Name,Address, Why is this here?
select getdate(),OrderId
from inserted
end
go

Related

SQL Trigger after update on a single column in different table

i'm creating a SQL trigger which I need to insert a record into a different table after updating it on the first table.
I got the following tables.
Queue table:
Bin table
Till now i've the following SQL query which doesn't compile.
CREATE TRIGGER dbo.MoveBinToQueue
ON dbo.Bins
AFTER UPDATE
AS
IF UPDATE(Status_StatusId)
BEGIN
INSERT INTO dbo.Queues
(
Prio,
Time
Bin_BinId,
Goal_GoalId
)
SELECT
20,
GETDATE(),
inserted.Status_StatusId,
inserted.Goal_GoalId
)
END
You need a FROM clause:
CREATE TRIGGER dbo.MoveBinToQueue
ON dbo.Bins
AFTER UPDATE
AS
BEGIN
IF UPDATE(Status_StatusId)
BEGIN
INSERT INTO dbo.Queues (Prio, Time, Bin_BinId, Goal_GoalId )
SELECT 20, GETDATE(), inserted.Status_StatusId, inserted.Goal_GoalId
FROM inserted;
END
END;

SQL Server use SCOPE_IDENTITY() for insert into with select command

Hello I have one table whose name is
PERSO_DATA(Id,refPerso,,Col1,Col2,Col3,Col4,Col5)
and I have
PERSO_DATA_QUEUE(Id,refPersoData,refVideo)
Firstly I will insert to datas to PERSO_DATA then I will take Id of inserted data and isnsert to another table as refPersoData.
INSERT INTO PERSO_DATA(refPerso,Col1,Col2,Col3,Col4,Col5)
SELECT #refPerso,pa.Col1,pa.Col2,pa.Col3,pa.Col4,pa.Col5 FROM #PERSODATA pa
SET #refPersoData=SCOPE_IDENTITY()
When I write like that i insert all datas but can't take the Id for each data
INSERT INTO PERSO_DATA_QUEUE(refVideoQueue,refPersoData)
SELECT #refVideoQueue,#refPersoData
so code above it add only one.But I want if I have 10 data to insert PERSO_DATA I need to also insert PERSO_DATA_QUEUE table 10 data with inserted Ids.
How can I do this? I couldn't find a solution.
Thanks in advance
Try this code:
CREATE TABLE #temp ([Id] [bigint] NOT NULL);
INSERT INTO PERSO_DATA(refPerso,Col1,Col2,Col3,Col4,Col5)
OUTPUT INSERTED.Id
INTO #temp (Id)
SELECT #refPerso,pa.Col1,pa.Col2,pa.Col3,pa.Col4,pa.Col5
FROM #PERSODATA pa;
INSERT INTO PERSO_DATA_QUEUE(refVideoQueue,refPersoData)
SELECT #refVideoQueue, Id
FROM #temp;
The solution might be combining either cursor or loop and any iterator - like ROW_NUMBER() in your temp table.
Then - use SCOPE_IDENTITY() in it to get created IDENTITY value.

How to get a inserted id in other table from inside a trigger?

I have 3 tables tbl_Users, tbl_Protocol and tbl_ProtocolDetails and inside of my trigger on Users, I have to inserted into Protocol and then insert into ProtocolDetails, but I don't know how work the inserted scope.
Something like that:
CREATE TRIGGER tg_Users ON tbl_Users
AFTER INSERT, UPDATE AS
BEGIN
DECLARE #UserId = Int
DECLARE #ProtocolId = Int
DECLARE #UserDetail = NVARCHAR(255)
SELECT
#UserId = user_id,
#UserDetail = user_detail + '#' + user_explanation
FROM INSERTED
INSERT INTO tbl_Protocol (user_id, inserted_date)
VALUES (#UserId, GetDate())
-- Return Inserted Id from tbl_Protocol into #ProtocolDetail then
INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details)
VALUES (#ProtocolId, #UserDetail)
END
Your trigger has a MAJOR flaw in that you seems to expect to always have just a single row in the Inserted table - that is not the case, since the trigger will be called once per statement (not once for each row), so if you insert 20 rows at once, the trigger is called only once, and the Inserted pseudo table contains 20 rows.
Therefore, code like this:
Select #UserId = user_id,
#UserDetail = user_detail + '#' + user_explanation
From INSERTED;
will fail, since you'll retrieve only one (arbitrary) row from the Inserted table, and you'll ignore all other rows that might be in Inserted.
You need to take that into account when programming your trigger! You have to do this in a proper, set-based fashion - not row-by-agonizing-row stlye!
Try this code:
CREATE TRIGGER tg_Users ON tbl_Users
AFTER INSERT, UPDATE AS
BEGIN
-- declare an internal table variable to hold the inserted "ProtocolId" values
DECLARE #IdTable TABLE (UserId INT, ProtocolId INT);
-- insert into the "tbl_Protocol" table from the "Inserted" pseudo table
-- keep track of the inserted new ID values in the #IdTable
INSERT INTO tbl_Protocol (user_id, inserted_date)
OUTPUT Inserted.user_id, Inserted.ProtocolId INTO #IdTable(UserId, ProtocolId)
SELECT user_id, SYSDATETIME()
FROM Inserted;
-- insert into the "tbl_ProtocolDetails" table from both the #IdTable,
-- as well as the "Inserted" pseudo table, to get all the necessary values
INSERT INTO tbl_ProtocolDetails (protocol_id, protocol_details)
SELECT
t.ProtocolId,
i.user_detail + '#' + i.user_explanation
FROM
#IdTable t
INNER JOIN
Inserted i ON i.user_id = t.UserId
END
There is nothing in this trigger that would handle a multiple insert/update statement. You will need to either use one scenario that will handle multiple records or check how many records were effected with a IF ##ROWCOUNT = 1 else statement. In your example, I would just use something like
insert into tbl_Protocol(user_id, inserted_date)
select user_id, user_detail + '#' + user_explanation
From INSERTED;
As for your detail table, I see Marc corrected his answer to include the multiple lines and has a simple solution or you can create a second trigger on the tbl_Protocol. Another solution I have used in the past is a temp table for processing when I have very complicated triggers.

Insert multiple rows into a table with a trigger on insert into another table

I am attempting to create a T-SQL trigger that will essentially insert x number of rows into a third table based upon the data being inserted into the original table and data contained in a second table; however, I'm getting all sorts of errors in the select portions of the insert statement.
If I comment out this portion [qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns]), IntelliSense gets rid of all the red lines.
Table designs:
Users table - contains user info
skillColumns table - list of all columns possible, filtered on the productGroupID of the user
Skills table - contains the data per user, one row for every columnID in skillColumns
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[cID] in (select [columnID] as [cID] from [qmgmt].[dbo].[skillColumns])
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID]
END
GO
Is what I'm looking to accomplish even possible with a trigger? Can multiple rows be inserted into a table with the in keyword?
UPDATE:
After using the answer provided by J0e3gan, I was able to create a trigger in the opposite direction:
CREATE TRIGGER tr_skillColumns_INSERT_Users
ON [qmgmt].[dbo].[skillColumns]
AFTER INSERT
AS
BEGIN
INTO [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [qmgmt].[dbo].[Users].[userID],
[qmgmt].[dbo].[Users].[displayName],
[iTable].[columnID]
From inserted as [iTable] inner Join
[qmgmt].[dbo].[Users] on
[iTable].[groupID] = [qmgmt].[dbo].[Users].[productGroupID]
Where
[qmgmt].[dbo].[Users].[userID] in (select [userID] from [qmgmt].[dbo].[Users])
END
GO
Yes, this can be done with an AFTER trigger.
The column list is not the correct place for the IN criterion that you are trying to use, which is why it is underlined in red.
Try adding the IN criterion to the JOIN criteria instead:
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[qmgmt].[dbo].[skillColumns].[columnID]
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID] and
[qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns])
END
GO
Alternatively add it to a WHERE clause:
CREATE TRIGGER tr_Users_INSERT
ON [qmgmt].[dbo].[Users]
AFTER INSERT
AS
BEGIN
INSERT into [qmgmt].[dbo].[Skills]([userID], [displayName], [columnID])
Select [iTable].[userID],
[iTable].[displayName],
[qmgmt].[dbo].[skillColumns].[columnID]
From inserted as [iTable] inner join
[qmgmt].[dbo].[skillColumns] on
[iTable].[productGroupID] = [qmgmt].[dbo].[skillColumns].[groupID]
Where
[qmgmt].[dbo].[skillColumns].[columnID] in (select columnID from [qmgmt].[dbo].[skillColumns])
END
GO

Trigger an Insert in another table when i insert a value on a table

I have one table that I log the status from some services.
I need to trigger an insert in another table when this table A receive one insert with the value FALSE.
Let me try to explain a little more:
I Have one table EMAIL into which I insert emails that I want to send. I Have another table LOG that logs one service. If the table LOG receives one insert on field STATUS with the value FALSE I want to trigger one insert in the table EMAIL.
Hi Try this...........
-------------Sample Table
create table [log] (Id int,[status] varchar(10))
create table Email ([Status] varchar(10),id int)
go
------------ Trigger Creation
create trigger tri_log on log
for insert
as
insert into email(id,[status])
select a.[id],a.[status]
from inserted a where a.[status] = 'false'
go
------------------Sample Check
select * from [log]
select * from [email]
-----------insert records for test
insert into [log] values (1,'True')
insert into [log] values (2,'False')
----------verify result
select * from [log]
select * from [email]