Locking From Temp Table - SQL 2008 R2 - sql
I have just implemented a new database on our live environment, this database is fed information by a service brokers from our two transactional databases. When the messages come into the new database we have a series of stored procedures which manipulate the feed for each specific user.
I also have another set of stored procedures which re-manipulate the data by user instead of by vehicle, these are used by our maintenance screens to ensure we can change users visibility of the data.
The below stored procedure keeps locking up I have now amended this sp to update a temp table first and then just undertake one update against the main database, however this has not aided the situation, I have also amended so I can update in smaller batches and if this fails keep retrying until it is successful. This works 100% on our dev environment but on live it keeps locking. The throughput on the servicebrokers is not great enough to register the number of failures, I therefore believe I am locking myself within this sp?
I have included ---'THIS UPDATE KEEPS LOCKING' at the point of failure.
What could be causing this locking behavior?
USE [Isight]
GO
/** Object: StoredProcedure [dbo].[UserVisibilityForVehicles] Script Date: 07/18/2014 14:43:04 **/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[UserVisibilityForVehicles]
-- Add the parameters for the stored procedure here
#Username VARCHAR(50)
WITH RECOMPILE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
PRINT 'UserVisibilityForVehicles Started'
-- Now Start to check security for user.
IF EXISTS ( SELECT ID FROM dbo.SecurityTable WHERE userid = #Username AND Deleted = 0)
BEGIN
CREATE TABLE #VehicleToUsers(ID BIGINT, NewRecord BIT DEFAULT(0))
CREATE CLUSTERED INDEX IDX_VehicleToUsers ON #VehicleToUsers(ID)
CREATE NonCLUSTERED INDEX IDX_NewRecord ON #VehicleToUsers(ID)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT Distinct Veh.[ID]
FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK)
INNER JOIN SecurityTable WITH (NOLOCK) ON Veh.[System] = SecurityTable.[System]
WHERE SecurityType = 1 AND UserID = #Username AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Veh.[ID]
FROM [iSight].[dbo].[Vehicle] Veh WITH (NOLOCK)
INNER JOIN SecurityTable WITH (NOLOCK) ON Veh.[System] = SecurityTable.[System] AND Veh.CurrentSite = SecurityTable.[Site]
WHERE SecurityType = 2 AND UserID = #Username AND SecurityTable.deleted = 0
)
BEGIN
PRINT 'UserVisibilityForVehicles: ' + #Username
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Manufacturer.ManufacturerGroupID = SecurityTable.ManufacturerGroupID AND Vehicle.System = SecurityTable.System
WHERE (SecurityTable.SecurityType = 3) AND (SecurityTable.UserID = #Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID
WHERE (SecurityTable.SecurityType = 4) AND (SecurityTable.UserID = #Username) AND ManufacturerMake.Deleted = 0 AND ManufacturerAgreementSubcustomer.Deleted = 0 AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND
ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON
ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND
SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID AND
SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName
WHERE (SecurityTable.SecurityType = 5) AND (SecurityTable.UserID = #Username) AND (ManufacturerMake.Deleted = 0) AND
(ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0
)
INSERT INTO #VehicleToUsers
( ID )
(
SELECT DISTINCT Vehicle.ID
FROM Manufacturer WITH (NOLOCK) INNER JOIN
ManufacturerAgreementSubcustomer WITH (NOLOCK) ON Manufacturer.ID = ManufacturerAgreementSubcustomer.ManufacturerID INNER JOIN
ManufacturerMake WITH (NOLOCK) ON Manufacturer.ID = ManufacturerMake.ManufacturerID INNER JOIN
Vehicle WITH (NOLOCK) ON ManufacturerMake.Make = Vehicle.Make AND ManufacturerAgreementSubcustomer.Agreement = Vehicle.CurrentAgreement AND
ManufacturerAgreementSubcustomer.Subcustomer = Vehicle.CurrentSubCustomer INNER JOIN
SecurityTable WITH (NOLOCK) ON Vehicle.System = SecurityTable.System AND Manufacturer.ID = SecurityTable.ManufacturerID AND
ManufacturerAgreementSubcustomer.ID = SecurityTable.ManufacturerAgreementSub INNER JOIN
ManufacturerUserAgreementSubcustomer WITH (NOLOCK) ON
ManufacturerAgreementSubcustomer.ID = ManufacturerUserAgreementSubcustomer.ManufacturerAgreementSubcustomerID AND
SecurityTable.UserID = ManufacturerUserAgreementSubcustomer.UserName AND
SecurityTable.ManufacturerID = ManufacturerUserAgreementSubcustomer.ManufacturerID
WHERE (SecurityTable.SecurityType = 6) AND (SecurityTable.UserID = #Username) AND (ManufacturerMake.Deleted = 0) AND
(ManufacturerAgreementSubcustomer.Deleted = 0) AND (ManufacturerUserAgreementSubcustomer.Deleted = 0) AND SecurityTable.deleted = 0
)
END
CREATE TABLE #VehicleToUserCopy(ID BIGINT, vehicleTableID BIGINT, Deleted BIT DEFAULT(1), UpdatedAt DATETIME DEFAULT (GETDATE()), UpdatedBy VARCHAR(50) DEFAULT('UserVisibilityForVehicles-Update'), NextToUpdate BIT DEFAULT(0))
CREATE CLUSTERED INDEX idx_ID ON #VehicleToUserCopy(ID)
CREATE NONCLUSTERED INDEX idx_VehicleTableID ON #VehicleToUserCopy(vehicleTableID)
CREATE NONCLUSTERED INDEX idx_NextToUpdate ON #VehicleToUserCopy(NextToUpdate)
INSERT INTO #VehicleToUserCopy
( ID ,
vehicleTableID ,
Deleted
)
(
SELECT ID, vehicleTableID, Deleted
FROM dbo.VehicleToUser WITH (nolock)
WHERE Username = #Username
)
PRINT 'Starting to do updates'
--Not required as default set to 1
----UPDATE VehicleToUser
----SET DELETED = 1
----,UpdatedAt = GETDATE()
----,UpdatedBy = 'UserVisibilityForVehicles'
----FROM dbo.VehicleToUser WITH (NOLOCK)
----LEFT JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUser.VehicleTableID = UsersVehicles.ID
----WHERE UserName = #Username AND UsersVehicles.ID IS null
PRINT 'Starting to do updates - Set Deleted = 0'
SET LOCK_TIMEOUT 1000 -- set to second
DECLARE #Tries tinyint
UPDATE #VehicleToUserCopy
SET Deleted = 0
FROM #VehicleToUserCopy AS VehicleToUserCopy
inner JOIN #VehicleToUsers AS UsersVehicles ON VehicleToUserCopy.VehicleTableID = UsersVehicles.ID
INSERT INTO VehicleToUser(UserName, VehicleTableID, DELETED, UpdatedAt, UpdatedBy)
(
SELECT DISTINCT #Username, TempVehicle.ID, 0 , GETDATE(), 'UserVisibilityForVehicles-Insert'
FROM #VehicleToUsers AS TempVehicle
LEFT JOIN (
SELECT VehicleTableID
FROM #VehicleToUserCopy WITH (NOLOCK)
) AS [VehicleToUser] ON TempVehicle.ID = [VehicleToUser].VehicleTableID
WHERE [VehicleToUser].VehicleTableID IS null
)
DECLARE #ID bigint
SELECT #ID = ID FROM #VehicleToUserCopy
WHILE ##rowcount > 0
BEGIN
SET ROWCOUNT 1000
SELECT #Tries = 1
WHILE #Tries <= 3
BEGIN
BEGIN TRANSACTION
BEGIN TRY
UPDATE #VehicleToUserCopy SET NextToUpdate = 1
---'THIS UPDATE KEEPS LOCKING'
UPDATE dbo.VehicleToUser
SET Deleted = VehicleToUserCopy.Deleted
, UpdatedAt = GETDATE()
, UpdatedBy = VehicleToUserCopy.UpdatedBy
FROM VehicleToUser
inner JOIN #VehicleToUserCopy AS VehicleToUserCopy ON VehicleToUser.ID = VehicleToUserCopy.ID
WHERE VehicleToUserCopy.NextToUpdate = 1
PRINT 'WORKED'
DELETE FROM #VehicleToUserCopy WHERE NextToUpdate = 1
COMMIT
-- therefore we can leave our loop
BREAK
END TRY
BEGIN CATCH
ROLLBACK --always rollback
PRINT 'Rolled Back '
-- Now check for Blocking errors 1222 or Deadlocks 1205 and if its a deadlock wait for a while to see if that helps
SELECT ERROR_MESSAGE()
IF ERROR_NUMBER() = 1205 OR ERROR_NUMBER() = 1222
BEGIN
-- if its a deadlock wait 2 seconds then try again
IF ERROR_NUMBER() = 1205
BEGIN -- wait 2 seconds to see if that helps the deadlock
WAITFOR DELAY '00:00:02'
END
-- no need to wait for anything for BLOCKING ERRORS as our LOCK_TIMEOUT is going to wait for half a second anyway
-- and if it hasn't finished by then (500ms x 3 attempts = 1.5 seconds) there is no point waiting any longer
END
SELECT #Tries = #Tries + 1 -- increment and try again for 3 goes
-- we carry on until we reach our limit i.e 3 attempts
CONTINUE
END CATCH
END
SELECT #ID = ID FROM #VehicleToUserCopy
End
SET ROWCOUNT 0
DROP TABLE #VehicleToUsers
END
ELSE
BEGIN
DELETE FROM dbo.VehicleToUser WHERE username = #Username
DELETE FROM dbo.VehicleToUser_UserCurrentImageCount WHERE username = #Username
DELETE FROM dbo.VehicleToUser_UsersCurrentVehicles WHERE username = #Username
End
Try changing your update slightly. I have seen some inconsistent results when using an update like this and you update the base table. You should instead update the alias.
UPDATE v
SET Deleted = VCopy.Deleted
, UpdatedAt = GETDATE()
, UpdatedBy = VCopy.UpdatedBy
FROM VehicleToUser v
inner JOIN #VehicleToUserCopy AS VCopy ON v.ID = VCopy.ID
WHERE VCopy.NextToUpdate = 1
Related
SQL Update trigger requirement
I want to write a trigger which updates some fields in another master table record in TRN_PT_TESTS_DET table gets updated for a specific test. EG. when driving license in PTD_READING_TEXT column is updated in TRN_PT_TESTS_DET table, we want to update PT_DRIVER_LIC column in MST_PATIENT where PT_ID = ENC_PT_ID, which will also look in TST_CODE = 'SC32105' in MST_TESTS table (code 'SC32105' stands for driving license). Reference query: select top 10 ENC_PT_ID, PTD_READING_TEXT from trn_pt_tests_Det inner join trn_pt_tests_head on ptd_pth_id = pth_id inner join trn_encounters on pth_enc_id = enc_id where ptd_test_id = (select TST_ID from MST_TESTS where TST_CODE = 'SC32105'); While doing that we also want to add a record in TRN_NOTES with TN_TYPE = 'PC', TN_OBJECT_ID = PT_ID and TN_NOTE = "Updated Patient <PT_LAST_NAME>, <PT_FIRST_NAME> Driver License Old:XXX New:YYYY" I have created a below trigger which is not updating the PT_DRIVER_LIC column in MST_PATIENT and also inserting incorrect record into TRN_NOTES table. Can someone please tell me what I am doing wrong? When I execute below update query. update TRN_PT_TESTS_DET set PTD_READING_TEXT = 'aaaaa' where PTD_TEST_ID = 11025 and PTD_PTH_ID = 134 the value is updated and trigger is called but #pt_id, #enc_id, #pt_last_name and #pt_first_name declared variable in trigger fetch different ID's and insert different values in TRN_NOTES table and the update MST_PATIENT table part don't work at all. Can some please review below trigger and help me to fin out what I am doing wrong. Trigger: CREATE TRIGGER update_driver_lic_and_notes ON TRN_PT_TESTS_DET AFTER UPDATE AS IF (UPDATE (PTD_READING_TEXT)) BEGIN IF EXISTS (SELECT 1 FROM trn_pt_tests_Det INNER JOIN trn_pt_tests_head ON ptd_pth_id = pth_id INNER JOIN trn_encounters ON pth_enc_id = enc_id WHERE PTH_ID = PTD_PTH_ID AND EXISTS (SELECT 1 FROM MST_TESTS WHERE TST_CODE = 'VTWTLBS')) BEGIN DECLARE #old_dl varchar(255); DECLARE #new_dl varchar(255); DECLARE #pt_id int; DECLARE #enc_id int; DECLARE #pt_last_name varchar(255); DECLARE #pt_first_name varchar(255); SELECT #old_dl = PT_DRIVER_LIC FROM MST_PATIENT INNER JOIN trn_encounters ON PT_ID = ENC_PT_ID INNER JOIN trn_pt_tests_head ON pth_enc_id = enc_id INNER JOIN TRN_PT_TESTS_DET ON ptd_pth_id = pth_id WHERE ptd_test_id = (SELECT TST_ID FROM MST_TESTS WHERE TST_CODE = 'VTWTLBS');; SELECT #new_dl = PTD_READING_TEXT, #pt_id = ENC_PT_ID, #enc_id = enc_id, #pt_last_name = PT_LNAME, #pt_first_name = PT_FNAME FROM MST_PATIENT INNER JOIN trn_encounters ON PT_ID = ENC_PT_ID INNER JOIN trn_pt_tests_head ON pth_enc_id = enc_id INNER JOIN TRN_PT_TESTS_DET ON ptd_pth_id = pth_id WHERE ptd_test_id = (SELECT TST_ID FROM MST_TESTS WHERE TST_CODE = 'VTWTLBS'); -- IF (#old_dl != #new_dl) UPDATE MST_PATIENT SET PT_DRIVER_LIC = #new_dl WHERE PT_ID = #pt_id; INSERT INTO TRN_NOTES (TN_TYPE, TN_OBJECT_ID, TN_ENC_ID, TN_MOD_USER, TN_NOTES, TN_MOD_TIMESTAMP) VALUES ('PC', #pt_id, #enc_id,0, 'Updated Patient ' + #pt_last_name + ', ' + #pt_first_name + ' Driver License Old:' + #old_dl + ' New:' + #new_dl, GETDATE()); END END Thank you.
Updating table based on derived column as well as returning the resultset of the stored procedure
I have written a SQL Server stored procedure that returns a derived column in its result set. The derived column returns the difference in days and if the difference is less than 24 hours, then it returns hours. I need to call an update statement based on value that comes from the derived column (NoOfDays) is -1: The storedprocedure would however return the entire resultset that includes the derived column and perform the update if necessary update [org].[User] set [Disabled] = 0 where id = #UserID AND .... How do include this update statement to do that in this stored procedure Stored procedure: CREATE PROCEDURE declaration.UserAgreementsOutstanding (#UserID INT) AS BEGIN SET NOCOUNT ON; BEGIN TRY UPDATE ua SET ua.AcceptanceWindowExpiry = GETUTCDATE() + a.ReviewPeriodInDays FROM declaration.UserAgreement ua INNER JOIN declaration.Agreement a ON ua.AgreementID = a.ID WHERE ua.USERID = #UserID AND ua.AcceptanceWindowExpiry IS NULL; SELECT ua.ID AS UserAgreementID, A.ID AS AgreementID, A.Code, A.ComplianceCode, A.Name, A.Description, A.Version, ua.UserAgreementStateID, uas.Name AS UserAgreementStateName, ua.AcceptanceWindowExpiry, declaration.GetDifferenceInDaysOrHours(ua.AcceptanceWindowExpiry) AS NoOfDays, A.Data, pa.ID AS AuthoredByID, pa.FirstName + ' ' + pa.LastName AS AuthoredByName, A.Authored, ia.ID AS IssuedByID, ia.FirstName + ' ' + pa.LastName AS IssuedByName, A.Issued FROM declaration.Agreement AS A INNER JOIN declaration.UserAgreement AS ua ON A.ID = ua.AgreementID INNER JOIN declaration.UserAgreementState AS uas ON ua.UserAgreementStateID = uas.ID LEFT JOIN common.Person AS pa ON A.AuthoredBy = pa.ID LEFT JOIN common.Person AS ia ON A.IssuedBy = ia.ID WHERE ua.UserID = 607 AND uas.Code IN ('ISS', 'DEF') -- Issued, Deferred AND A.Draft = CONVERT(BIT, 0) -- Not a draft. AND A.Deleted = CONVERT(BIT, 0) -- Not deleted. AND (A.Issued <= GETUTCDATE() OR A.Issued IS NULL) AND (A.Expires > GETUTCDATE() OR A.Expires IS NULL) END TRY BEGIN CATCH -- do some pseudo logging PRINT ERROR_MESSAGE(); THROW; END CATCH; END; Function CREATE FUNCTION declaration.GetDifferenceInDaysOrHours(#AcceptanceWindowExpiry datetime) RETURNS int AS BEGIN DECLARE #timeDifferenceInDays INT; DECLARE #timeDifferenceInHours INT; DECLARE #timeDifference INT; SELECT #timeDifferenceInDays = DATEDIFF(d, GETUTCDATE(), #AcceptanceWindowExpiry) IF #timeDifferenceInDays > 1 BEGIN SELECT #timeDifference = #timeDifferenceInDays END ELSE BEGIN SELECT #timeDifferenceInHours = DATEDIFF(HOUR, GETUTCDATE(), #AcceptanceWindowExpiry) IF #timeDifferenceInHours >= 0 AND #timeDifferenceInHours <= 24 BEGIN SELECT #timeDifference = #timeDifferenceInHours END ELSE BEGIN SELECT #timeDifference = -1 END END RETURN #timeDifference; END; The current resultset
You can add UPDATE statement to disable the user before updating the user agreement. Also, have the transaction scope. BEGIN TRY BEGIN TRANSACTION; DECLARE #OutStandingUserAgreements TABLE(UserID INT, AgreementID INT, TimeDifference INT) INSERT INTO #OutStandingUserAgreements(UserID, AgreementID , TimeDifference) SELECT U.Id , UA.AgreementID , declaration.UserAgreementsOutstanding(UA.AcceptanceWindowExpiry) AS TimeDifference FROM [org].[User] AS U INNER JOIN declaration.UserAgreement AS UA ON U.UserID = UA.UserID where U.id = #UserID; -- We are disabling user here, based on the UserAgreement Status UPDATE U SET U.[Disabled] = 0 FROM [org].[User] AS U WHERE EXISTS (SELECT 1 FROM #OutStandingUserAgreements AS oua WHERE oua.UserID = U.ID AND oua.TimeDifference = -1); UPDATE ua SET ua.AcceptanceWindowExpiry = GETUTCDATE() + a.ReviewPeriodInDays FROM declaration.UserAgreement ua INNER JOIN declaration.Agreement a ON ua.AgreementID = a.ID WHERE ua.USERID = #UserID AND ua.AcceptanceWindowExpiry IS NULL; IF EXISTS(SELECT 1 FROM Org.User WHERE Id = #UserID AND Disabled = 0) BEGIN SELECT -1; END ELSE BEGIN SELECT ua.ID AS UserAgreementID, A.ID AS AgreementID, A.Code, A.ComplianceCode, A.Name, A.Description, A.Version, ua.UserAgreementStateID, uas.Name AS UserAgreementStateName, ua.AcceptanceWindowExpiry, oua.TimeDifference AS NoOfDays, A.Data, pa.ID AS AuthoredByID, pa.FirstName + ' ' + pa.LastName AS AuthoredByName, A.Authored, ia.ID AS IssuedByID, ia.FirstName + ' ' + pa.LastName AS IssuedByName, A.Issued FROM declaration.Agreement AS A INNER JOIN declaration.UserAgreement AS ua ON A.ID = ua.AgreementID INNER JOIN declaration.UserAgreementState AS uas ON ua.UserAgreementStateID = uas.ID INNER JOIN #OutStandingUserAgreements AS oua ON oua.AgreementID = ua.AgreementID LEFT JOIN common.Person AS pa ON A.AuthoredBy = pa.ID LEFT JOIN common.Person AS ia ON A.IssuedBy = ia.ID WHERE ua.UserID = 607 AND uas.Code IN ('ISS', 'DEF') -- Issued, Deferred AND A.Draft = CONVERT(BIT, 0) -- Not a draft. AND A.Deleted = CONVERT(BIT, 0) -- Not deleted. AND (A.Issued <= GETUTCDATE() OR A.Issued IS NULL) AND (A.Expires > GETUTCDATE() OR A.Expires IS NULL) END COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; END CATCH
Splitting SQL query with many joins into smaller ones helps?
We need to do some reporting every night on our SQL server 2008R2. Calculating the reports takes several hours. In order to shorten the time we precalculate a table. This table is created based on JOINining 12 quite big (tens of milions row) tables. The calculation of this aggregation table took until few days ago cca 4 hours. Our DBA than split this big join into 3 smaller joins (each joining 4 tables). The temporar result is everytime saved into a temporary table, which is used in the next join. The result of the DBA enhancment is, that the aggregation table is calculated in 15 minutes. I wondered how is that possible. DBA told me that it is because the number of data the server must process is smaller. In other words, that in the big original join the server has to work with more data than in summed smaller joins. However, I would presume that optimizer would take care of doing it effeciently with the original big join, splitting the joins on its own and sending only the number of columns needed to next joins. The other thing he has done is that he created an index on one of the tmeporary tables. However, once again I would think that the optimizer will create the appropriate hash tables if needed and alltogether better optimize the computation. I talked about this with our DBA, but he was himself uncertain about what cased the improvement in processing time. He just mentioned, that he would not blame the server as it can be overwhelming to compute such big data and that it is possible that the optimizer has hard time to predict the best execution plan ... . This I understand, but I would like to have more defining answer as to exactly why. So, the questions are: 1. "What could possibly cause the big improvement?" 2. "Is it a standard procedure to split big joins into smaller?" 3. "Is the amount of data which srever has to process really smaller in case of multiple smaller joins?" Here is the original query: Insert Into FinalResult_Base SELECT TC.TestCampaignContainerId, TC.CategoryId As TestCampaignCategoryId, TC.Grade, TC.TestCampaignId, T.TestSetId ,TL.TestId ,TSK.CategoryId ,TT.[TestletId] ,TL.SectionNo ,TL.Difficulty ,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty) ,TQ.[QuestionId] ,TS.StudentId ,TS.ClassId ,RA.SubjectId ,TQ.[QuestionPoints] ,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0 When TQ.[QuestionPoints] > 0 Then 1 Else 0 End ,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1 When TQ.[QuestionPoints] Is null Then 1 Else 0 End ,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End ,TS.Redizo ,TT.ViewCount ,TT.SpentTime ,TQ.[Position] ,RA.SpecialNeeds ,[Version] = 1 ,TestAdaptationId = TA.Id ,TaskId = TSK.TaskId ,TaskPosition = TT.Position ,QuestionRate = Q.Rate ,TestQuestionId = TQ.Guid ,AnswerType = TT.TestletAnswerTypeId FROM [TestQuestion] TQ WITH (NOLOCK) Join [TestTask] TT WITH (NOLOCK) On TT.Guid = TQ.TestTaskId Join [Question] Q WITH (NOLOCK) On TQ.QuestionId = Q.QuestionId Join [Testlet] TL WITH (NOLOCK) On TT.TestletId = TL.Guid Join [Test] T WITH (NOLOCK) On TL.TestId = T.Guid Join [TestSet] TS WITH (NOLOCK) On T.TestSetId = TS.Guid Join [RoleAssignment] RA WITH (NOLOCK) On TS.StudentId = RA.PersonId And RA.RoleId = 1 Join [Task] TSK WITH (NOLOCK) On TSK.TaskId = TT.TaskId Join [Category] C WITH (NOLOCK) On C.CategoryId = TSK.CategoryId Join [TimeWindow] TW WITH (NOLOCK) On TW.Id = TS.TimeWindowId Join [TestAdaptation] TA WITH (NOLOCK) On TA.Id = TW.TestAdaptationId Join [TestCampaign] TC WITH (NOLOCK) On TC.TestCampaignId = TA.TestCampaignId WHERE T.TestTypeId = 1 -- eliminuji ankety And t.ProcessedOn is not null -- ne vsechny, jen dokoncene And TL.ShownOn is not null And TS.Redizo not in (999999999, 111111119) END; The new splitted joins after DBA great work: SELECT TC.TestCampaignContainerId, TC.CategoryId As TestCampaignCategoryId, TC.Grade, TC.TestCampaignId, T.TestSetId ,TL.TestId ,TL.SectionNo ,TL.Difficulty ,TestletName = Char(65+TL.SectionNo) + CONVERT(varchar(4),6 - TL.Difficulty) -- prevod na A5, B4, B5 ... ,TS.StudentId ,TS.ClassId ,TS.Redizo ,[Version] = 1 -- ? ,TestAdaptationId = TA.Id ,TL.Guid AS TLGuid ,TS.TimeWindowId INTO [#FinalResult_Base_1] FROM [TestSet] [TS] WITH (NOLOCK) JOIN [Test] [T] WITH (NOLOCK) ON [T].[TestSetId] = [TS].[Guid] AND [TS].[Redizo] NOT IN (999999999, 111111119) AND [T].[TestTypeId] = 1 AND [T].[ProcessedOn] IS NOT NULL JOIN [Testlet] [TL] WITH (NOLOCK) ON [TL].[TestId] = [T].[Guid] AND [TL].[ShownOn] IS NOT NULL JOIN [TimeWindow] [TW] WITH (NOLOCK) ON [TW].[Id] = [TS].[TimeWindowId] AND [TW].[IsActive] = 1 JOIN [TestAdaptation] [TA] WITH (NOLOCK) ON [TA].[Id] = [TW].[TestAdaptationId] AND [TA].[IsActive] = 1 JOIN [TestCampaign] [TC] WITH (NOLOCK) ON [TC].[TestCampaignId] = [TA].[TestCampaignId] AND [TC].[IsActive] = 1 JOIN [TestCampaignContainer] [TCC] WITH (NOLOCK) ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1 ; SELECT FR1.TestCampaignContainerId, FR1.TestCampaignCategoryId, FR1.Grade, FR1.TestCampaignId, FR1.TestSetId ,FR1.TestId ,TSK.CategoryId AS [TaskCategoryId] ,TT.[TestletId] ,FR1.SectionNo ,FR1.Difficulty ,TestletName = Char(65+FR1.SectionNo) + CONVERT(varchar(4),6 - FR1.Difficulty) -- prevod na A5, B4, B5 ... ,FR1.StudentId ,FR1.ClassId ,FR1.Redizo ,TT.ViewCount ,TT.SpentTime ,[Version] = 1 -- ? ,FR1.TestAdaptationId ,TaskId = TSK.TaskId ,TaskPosition = TT.Position ,AnswerType = TT.TestletAnswerTypeId ,TT.Guid AS TTGuid INTO [#FinalResult_Base_2] FROM #FinalResult_Base_1 FR1 JOIN [TestTask] [TT] WITH (NOLOCK) ON [TT].[TestletId] = [FR1].[TLGuid] JOIN [Task] [TSK] WITH (NOLOCK) ON [TSK].[TaskId] = [TT].[TaskId] AND [TSK].[IsActive] = 1 JOIN [Category] [C] WITH (NOLOCK) ON [C].[CategoryId] = [TSK].[CategoryId]AND [C].[IsActive] = 1 ; DROP TABLE [#FinalResult_Base_1] CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class] ON [dbo].[#FinalResult_Base_2] ([StudentId],[ClassId]) INCLUDE ([TTGuid]) SELECT FR2.TestCampaignContainerId, FR2.TestCampaignCategoryId, FR2.Grade, FR2.TestCampaignId, FR2.TestSetId ,FR2.TestId ,FR2.[TaskCategoryId] ,FR2.[TestletId] ,FR2.SectionNo ,FR2.Difficulty ,FR2.TestletName ,TQ.[QuestionId] ,FR2.StudentId ,FR2.ClassId ,RA.SubjectId ,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer ,GoodAnswer = Case When TQ.[QuestionPoints] Is null Then 0 When TQ.[QuestionPoints] > 0 Then 1 -- cookie Else 0 End ,WrongAnswer = Case When TQ.[QuestionPoints] = 0 Then 1 When TQ.[QuestionPoints] Is null Then 1 Else 0 End ,NoAnswer = Case When TQ.[QuestionPoints] Is null Then 1 Else 0 End ,FR2.Redizo ,FR2.ViewCount ,FR2.SpentTime ,TQ.[Position] AS [QuestionPosition] ,RA.SpecialNeeds -- identifikace SVP ,[Version] = 1 -- ? ,FR2.TestAdaptationId ,FR2.TaskId ,FR2.TaskPosition ,QuestionRate = Q.Rate ,TestQuestionId = TQ.Guid ,FR2.AnswerType INTO [#FinalResult_Base] FROM [#FinalResult_Base_2] FR2 JOIN [TestQuestion] [TQ] WITH (NOLOCK) ON [TQ].[TestTaskId] = [FR2].[TTGuid] JOIN [Question] [Q] WITH (NOLOCK) ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1 JOIN [RoleAssignment] [RA] WITH (NOLOCK) ON [RA].[PersonId] = [FR2].[StudentId] AND [RA].[ClassId] = [FR2].[ClassId] AND [RA].[IsActive] = 1 AND [RA].[RoleId] = 1 drop table #FinalResult_Base_2; truncate table [dbo].[FinalResult_Base]; insert into [dbo].[FinalResult_Base] select * from #FinalResult_Base; drop table #FinalResult_Base;
For the first, please, rebuilding indexes on your tables by this script (this may take a long time) - SET NOCOUNT ON; DECLARE #SQL NVARCHAR(MAX) , #IndexName SYSNAME , #Output VARCHAR(200) , #ServerVersion VARCHAR(100) SELECT #ServerVersion = CAST(SERVERPROPERTY('Edition') AS VARCHAR(100)) DECLARE cur CURSOR LOCAL READ_ONLY FORWARD_ONLY FOR SELECT 'ALTER INDEX [' + ix.name + N'] ON [' + SCHEMA_NAME(t.[schema_id]) + '].[' + t.name + '] ' + CASE WHEN ps.avg_fragmentation_in_percent > 50 THEN CASE WHEN #ServerVersion LIKE 'Enterprise%' OR #ServerVersion LIKE 'Developer%' THEN 'REBUILD WITH (SORT_IN_TEMPDB = ON, ONLINE = ON ' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') ' ELSE 'REBUILD WITH (SORT_IN_TEMPDB = ON' + CASE WHEN ix.fill_factor > 0 THEN ', FILLFACTOR = ' + CAST(ix.fill_factor AS VARCHAR(3)) ELSE '' END + ') ' END ELSE 'REORGANIZE ' END + CASE WHEN ps.partition_number > 1 THEN N' PARTITION = ' + CAST(ps.partition_number AS NVARCHAR(MAX)) ELSE N'' END + ';', ix.name FROM sys.indexes ix JOIN sys.objects t ON t.[object_id] = ix.[object_id] JOIN ( SELECT [object_id] , index_id , avg_fragmentation_in_percent , partition_number FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, N'LIMITED') WHERE page_count > 100 AND avg_fragmentation_in_percent > 10 ) ps ON t.[object_id] = ps.[object_id] AND ix.index_id = ps.index_id WHERE t.[type] = 'U' AND t.name IN ( 'TestQuestion', 'TestTask', 'Question', 'Testlet', 'Test', 'TestSet', 'RoleAssignment', 'Task', 'category', 'TimeWindow', 'TestAdaptation', 'TestCampaign') OPEN cur FETCH NEXT FROM cur INTO #SQL, #IndexName WHILE ##FETCH_STATUS = 0 BEGIN SELECT #Output = CONVERT(NVARCHAR(15), GETDATE(), 114) + ': ' + #IndexName RAISERROR(#Output, 0, 1) WITH NOWAIT EXEC sys.sp_executesql #SQL FETCH NEXT FROM cur INTO #SQL, #IndexName END CLOSE cur DEALLOCATE cur And after it try this query - INSERT INTO dbo.FinalResult_Base SELECT TC.TestCampaignContainerId , TestCampaignCategoryId = TC.CategoryID , TC.Grade , TC.TestCampaignId , T.TestSetId , TL.TestId , TSK.CategoryID , TT.[TestletId] , TL.SectionNo , TL.Difficulty , TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty) , TQ.[QuestionId] , TS.StudentId , TS.ClassId , RA.SubjectId , TQ.[QuestionPoints] , GoodAnswer = CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0 THEN 1 ELSE 0 END , WrongAnswer = CASE WHEN ISNULL(TQ.[QuestionPoints], 0) = 0 THEN 1 ELSE 0 END , NoAnswer = CASE WHEN TQ.[QuestionPoints] IS NULL THEN 1 ELSE 0 END , TS.Redizo , TT.ViewCount , TT.SpentTime , TQ.[Position] , RA.SpecialNeeds , [Version] = 1 , TestAdaptationId = TA.id , TaskId = TSK.TaskId , TaskPosition = TT.Position , QuestionRate = Q.Rate , TestQuestionId = TQ.guid , AnswerType = TT.TestletAnswerTypeId FROM dbo.TestQuestion TQ WITH (NOLOCK) JOIN dbo.TestTask TT WITH (NOLOCK) ON TT.[guid] = TQ.TestTaskId JOIN dbo.Question Q WITH (NOLOCK) ON TQ.QuestionId = Q.QuestionId JOIN ( SELECT * FROM dbo.Testlet TL WITH (NOLOCK) WHERE TL.ShownOn IS NOT NULL ) TL ON TT.TestletId = TL.[guid] JOIN ( SELECT * FROM dbo.Test T WITH (NOLOCK) WHERE T.TestTypeId = 1 AND T.ProcessedOn IS NOT NULL ) T ON TL.TestId = T.[guid] JOIN ( SELECT * FROM dbo.TestSet TS WITH (NOLOCK) WHERE TS.Redizo NOT IN (999999999, 111111119) ) TS ON T.TestSetId = TS.[guid] JOIN dbo.RoleAssignment RA WITH (NOLOCK) ON TS.StudentId = RA.PersonID AND RA.RoleId = 1 JOIN dbo.Task TSK WITH (NOLOCK) ON TSK.TaskId = TT.TaskId JOIN dbo.category C WITH (NOLOCK) ON C.CategoryID = TSK.CategoryID JOIN dbo.TimeWindow TW WITH (NOLOCK) ON TW.id = TS.TimeWindowId JOIN dbo.TestAdaptation TA WITH (NOLOCK) ON TA.id = TW.TestAdaptationId JOIN dbo.TestCampaign TC WITH (NOLOCK) ON TC.TestCampaignId = TA.TestCampaignId And try this query - SELECT TC.TestCampaignContainerId ,TC.CategoryID AS TestCampaignCategoryId ,TC.Grade ,TC.TestCampaignId ,T.TestSetId ,TL.TestId ,TL.SectionNo ,TL.Difficulty ,TestletName = CHAR(65 + TL.SectionNo) + CONVERT(VARCHAR(4), 6 - TL.Difficulty) -- prevod na A5, B4, B5 ... ,TS.StudentId ,TS.ClassId ,TS.Redizo ,[Version] = 1 -- ? ,TestAdaptationId = TA.id ,TL.guid AS TLGuid ,TS.TimeWindowId INTO [#FinalResult_Base_1] FROM ( SELECT * FROM dbo.[TestSet] [TS] WITH (NOLOCK) WHERE [TS].[Redizo] NOT IN (999999999, 111111119) ) TS JOIN ( SELECT * FROM dbo.[Test] [T] WITH (NOLOCK) WHERE [T].[TestTypeId] = 1 AND [T].[ProcessedOn] IS NOT NULL ) T ON [T].[TestSetId] = [TS].[guid] JOIN ( SELECT * FROM dbo.[Testlet] [TL] WITH (NOLOCK) WHERE [TL].[ShownOn] IS NOT NULL ) TL ON [TL].[TestId] = [T].[guid] JOIN ( SELECT * FROM dbo.[TimeWindow] [TW] WITH (NOLOCK) WHERE [TW].[IsActive] = 1 ) TW ON [TW].[id] = [TS].[TimeWindowId] JOIN ( SELECT * FROM dbo.[TestAdaptation] [TA] WITH (NOLOCK) WHERE [TA].[IsActive] = 1 ) TA ON [TA].[id] = [TW].[TestAdaptationId] JOIN ( SELECT * FROM dbo.[TestCampaign] [TC] WITH (NOLOCK) WHERE [TC].[IsActive] = 1 ) TC ON [TC].[TestCampaignId] = [TA].[TestCampaignId] --possible unused join in this query --JOIN dbo.[TestCampaignContainer] [TCC] WITH (NOLOCK) ON [TCC].[TestCampaignContainerId] = [TC].[TestCampaignContainerId] AND [TCC].[IsActive] = 1 SELECT FR1.TestCampaignContainerId ,FR1.TestCampaignCategoryId ,FR1.Grade ,FR1.TestCampaignId ,FR1.TestSetId ,FR1.TestId ,TSK.CategoryID AS [TaskCategoryId] ,TT.[TestletId] ,FR1.SectionNo ,FR1.Difficulty ,TestletName = CHAR(65 + FR1.SectionNo) + CONVERT(VARCHAR(4), 6 - FR1.Difficulty) -- prevod na A5, B4, B5 ... ,FR1.StudentId ,FR1.ClassId ,FR1.Redizo ,TT.ViewCount ,TT.SpentTime ,[Version] = 1 -- ? ,FR1.TestAdaptationId ,TaskId = TSK.TaskId ,TaskPosition = TT.Position ,AnswerType = TT.TestletAnswerTypeId ,TT.guid AS TTGuid INTO [#FinalResult_Base_2] FROM #FinalResult_Base_1 FR1 JOIN [TestTask] [TT] WITH (NOLOCK) ON [TT].[TestletId] = [FR1].[TLGuid] JOIN [Task] [TSK] WITH (NOLOCK) ON [TSK].[TaskId] = [TT].[TaskId] --possible unused join --JOIN [category] [C] WITH (NOLOCK) ON [C].[CategoryID] = [TSK].[CategoryID] WHERE [TSK].[IsActive] = 1 --AND [C].[IsActive] = 1 DROP TABLE [#FinalResult_Base_1] CREATE NONCLUSTERED INDEX [#IX_FR_Student_Class] ON [dbo].[#FinalResult_Base_2] ([StudentId], [ClassId]) INCLUDE ([TTGuid]) TRUNCATE TABLE [dbo].[FinalResult_Base]; INSERT INTO [dbo].[FinalResult_Base] SELECT FR2.TestCampaignContainerId ,FR2.TestCampaignCategoryId ,FR2.Grade ,FR2.TestCampaignId ,FR2.TestSetId ,FR2.TestId ,FR2.[TaskCategoryId] ,FR2.[TestletId] ,FR2.SectionNo ,FR2.Difficulty ,FR2.TestletName ,TQ.[QuestionId] ,FR2.StudentId ,FR2.ClassId ,RA.SubjectId ,TQ.[QuestionPoints] -- 1+ good, 0 wrong, null no answer , GoodAnswer = CASE WHEN ISNULL(TQ.[QuestionPoints], 0) > 0 THEN 1 ELSE 0 END , WrongAnswer = CASE WHEN ISNULL(TQ.[QuestionPoints], 0) = 0 THEN 1 ELSE 0 END , NoAnswer = CASE WHEN TQ.[QuestionPoints] IS NULL THEN 1 ELSE 0 END ,FR2.Redizo ,FR2.ViewCount ,FR2.SpentTime ,TQ.[Position] AS [QuestionPosition] ,RA.SpecialNeeds -- identifikace SVP ,[Version] = 1 -- ? ,FR2.TestAdaptationId ,FR2.TaskId ,FR2.TaskPosition ,QuestionRate = Q.Rate ,TestQuestionId = TQ.guid ,FR2.AnswerType FROM [#FinalResult_Base_2] FR2 JOIN [TestQuestion] [TQ] WITH (NOLOCK) ON [TQ].[TestTaskId] = [FR2].[TTGuid] JOIN [Question] [Q] WITH (NOLOCK) ON [Q].[QuestionId] = [TQ].[QuestionId] AND [Q].[IsActive] = 1 JOIN [RoleAssignment] [RA] WITH (NOLOCK) ON [RA].[PersonID] = [FR2].[StudentId] AND [RA].[ClassId] = [FR2].[ClassId] AND [RA].[IsActive] = 1 AND [RA].[RoleId] = 1 DROP TABLE #FinalResult_Base_2;
IMHO It should not be the case, I faced similar problem and took the following steps to optimize it. Try putting Indexes on the columns which are used in filtering (The columns deciding the joins). Try to put indexes on Views, It could be done but It needs some special requirements. Have some jobs for Index Rebuilding. Use another mirror instance of DB for reporting leave the live DB Don't use functions while joining if you want to transform data do it after joining. Use Query optimizer to view what part of join is taking most of the time/resources. Use an Archive table to purge data into it from live DB. Hope it helps :)
SQL Server trigger on a field that's updated
I have the following trigger: BEGIN DECLARE #email varchar(200) DECLARE #jobcode int DECLARE #status char(1) DECLARE #emaild varchar(200) DECLARE #jobcoded int DECLARE #statusd char(1) SET #statusd = NULL SELECT #status = z.status, #email = p.EMail, #jobcode = z.jobID FROM zipoutfiles z INNER JOIN inserted AS i ON z.jobID = i.jobID INNER JOIN PS_LoginUser AS p ON z.UserID = p.UserID SELECT #statusd = z.status, #emaild = p.EMail, #jobcoded = z.jobID FROM zipoutfiles z INNER JOIN deleted AS d ON z.jobID = d.jobID INNER JOIN PS_LoginUser AS p ON z.UserID = p.UserID WHERE d.jobID = #jobcode IF ((#status = 'D' AND #statusd = 'R') OR (#status = 'D' AND #statusd = 'E')) BEGIN EXEC SendMail #email, #jobcode END END I want to be able to run SendMail when status goes from E to D or R to D, but not D to D (if it gets updated again) and also when it gets inserted as D. What am I doing wrong here:
Not sure what your table schemas are, but this may get you all of the appropriate emails: select p.EMail as Email, z.JobId as JobCode from ZipOutFiles as ZOF inner join inserted as i on i.JobId = ZOF.JobId inner join PS_LoginUser as PLU on PLU.UserId = ZOF.UserId left outer join deleted as d on d.JobId = ZOF.JobId where ( d.Status = 'E' and i.Status = 'D' ) or -- E -> D. ( d.Status = 'R' and i.Status = 'D' ) or -- R -> D. ( d.Status is NULL and i.Status = 'D' ) -- Inserted D. I've assumed that you aren't really updating JobId. If so, how do you match the before and after rows? Also assumed is that Status cannot be NULL. If so, the last condition needs to be modified to properly detect no corresponding row was found in the deleted table.
Writing a complex trigger
This posting is an update (with trigger code) from my earlier posting yesterday I am using SQL Server 2000. I am writing a trigger that is executed when a field Applicant.AppStatusRowID Table Applicant is linked to table Location, table Company & table AppStatus. My issue is creating the joins in my query. When Applicant.AppStatusRowID is updated, I want to get the values from Applicant.AppStatusRowID, Applicant.FirstName, Applicant.Lastname, Location.LocNumber, Location.LocationName, Company.CompanyCode, AppStatus.DisplayText The joins would be : Select * from Applicant A Inner Join AppStatus ast on ast.RowID = a.AppStatusRowID Inner Join Location l on l.RowID = a.LocationRowID Inner Join Company c on c.RowID = l.CompanyRowID This is to be inserted into an Audit table (fields are ApplicantID, LastName, FirstName, Date, Time, Company, Location Number, Location Name, StatusDisposition, User) The trigger query is: SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO CREATE TRIGGER tri_UpdateAppDispo ON dbo.Test_App For Update AS declare #Approwid int Declare #triggername sysname Set #rowCnt = ##rowcount Set #triggername = object_name(##procid) If #rowCnt = 0 RETURN If Update(appstatusrowid) BEGIN ----------------------------------------------------------------------------- -- insert a record to the AppDispo table, if AppstatusRowid -- is being Updated ----------------------------------------------------------------------------- Insert AppDispo(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDispo,[Username]) Select d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User From deleted d with(nolock) Inner join Test_App a with (nolock) on a.RowID = d.rowid inner join location l with (nolock) on l.rowid = d.Locationrowid inner join appstatus ast with (nolock) on ast.rowid = d.appstatusrowid inner join company c with (nolock) on c.rowid = l.CompanyRowid --Inner Join Deleted d ON a.RowID = d.RowID --Where (a.rowid = #Approwid) END GO Any ideas?
Try with this code SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO CREATE TRIGGER tri_UpdateAppDispo ON dbo.Test_App For Update AS declare #Approwid int Declare #triggername sysname Set #rowCnt = ##rowcount Set #triggername = object_name(##procid) If #rowCnt = 0 RETURN If Update(appstatusrowid) BEGIN ----------------------------------------------------------------------------- -- insert a record to the AppDispo table, if AppstatusRowid -- is being Updated ----------------------------------------------------------------------------- Insert AppDispo(AppID, LastName, FirstName, [DateTime],Company,Location,LocationName, StatusDispo,[Username]) Select d.Rowid,d.LastName, d.FirstName, getDate(),C.CompanyCode,l.locnum,l.locname, ast.Displaytext, SUSER_SNAME()+' '+User From deleted d with(nolock),location l with (nolock),appstatus ast with (nolock),company c with (nolock) where d.Locationrowid =l.rowid and d.appstatusrowid = ast.rowid and c.rowid = l.CompanyRowid END GO whith this code you get the update-deleted row(the old_value) see you.