SQL Server 2012 Trigger - sql-server

Hey guys thank you in advance for any help,
I have this trigger in my SQL Server 2012 database
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
GO
And as you can see it should update 2 values the "tag" row and the "data" row once something is inserted in the table, however its only updating the "data" row.
If i just select this piece of code and run/debug it, it actually updates both rows, any idea why this is hapening ?
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE dbo.textos
SET tag = UPPER(#tag)
WHERE ID_texto = #ID
END
BEGIN
UPDATE dbo.textos
SET data = GETDATE()
WHERE ID_texto = #ID
END
Once again thank you in advance for your help and time.

I assume that you are performing the following query simply to get the inserted row:
SELECT MAX(ID_texto) FROM dbo.textos
That won't work, as others have pointed out. If you insert more than one row at once, only the last in the set will be modified by the trigger.
Do a JOIN on the INSERTED table to get the new rows, then another JOIN on semantickeyphrasetable(textos, *) to get the tag values. Something like this:
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
UPDATE T
SET tag = UPPER(K.keyphrase), data = GETDATE()
FROM dbo.textos T
JOIN INSERTED ON INSERTED.ID_texto = T.ID_texto
LEFT JOIN (
SELECT TOP 1 document_key, keyphrase
FROM semantickeyphrasetable(textos, *)
) K ON K.document_key=T.ID_texto
END
GO

Triggers will basically trigger once for each batch operation, so you should perform your logic based on this reality. This is also in SQL spirit, which favors (read as performs better) set based operations.
All inserted items are stored into a special table, called inserted, so you should join with this table to know what are the exact records that were touched:
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag)
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
BEGIN
UPDATE Dest
SET data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END
The above is not tested, but should help you get an idea on how to proceed to actually update records that were inserted.

Did this answer ever get solved?
If not, why not just add both updates in one line instead of having 2 BEGIN...END blocks?
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
BEGIN
DECLARE #ID INT
SET #ID = ( SELECT MAX(ID_texto) FROM dbo.textos)
DECLARE #tag NVARCHAR(MAX)
SET #tag = ( SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key=#ID)
BEGIN
UPDATE Dest
SET tag = UPPER(#tag), data = GETDATE()
FROM dbo.textos Dest
JOIN inserted I ON I.ID_texto = Dest.ID_texto
WHERE ID_texto = #ID
END
END

Use the below code. In your case I think the trigger is firing before semantickeyphrasetable TABLE insertion done. So updating nothing in first begin as #tag is empty.
Its better to put the trigger in child table.(If we need to update Parent table with child table data.)
USE Teste_TextMining
CREATE TRIGGER Noticia07032016 ON dbo.textos
AFTER INSERT
AS
DECLARE #ID INT
,#tag NVARCHAR(MAX)
SELECT #ID = ID_texto
FROM INSERTED
SET #tag = (
SELECT TOP 1 keyphrase
FROM semantickeyphrasetable(textos, *)
WHERE document_key = #ID
)
UPDATE dbo.textos
SET tag = UPPER(#tag)
,
SET data = GETDATE()
WHERE ID_texto = #ID
GO
Note: When multiple insertion done, it will fail.

Related

insert data into sql table and get recent inserted iD and insert data in same table from different table

Here is the situation that I have to insert profile photos in the SQL table. But here are 2 scenarios the condition
if user is inserting photo and data from front end. Its working perfectly fine.
if user is skip the photo and just inserting his biography then in that case the default image should be inserted by default. I tried to do in front end Just adding dummy image in if else condition, but in DMZ server for some reason this is creating problem, on local server its working good.
Here is the Query...
ALTER PROCEDURE [dbo].[SavePhysicianBiodata]
-- Add the parameters for the stored procedure here
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if( #ID is null OR #ID='')
begin
--if not image then deafult image will be applied
if((#Physician_ImageType is null or #Physician_ImageType='') and
(#Physician_ImageFileName is null or #Physician_ImageFileName='') )
begin
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic)
values(#Physician_Bio, #Physician_Mnemonic)
set #ID = SCOPE_IDENTITY()
update [dbo].[Physician_Biodata]
set Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
else
begin
-- Insert statements for procedure here when user adds photo as well
insert into Physician_Biodata(Physician_Bio, Physician_Mnemonic,
Physician_Image, Physician_ImageType, Physician_ImageFileName)
values(#Physician_Bio, #Physician_Mnemonic,
#Physician_Image,#Physician_ImageType,#Physician_ImageFileName)
end
end
else
begin
update [dbo].[Physician_Biodata]
set Physician_Bio=#Physician_Bio,
Physician_Mnemonic=#Physician_Mnemonic,
Physician_Image=#Physician_Image,
Physician_ImageType=#Physician_ImageType,
Physician_ImageFileName=#Physician_ImageFileName
where ID=#ID
end
END
In this query I also tried insert query which is given below
insert into Physician_Biodata(ID, Physician_Image, Physician_ImageType, Physician_ImageFileName)
select #ID, dd.Physician_Image,dd.Physician_ImageType,dd.Physician_ImageFileName from DefaultImage as dd
join Physician_Biodata
on Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
where Physician_Biodata.ID = #ID
but getting error during execute procedure
Msg 544, Level 16, State 1, Procedure dbo.SavePhysicianBiodata, Line 35 [Batch Start Line 2]
Cannot insert explicit value for identity column in table 'Physician_Biodata' when IDENTITY_INSERT is set to OFF.
If somebody can help me it would be great.. Thanks in advance.
Yes I have already changed the first insert statement (removed ID) and
updated the 2nd query
set #ID = IDENT_CURRENT('Physician_Biodata')
update Physician_Biodata
set Physician_Biodata.Physician_Image= DefaultImage.Physician_Image, Physician_Biodata.Physician_ImageType= DefaultImage.Physician_ImageType, Physician_Biodata.Physician_ImageFileName=DefaultImage.Physician_ImageFileName from Physician_Biodata, DefaultImage where Physician_Biodata.ID=#ID
and it worked
It appears that Physician_Biodata's ID column is an IDENTITY, hence the exception you have.
Changing this...
INSERT INTO Physician_Biodata (
ID, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
#ID,
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
To this...
INSERT INTO Physician_Biodata (
Physician_Image, Physician_ImageType, Physician_ImageFileName
)
SELECT
dd.Physician_Image,
dd.Physician_ImageType,
dd.Physician_ImageFileName
FROM DefaultImage AS dd
JOIN Physician_Biodata
ON Physician_Biodata.Physician_ImageFileName = dd.Physician_ImageFileName
WHERE
Physician_Biodata.ID = #ID;
Will make your "explicit value" exception go away as in your INSERT you are attempting to insert #ID into ID which is an identity column. You also use ID = #ID in your WHERE clause, which makes inserting #ID pointless as this would be a chicken-and-egg issue.
On another note, if #Physician_ImageType and #Physician_ImageFileName are both NULL going in, they'll still be NULL on your UPDATE given your existing SP's logic.
I've taken a little liberty to tidy/simplify your T-SQL and added a note about what I've questioned.
ALTER PROCEDURE [dbo].[SavePhysicianBiodata] (
#ID int,
#Physician_Bio nvarchar(MAX),
#Physician_Mnemonic nvarchar(MAX),
#Physician_Image image,
#Physician_ImageType nvarchar(MAX),
#Physician_ImageFileName nvarchar(MAX)
)
AS
BEGIN
SET NOCOUNT ON;
IF ISNULL( #ID, '' ) = ''
BEGIN
--if not image then deafult image will be applied
IF ISNULL( #Physician_ImageType, '' ) = '' AND ISNULL( #Physician_ImageFileName, '' ) = ''
BEGIN
INSERT INTO Physician_Biodata ( Physician_Bio, Physician_Mnemonic )
VALUES ( #Physician_Bio, #Physician_Mnemonic ) ;
SET #ID = SCOPE_IDENTITY();
/*
Where are you setting the values for #Physician_Image, #Physician_ImageType, and #Physician_ImageFileName? These are still NULL?
*/
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
ELSE BEGIN
-- Insert statements for procedure here when user adds photo as well
INSERT INTO Physician_Biodata (
Physician_Bio, Physician_Mnemonic, Physician_Image, Physician_ImageType, Physician_ImageFileName
)
VALUES (
#Physician_Bio, #Physician_Mnemonic, #Physician_Image, #Physician_ImageType, #Physician_ImageFileName
);
END
END
ELSE BEGIN
UPDATE [dbo].[Physician_Biodata]
SET
Physician_Bio = #Physician_Bio,
Physician_Mnemonic = #Physician_Mnemonic,
Physician_Image = #Physician_Image,
Physician_ImageType = #Physician_ImageType,
Physician_ImageFileName = #Physician_ImageFileName
WHERE
ID = #ID;
END
END

SQL Server trigger Insert/Update specific column

Point is to make a trigger which will:
Check the configuration table which contains a column ConnectionField nvarchar(50)
It should return the string value (columnName) which will be used as a key
So on insert/update on table Workers, the code should set my Xfield value to the value from column ConnectionField, read from the Configuration table.
In short since this is all messy. I want to be able to let my end user to write down in configuration which column he will use as unique (Worker ID, SNSID, Name etc... ) based on his pick trigger need to put that field value to my Xfield
Don't ask why. It's really confusing.
I've written a trigger which will do that but it just is stuck somewhere in an infinite loop
CREATE TRIGGER [dbo].Tr_ConnectionField
ON [dbo].Workers
FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
DECLARE #ID BIGINT
DECLARE #tmpUpit CURSOR;
DECLARE #ConFieldSETUP NVARCHAR(50)
-- Here I will read the field from configuration which will be used as key
SET #ConFieldSETUP = (SELECT TOP 1 ISNULL(ConnectionField, 'SNSID')
FROM ConfigurationTable)
BEGIN
SET #tmpUpit = CURSOR LOCAL SCROLL FOR
SELECT i.id FROM inserted i
OPEN #tmpUpit
END
FETCH NEXT FROM #tmpUpit INTO #ID
WHILE ##fetch_status = 0
BEGIN
-- Here I will use the configuration columns value to my Xfield
UPDATE Workers
SET Xfield = (SELECT #ConFieldSETUP
FROM Workers cld
WHERE cld.Id = #ID)
WHERE Id = #ID
END
FETCH NEXT FROM #tmpUpit INTO #ID
DEALLOCATE #tmpUpit
Try
CREATE TRIGGER [dbo].Tr_ConnectionField ON [dbo].Textt
FOR INSERT, UPDATE AS
SET NOCOUNT ON;
DECLARE #ConFieldSETUP nvarchar(50);
-- Stop recursion for the trigger
IF TRIGGER_NESTLEVEL(OBJECT_ID('dbo.Tr_ConnectionField')) > 1
RETURN;
-- Here i will read the field from configuration which will be used as key
SET #ConFieldSETUP = (SELECT TOP 1 ISNULL(ConnectionField, 'SNSID')
FROM ConfigurationTable
-- ORDER BY ...
);
-- Update Xfield depending on configuration
UPDATE w
SET Xfield = CASE #ConFieldSETUP
WHEN 'SNSID' THEN w.SNSID
WHEN 'Name' THEN w.Name
...
END
FROM Workers w
JOIN inserted i ON i.Id = w.Id;

How do you pass identify value to out parameter for an UPDATE?

So far I have something like the following.
However I'm not sure what to do when I perform UPDATE - from another question here I found that you need to store the OUTPUT INSERTED result to a table because the update (or insert) may affect multiple rows? I tried using SCOPE IDENTITY but it return NULL on the UPDATE. Anyway if I use the table - then how do I get an individual integer that I can pass to the out parameter? Or do I have change the out parameter to a different type like a collection?
ALTER PROCEDURE [Data].[UpdateRecord]
#theValue decimal(4,2) = NULL,
#updatetime datetimeoffset(7),
#maxintervaltime datetimeoffset(7),
#recordID int = NULL output
AS
declare #mytable as TABLE
(
Id int
)
begin tran
if exists (select * from Data.theValue with (updlock,serializable) where Data.theValue.maxintervaltime = #maxintervaltime)
begin
update Data.theValue set theValue = #theValue, updatetime = #updatetime, maxintervaltime = #maxintervaltime
where Data.theValue.maxintervaltime = #maxintervaltime
-- OUTPUT INSERTED.id into #mytable (this line is wrong)
end
else
begin
insert into Data.theValue(theValue, updatetime, maxintervaltime) values(#theValue, #updatetime, #maxintervaltime);
SET #recordID = SCOPE_IDENTITY();
end
commit tran
The output clause should be placed between update and from/where clause. UPDATE can affect multi rows so you have to ensure your logic is correct.
update Data.theValue set theValue = #theValue, updatetime = #updatetime, maxintervaltime = #maxintervaltime
OUTPUT INSERTED.id into #mytable
where Data.theValue.maxintervaltime = #maxintervaltime
SET #recordID = top 1 id from #mytable

Trigger not working when inserting multiple records

I have the following trigger working correctly when I insert one record on table Pedidos.
However, when I insert multiple records I get a 512 error message. I've searched around for details about inserting multiple records and triggers, but not found an answer to my problem.
The trigger reads the inserted records and finds values from other tables to modify the value of the column situacion in table planificaciones.
Am I totally wrong in the way I'm trying to do this? Is there any obvious problems in my trigger?
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA ON dbo.pedidos after insert as begin if ##ROWCOUNT = 0
return
set nocount on
declare #v_idpla int,
#v_situacion nvarchar(12),
#v_nombre nvarchar(50),
#v_almacen nvarchar(50),
#v_status_pedido nvarchar(4);
set #v_almacen = (select almacen_pedido from inserted);
set #v_nombre =(select cliente from inserted);
set #v_status_pedido = (select status_pedido from inserted);
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion
where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones
where dia_entrega >= GETDATE() and situacion <> 'Departed'
and nombre like '%'+#v_almacen +'%'+ #v_nombre);
if(#v_idpla is not null)
begin
--select Timespan=SYSDATETIME() from inserted;
select ##rowcount;
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
end
UPDATE & SOLVED: Looking on tanner suggestion i do the next update on code and works, but i think some one can find this more clear and useful. In suggested by tanner, says cursor not best way to do this and the best option is a Join. In my case this insert never goes more than 50 inserts at same time.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
after insert as
begin
declare #v_idpla int,#v_situacion nvarchar(12),#v_nombre nvarchar(50),#v_almacen nvarchar(50), #v_status_pedido nvarchar(4)
DECLARE c_cursor CURSOR FAST_FORWARD FOR SELECT ALMACEN_PEDIDO, CLIENTE, STATUS_PEDIDO FROM INSERTED;
OPEN c_cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
--declared and open cursor chargin values to variables
while ##fetch_status = 0
begin
-- set values to variables from anothers tables
set #v_situacion = (select top 1 nombre from dbo.StatusPlanificacion where STATUS_PEDIDO = #v_status_pedido);
set #v_idpla = (select top 1 id from dbo.Planificaciones where dia_entrega >= GETDATE() and
situacion <> 'Departed' and nombre like '%'+#v_almacen +'%'+ #v_nombre);
--check value not null for assigned variable and do update to the value
if(#v_idpla is not null)
begin
UPDATE DBO.Planificaciones
SET situacion = #v_situacion
WHERE id = #v_idpla;
end
--move to the next row of cursor
fetch next from c_cursor into #v_almacen,#v_nombre,#v_status_pedido
end
CLOSE c_cursor
DEALLOCATE c_cursor
end
Not sure if the code is 100% correct but should give you an idea..
inserted is a dataset with all rows of that batch. You just need to think as set based operation.
CREATE TRIGGER TRG_INS_PL_SYNC_STATUS_PLA
ON dbo.pedidos
AFTER INSERT
AS
BEGIN
UPDATE p
SET
situacion = i.nombre
FROM DBO.Planificaciones p
INNER JOIN (
SELECT
v_idpla.id
v_situacion.nombre
FROM INSERTED I
CROSS APPLY (
select top 1
SP.nombre
from dbo.StatusPlanificacion SP
where
SP.STATUS_PEDIDO = I.STATUS_PEDIDO
) v_situacion
CROSS APPLY (
select top 1
Pla.id
from dbo.Planificaciones Pla
where
Pla.dia_entrega >= GETDATE() and
Pla.situacion <> 'Departed' and
Pla.nombre like '%'+I.ALMACEN_PEDIDO +'%'+ I.CLIENTE
) v_idpla
) I ON
P.id = I.id
END

Update Large Number of rows in sql server

I'm trying to update a column in a table which has ~90,000 rows. Is there is any optimized way to update the table?
I have added necessary indexes.. so that no table scans/lookups are not happening. But still it takes much time to run (1hr).
My scenario:
DECLARE #ParentID NVARCHAR(100),
#Con_ERID INT
DECLARE #MaxCount INT,
#MinCount INT,
#Id INT
SELECT #MaxCount = MAX(Id) from [dbo].[ParentIDStaging] where Type='grid'
SET #MinCount = 1
WHILE #MinCount <= #MaxCount
BEGIN
SELECT #Id = ConID FROM [dbo].[ParentIDStaging] WHERE Id = #MinCount and Type = 'grid'
IF #Id IS NOT NULL
BEGIN
SELECT #Con_ERID = ErId FROM Context (NOLOCK) Where ConId = #Id
SELECT #ParentID = Identifier FROM Recording (NOLOCK) where ErId = #Con_ERID
BEGIN TRAN
UPDATE [ParentIDStaging] WITH (ROWLOCK)
SET [ParentID] = #ParentID
WHERE ContentType = 'grid'
AND ConID = #Id
COMMIT
END
SET #MinCount = #MinCount + 1
END
Looping is slow. Try doing it in one update with include the relevant other tables using joins. Your query can probably be writen like this (don't know your actual schema):
UPDATE PS
SET PS.ParentID = Recording.Identifier
FROM ParetnIDStaging PS
JOIN Context on (Context.ConId = PS.ConId)
JOIN Recording on (Recording.ErId = Context.ErId)
WHERE ...
It is because you are looping and updating one record at a time and using explicit locks/transactions.
Without knowing your underlying structure - I would bet you could do what you are trying with an update from a select.
UPDATE ParentIDStaging
SET parentIdStaging.ParentID=recording.Identifier
from ParentIDStaging
join Context on context.ConId = ParentIDStaging.ConId
join recording on contect.erid=recording.erId
WHERE parentIdStaging.ContentType = 'grid'
AND parentidStaging.Type='grid'

Resources