TempDB drive Full - Procedure needs much performance? - sql

following situation: We have an azure server with db and the TempDB drive ran full. At this moment we could find a process with much resources need in activity monitor. The process was not killable cause the rollback couldn't be done cause of the full drive.
Now I have two questions:
Can the process be the cause of the huge tempdb files?
Can someone explain why the process needs so much resources?
Attach you find a screenshot of the activity monitor and the code of the procedure.
The procedure is started every 10 seconds with SQL Server agent. The loop inside the procedure is not that nice but we needed the statistics and it run well for the last 3 weeks.
CREATE PROCEDURE Log_Blocking_Processes
AS
BEGIN
IF OBJECT_ID('dbo.Log_Blocked_Processes', 'U') IS NULL
BEGIN
SELECT GETDATE() as Tag,
db.name DBName,
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
tl.resource_type,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode,
er.transaction_id as Requesting_Transaction_ID,
tst.transaction_id as Blocking_Transaction_ID,
tat.name as Blocking_Transaction_Name,
er.wait_time/1000 as Wait_Time_SEC
INTO Log_Blocked_Processes
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
INNER JOIN sys.dm_exec_requests er ON er.session_id = tl.request_session_id AND er.blocking_session_id = wt.blocking_session_id AND er.blocking_session_id <> 0
INNER JOIN sys.dm_tran_session_transactions tst ON tst.session_id = wt.blocking_session_id
INNER JOIN sys.dm_tran_active_transactions tat ON tat.transaction_id = tst.transaction_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
WHERE db.database_id = DB_ID();
RETURN;
END;
DECLARE #DBName nvarchar(128),
#request_session_id int,
#blocking_session_id smallint,
#BlockedObjectName nvarchar(128),
#resource_type nvarchar(60),
#RequestingText nvarchar(MAX),
#BlockingText nvarchar(MAX),
#request_mode nvarchar(60),
#Requesting_Transaction_ID bigint,
#Blocking_Transaction_ID bigint,
#Blocking_Transaction_Name nvarchar(32),
#Wait_Time_SEC int,
#Tag DATE,
#Mycount int,
#LastInsertDay DATE,
#counter int = 1;
DECLARE blocked_processes_cursor CURSOR FOR
SELECT cast(GETDATE() as DATE) as Tag,
db.name DBName,
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
tl.resource_type,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingText,
tl.request_mode,
er.transaction_id as Requesting_Transaction_ID,
tst.transaction_id as Blocking_Transaction_ID,
tat.name as Blocking_Transaction_Name,
er.wait_time/1000 as Wait_Time_SEC
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
INNER JOIN sys.dm_exec_requests er ON er.session_id = tl.request_session_id AND er.blocking_session_id = wt.blocking_session_id AND er.blocking_session_id <> 0
INNER JOIN sys.dm_tran_session_transactions tst ON tst.session_id = wt.blocking_session_id
INNER JOIN sys.dm_tran_active_transactions tat ON tat.transaction_id = tst.transaction_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
WHERE db.database_id = DB_ID();
WHILE #counter <= 4
BEGIN
OPEN blocked_processes_cursor
FETCH NEXT FROM blocked_processes_cursor INTO #Tag, #DBName, #request_session_id, #blocking_session_id, #BlockedObjectName, #resource_type, #RequestingText, #BlockingText, #request_mode, #Requesting_Transaction_ID, #Blocking_Transaction_ID, #Blocking_Transaction_Name, #Wait_Time_SEC;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Mycount = count(*), #LastInsertDay = cast(max(Tag) as date) FROM Log_Blocked_Processes WHERE Requesting_Transaction_ID = #Requesting_Transaction_ID AND Blocking_Transaction_ID = #Blocking_Transaction_ID;
IF #Mycount > 0 AND #LastInsertDay = cast(getdate() as date)
BEGIN
UPDATE Log_Blocked_Processes
SET Wait_Time_SEC = #Wait_Time_SEC
WHERE Requesting_Transaction_ID = #Requesting_Transaction_ID
AND Blocking_Transaction_ID = #Blocking_Transaction_ID;
END;
ELSE
BEGIN
INSERT INTO [Log_Blocked_Processes]([Tag],[DBName],[request_session_id],[blocking_session_id],[BlockedObjectName],[resource_type],[RequestingText],[BlockingText],[request_mode],[Requesting_Transaction_ID],[Blocking_Transaction_ID],[Blocking_Transaction_Name],[Wait_Time_SEC])
VALUES(GETDATE(),#DBName,#request_session_id,#blocking_session_id,#BlockedObjectName,#resource_type,#RequestingText,#BlockingText,#request_mode,#Requesting_Transaction_ID,#Blocking_Transaction_ID,#Blocking_Transaction_Name,#Wait_Time_SEC)
END;
FETCH NEXT FROM blocked_processes_cursor INTO #Tag, #DBName, #request_session_id, #blocking_session_id, #BlockedObjectName, #resource_type, #RequestingText, #BlockingText, #request_mode, #Requesting_Transaction_ID, #Blocking_Transaction_ID, #Blocking_Transaction_Name, #Wait_Time_SEC;
END;
SET #counter = #counter + 1;
CLOSE blocked_processes_cursor;
WAITFOR DELAY '00:00:02';
END;
DEALLOCATE blocked_processes_cursor;
END;

Related

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

SQL EXEC PROCEDURE: "Must declare the scalar variable "#p1"

I am getting the following error when I try to execute the stored procedure below:
Must declare the scalar variable "#p1"
I don't understand why or how to fix, any help would be appreciated. thanKs
Stored procedure:
USE [SERVER_NAME]
GO
/****** Object: StoredProcedure [dbo].[APP_jdtest_shp_0] Script Date: 16/12/2019 11:13:01 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[jdtest_shp_0]
#p1 nvarchar(100),
#n nvarchar(100)
AS
EXEC('
CREATE VIEW dbo.[' + #n + '] AS
SELECT
RTRIM([F].[F_CODE]) As F_UID ,
RTRIM([TP].[F_TP_NAME]) As F_TP_UID ,
RTRIM([NS].[F_CODE]) AS F_CODE,
RTRIM([NS].[SOME_DATE]) AS SOME_DATE,
RTRIM([NS].[ANOTHER_DATE]) AS ANOTHER_DATE,
RTRIM([NS].[SPD]) AS SPD,
RTRIM([NS].[LK_DATE]) AS LK_DATE,
RTRIM([NS].[RC_DATE]) AS RC_DATE,
RTRIM([NS].[RD_DATE]) AS RD_DATE,
RTRIM([NS].[OLD_UID]) AS OLD_UID,
RTRIM([NS].[VN]) AS VN,
RTRIM([NS].[R_I]) AS R_I,
RTRIM([NS].[WTU_UID]) AS WTU_UID,
RTRIM([NS].[D_LT]) AS D_LT,
RTRIM([PLT_UD].[PLT]) As L_A_PLT_UD_UID ,
RTRIM([RT].[RT_NAME]) As RT_UID ,
RTRIM([SS].[S_S_NAME]) As S_S_UID ,
RTRIM([NS].[S_DATE]) AS S_DATE,
RTRIM([SUR].[S_SUR_NAME]) As S_SUR_UID ,
RTRIM([NS].[S_TOL]) AS S_TOL,
RTRIM([LKP_AUTH].[AUTH_NAME]) As AUTH_UID ,
[NS].[S_G] AS S_G,
RTRIM([NS].[NS_UID]) AS NS_UID,
RTRIM([NSG_C].[C_NAME]) As C_UID ,
RTRIM([NS].[CLT]) AS CLT,
RTRIM([NS].[ONR_UID]) AS ONR_UID,
RTRIM([NC].[S_CLF_NAME]) As S_CLF_UID ,
RTRIM([NS].[XP]) AS XP,
RTRIM([NS].[CSTART_X]) AS CSTART_X,
RTRIM([NS].[CSTART_Y]) AS CSTART_Y,
RTRIM([NS].[CEND_X]) AS CEND_X,
RTRIM([NS].[CEND_Y]) AS CEND_Y
FROM NS
LEFT OUTER JOIN F ON NS.F_UID = F.F_UID
LEFT OUTER JOIN FT ON NS.F_TP_UID = FT.FT_UID
LEFT OUTER JOIN PLT_UD ON NS.L_A_PLT_UD_UID = SEC_PLT_UD.PLT_UD_UID
LEFT OUTER JOIN RT ON NS.RT_UID = RT.RT_UID
LEFT OUTER JOIN STT ON NS.S_S_UID = SS.S_S_UID
LEFT OUTER JOIN SUR ON NS.S_SUR_UID = SUR.S_SUR_UID
LEFT OUTER JOIN AUTH ON NS.AUTH_UID = AUTH.AUTH_UID
LEFT OUTER JOIN C ON NS.C_UID = C.C_UID
LEFT OUTER JOIN NSC ON NS.S_CLF_UID = NSC.S_CLF_UID
WHERE
([NS].[SHAPE_GEOMETRY].STIntersects(Geometry::STGeomFromText(' + '#p1' + ', 0).MakeValid())>0) AND
([NS].[S_G].STGeometryTP() = ''POINT'') '
)
EDIT: using sql server 2014. This is not my code, I am trying to fix a bug in someone else's code.
UPDATE: updated the 'execute command' section to show how the procedure is being executed
You need to use sp_executesql instead of EXEC() if you want to use parameters in your dynamic statement:
CREATE PROCEDURE [dbo].[123456]
#p1 nvarchar(100),
#n nvarchar(100)
AS
BEGIN
DECLARE #stm nvarchar(max)
DECLARE #err int
SET #stm =
N'CREATE VIEW dbo.' + QUOTENAME(#n) + N' AS ' +
N'SELECT
RTRIM([FEATURE].[FEATURE_CODE]) As FEATURE_UID ,
RTRIM([FEATURE_TYPE].[FEATURE_TYPE_NAME]) As FEATURE_TYPE_UID ,
RTRIM([NSG_STREETS].[FEATURE_CODE]) AS FEATURE_CODE,
RTRIM([NSG_STREETS].[START_DATE]) AS START_DATE,
RTRIM([NSG_STREETS].[END_DATE]) AS END_DATE,
RTRIM([NSG_STREETS].[SUSPEND_ACTIVITIES]) AS SUSPEND_ACTIVITIES,
RTRIM([NSG_STREETS].[RECORD_ENTRY_DATE]) AS RECORD_ENTRY_DATE,
RTRIM([NSG_STREETS].[RECORD_CHANGE_DATE]) AS RECORD_CHANGE_DATE,
RTRIM([NSG_STREETS].[RECORD_DELETE_DATE]) AS RECORD_DELETE_DATE,
RTRIM([NSG_STREETS].[OLD_SYSTEM_UID]) AS OLD_SYSTEM_UID,
RTRIM([NSG_STREETS].[VERSION_NUMBER]) AS VERSION_NUMBER,
RTRIM([NSG_STREETS].[RECORD_IDENTIFIER]) AS RECORD_IDENTIFIER,
RTRIM([NSG_STREETS].[WARD_UID]) AS WARD_UID,
RTRIM([NSG_STREETS].[DIGITAL_LENGTH]) AS DIGITAL_LENGTH,
RTRIM([SEC_USER].[USER_NAME]) As LAST_EDIT_USER_UID ,
RTRIM([LKP_RECORD_TYPE].[RECORD_TYPE_NAME]) As RECORD_TYPE_UID ,
RTRIM([LKP_STREET_STATE].[STREET_STATE_NAME]) As STREET_STATE_UID ,
RTRIM([NSG_STREETS].[STATE_DATE]) AS STATE_DATE,
RTRIM([LKP_STREET_SURFACE].[STREET_SURFACE_NAME]) As STREET_SURFACE_UID ,
RTRIM([NSG_STREETS].[STREET_TOLERANCE]) AS STREET_TOLERANCE,
RTRIM([LKP_AUTHORITY].[AUTHORITY_NAME]) As AUTHORITY_UID ,
[NSG_STREETS].[SHAPE_GEOGRAPHY] AS SHAPE_GEOGRAPHY,
RTRIM([NSG_STREETS].[NSG_STREETS_UID]) AS NSG_STREETS_UID,
RTRIM([NSG_COUNTY].[COUNTY_NAME]) As COUNTY_UID ,
RTRIM([NSG_STREETS].[CLASS_UID]) AS CLASS_UID,
RTRIM([NSG_STREETS].[OWNER_UID]) AS OWNER_UID,
RTRIM([NSG_STREET_CLASSIFICATION].[STREET_CLASSIFICATION_NAME]) As STREET_CLASSIFICATION_UID ,
RTRIM([NSG_STREETS].[EXPORT]) AS EXPORT,
RTRIM([NSG_STREETS].[CSTART_X]) AS CSTART_X,
RTRIM([NSG_STREETS].[CSTART_Y]) AS CSTART_Y,
RTRIM([NSG_STREETS].[CEND_X]) AS CEND_X,
RTRIM([NSG_STREETS].[CEND_Y]) AS CEND_Y FROM NSG_STREETS
LEFT OUTER JOIN FEATURE ON NSG_STREETS.FEATURE_UID = FEATURE.FEATURE_UID
LEFT OUTER JOIN FEATURE_TYPE ON NSG_STREETS.FEATURE_TYPE_UID = FEATURE_TYPE.FEATURE_TYPE_UID
LEFT OUTER JOIN SEC_USER ON NSG_STREETS.LAST_EDIT_USER_UID = SEC_USER.USER_UID
LEFT OUTER JOIN LKP_RECORD_TYPE ON NSG_STREETS.RECORD_TYPE_UID = LKP_RECORD_TYPE.RECORD_TYPE_UID
LEFT OUTER JOIN LKP_STREET_STATE ON NSG_STREETS.STREET_STATE_UID = LKP_STREET_STATE.STREET_STATE_UID
LEFT OUTER JOIN LKP_STREET_SURFACE ON NSG_STREETS.STREET_SURFACE_UID = LKP_STREET_SURFACE.STREET_SURFACE_UID
LEFT OUTER JOIN LKP_AUTHORITY ON NSG_STREETS.AUTHORITY_UID = LKP_AUTHORITY.AUTHORITY_UID
LEFT OUTER JOIN NSG_COUNTY ON NSG_STREETS.COUNTY_UID = NSG_COUNTY.COUNTY_UID
LEFT OUTER JOIN NSG_STREET_CLASSIFICATION ON NSG_STREETS.STREET_CLASSIFICATION_UID = NSG_STREET_CLASSIFICATION.STREET_CLASSIFICATION_UID
WHERE
([NSG_STREETS].[SHAPE_GEOMETRY].STIntersects(Geometry::STGeomFromText(#p1, 0).MakeValid())>0) AND
([NSG_STREETS].[SHAPE_GEOGRAPHY].STGeometryType() = ''POINT'') '
EXEC #err = sp_executesql #stm, N'#p1 nvarchar(100)', #p1
IF #err <> 0 BEGIN
PRINT 'Error'
RETURN #err
END
END

Msg 512, Level 16, State 1,Subquery returned more than 1 value

This is the query error is pointing at, don't know what's wrong?
SELECT ISNULL(SUM(a.classes),0)
from (SELECT DISTINCT a.for_date, COUNT(DISTINCT classID) as classes
FROM School_Classes sc
INNER JOIN app_attendance a on a.schoolclass_id = sc.Id
WHERE schoolID =#SchoolID AND a.for_date BETWEEN
DATEADD(DAY,-30,getdate()) AND getdate() GROUP BY a.for_date
) a
The stored Procedure is as follow:
USE [smsdb]
GO
/****** Object: StoredProcedure [dbo].[DailyAlertGSP] Script Date: 28/11/2018 2:47:47 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER PROCEDURE [dbo].[DailyAlertGSP]
-- Add the parameters for the stored procedure here
#RegionIn varchar(150),
#isArea bit
--<#Param2, sysname, #p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #sumAgeing int,#countAgeing int,#sumTotalClasses int,#sumClassesAttendance int,#sumStudentStrength int
-- Insert statements for procedure here
DECLARE #SchoolID INT ,#principalID VARCHAR(50),#ageing INT,#totalClasses INT,#classesAttendance INT,#percentage FLOAT,#ssr INT,#noDays INT
DECLARE #region varchar(150),#area VARCHAR(150),#schoolName VARCHAR(150),#principalName VARCHAR(150)
DECLARE #StartDate date,#EndDate date
DECLARE #FinalData TABLE (Region VARCHAR(150), Area VARCHAR(150), [School ID] INT, [School Name] VARCHAR(150), [Principal Code] INT, [Principal Name] VARCHAR(150),
Ageing INT, [Total Classes] INT, [Classes Attendance] INT, [Precentage (%)] FLOAT, [Student Strength] INT)
iF #isArea = 1
DECLARE AllSchools CURSOR FOR
SELECT s.schoolID as school FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
--INNER JOIN SchoolEMIS se ON s.schoolID=se.schoolID
WHERE a.Name like #RegionIn AND s.isDeleted = 0 order by r.Name;
ELSE
DECLARE AllSchools CURSOR FOR
SELECT s.schoolID as school FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
--INNER JOIN SchoolEMIS se ON s.schoolID=se.schoolID
WHERE r.Name like #RegionIn AND s.isDeleted = 0 order by r.Name;
OPEN AllSchools
FETCH NEXT FROM AllSchools INTO #SchoolID
WHILE ##FETCH_STATUS = 0
BEGIN
SET #StartDate = GETDATE(); SET #EndDate = DATEADD(DAY,-30,getdate())
SET #schoolName = (SELECT Name FROM School WHERE schoolID=#SchoolID)
IF #isArea = 1
SET #region = (Select r.Name FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
WHERE a.Name like #RegionIn AND s.schoolID = #SchoolID )
ELSE
SET #region = (Select r.Name FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
WHERE r.Name like #RegionIn AND s.schoolID = #SchoolID )
IF #isArea = 1
SET #area = (Select a.Name FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
WHERE a.Name like #RegionIn AND s.schoolID = #SchoolID )
ELSE
SET #area = (Select a.Name FROM dbo.Region r INNER JOIN dbo.Area a ON r.regionID = a.regionID
INNER JOIN dbo.Location l ON a.areaID = l.areaID INNER JOIN Campus c on c.locationid = l.locationid INNER JOIN School s on s.campusID = c.id
WHERE r.Name like #RegionIn AND s.schoolID = #SchoolID )
SET #principalID = (SELECT [Employee Code] FROM [hcmdbserv].[HCM_LIVE].[dbo].[vw_BI_Principal_Info] WHERE [Job Status] = 'Active' AND [End Date_H] is NULL
AND [School ID_K] = #SchoolID)
SET #principalName = (SELECT ISNULL(First_Name,'') +' '+ISNULL(Name,'') FROM [hcmdbserv].[HCM_LIVE].[dbo].[vw_BI_Principal_Info] WHERE [Job Status] = 'Active' AND [End Date_H] is NULL
AND [School ID_K] = #SchoolID)
SET #ageing = (SELECT (SELECT DateDiff(DAY,(SELECT MAX([TimeStamp]) as LastDate),getdate())) FROM app_AuditLog WHERE InFunction ='StudentDataController.Get' AND OnTask = 'School' AND ObjectData = #SchoolID)
SET #ssr = (select top 1 totalStrength from Academics_Master where schoolId = #SchoolID order by id desc)
SET #noDays = (SELECT dbo.ufn_GetWeekDays(#EndDate,#StartDate))
SET #totalClasses = ((SELECT COUNT(*) FROM School_Classes WHERE schoolID=#SchoolID)*#noDays)
SET #classesAttendance = (SELECT ISNULL(SUM(a.classes),0) from (SELECT DISTINCT a.for_date, COUNT(DISTINCT classID) as classes FROM School_Classes sc
INNER JOIN app_attendance a on a.schoolclass_id = sc.Id WHERE schoolID =#SchoolID AND a.for_date BETWEEN DATEADD(DAY,-30,getdate())
AND getdate() GROUP BY a.for_date) a)
if (#classesAttendance = 0) BEGIN SET #percentage = 0 END
ELSE BEGIN SET #percentage = (#classesAttendance *100.0 /#totalClasses) END
IF (#principalID is NULL) BEGIN SET #principalID = '' END
IF (#principalName is NULL) BEGIN SET #principalName = '' END
IF (#ageing IS NULL) BEGIN SET #ageing = 0 END
IF (#totalClasses IS NULL) BEGIN SET #totalClasses = 0 END
IF (#classesAttendance IS NULL) BEGIN SET #classesAttendance = 0 END
IF (#percentage IS NULL) BEGIN SET #percentage = 0 END
IF (#ssr IS NULL) BEGIN SET #ssr = 0 END
INSERT INTO #FinalData (Region,Area,[School ID],[School Name],[Principal Code],[Principal Name],Ageing,[Student Strength],[Classes Attendance],[Total Classes],[Precentage (%)])
VALUES (#region,#area,#SchoolID,#schoolName,#principalID,#principalName,#ageing,#ssr,#classesAttendance,#totalClasses,#percentage)
FETCH NEXT FROM AllSchools INTO #SchoolID
END
CLOSE AllSchools
DEALLOCATE AllSchools
SELECT * FROM #FinalData fd order by fd.[Precentage (%)] asc, fd.Ageing desc,fd.Area asc,fd.Region
SET #sumTotalClasses= (SELECT SUM([Total Classes]) FROM #FinalData)
SET #sumAgeing= (SELECT SUM(Ageing) FROM #FinalData)
SET #countAgeing = (SELECT COUNT(Ageing) FROM #FinalData)
SET #sumClassesAttendance= (SELECT SUM([Classes Attendance]) FROM #FinalData)
SET #sumStudentStrength= (SELECT SUM([Student Strength]) FROM #FinalData)
--SET #averagePercentage= (SELECT CAST( (SUM([Classes Attendance])/SUM([Total Classes]) * 100) as FLOAT) FROM #FinalData)
SELECT #sumAgeing as [Sum Ageing],#countAgeing as [Count Ageing],#sumClassesAttendance as [Sum Classes],#sumStudentStrength as [Sum Student],
#sumTotalClasses as [Sum Total]
END

Locking From Temp Table - SQL 2008 R2

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

MSSQL merge with distributed transaction alternative

I have a distributed transaction where I need to merge into the target remote table.
Now MERGE INTO isn't allowed according to MSDN: “target_table cannot be a remote table”.
So my workaround goes as follows: 0. begin distributed transaction 1. define a cursor 2. open it 3. if cursor has at least one record (CURSOR_STATUS()=1) fetch next 4. if exists (select top 1 * from target_remote_table where id = #myCurrentCursorId) -> when true update target_remote_table when false insert into target_remote_table 5. commit/rollback distributed transaction depending on trancount and xact_state
It works but I know that cursors are evil and you shouldn't use them. So I want to ask if there is any other way I could solve this by not using cursors?
USE [My_DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[my_proc_merge_into_remote_table]
#ID_A INT,
#ID_B INT
AS
BEGIN
SET NOCOUNT ON;
-- CURSOR VALUES
DECLARE #field_A INT
DECLARE #field_B INT
DECLARE #field_C INT
DECLARE #field_D BIT
DECLARE #field_E INT
DECLARE #field_F DATETIME
DECLARE #field_G VARCHAR(20)
DECLARE #field_H DATETIME
DECLARE #field_I VARCHAR(20)
BEGIN TRY
BEGIN DISTRIBUTED TRANSACTION
-- CURSOR !!
DECLARE my_cursor CURSOR FOR
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = #ID_B
AND a.ID_A = #ID_A;
OPEN my_cursor;
-- check if cursor result set has at least one row
IF CURSOR_STATUS('global', 'my_cursor') = 1 BEGIN
FETCH NEXT FROM my_cursor
INTO #field_A,
#field_B,
#field_C,
#field_D,
#field_E,
#field_F,
#field_G,
#field_H,
#field_I;
WHILE ##FETCH_STATUS = 0 BEGIN
-- HINT: MY_REMOTE_TARGET_TABLE is a Synonym which already points to the correct database and table
IF EXISTS(SELECT TOP 1 * FROM MY_REMOTE_TARGET_TABLE WHERE field_A = #field_A AND field_B = #field_B AND field_C = #field_C AND field_E = #field_E)
UPDATE MY_REMOTE_TARGET_TABLE SET field_D = #field_D, field_H = #field_H, field_I = #field_I;
ELSE
INSERT INTO MY_REMOTE_TARGET_TABLE (field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I) VALUES (#field_A, #field_B, #field_C, #field_D, #field_E, #field_F, #field_G, #field_H, #field_I);
FETCH NEXT FROM my_cursor
INTO #field_A,
#field_B,
#field_C,
#field_D,
#field_E,
#field_F,
#field_G,
#field_H,
#field_I;
END;
END;
CLOSE my_cursor;
DEALLOCATE my_cursor;
IF (##TRANCOUNT > 0 AND XACT_STATE() = 1)
BEGIN
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
IF (##TRANCOUNT > 0 AND XACT_STATE() = -1)
ROLLBACK TRANSACTION
END CATCH;
END
Here you go, first inner join target and source to update, then left join to insert missing.
;WITH CTE_Source AS
(
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = #ID_B
AND a.ID_A = #ID_A;
)
UPDATE trgt
SET trgt.field_D = src.field_D, trgt.field_H = src.field_H, trgt.field_I = src.field_I
FROM MY_REMOTE_TARGET_TABLE trgt
INNER JOIN CTE_Source src ON src.field_A = trgt.field_A AND src.field_B = trgt.field_B AND src.field_C = trgt.field_C AND src.field_E = trgt.field_E
;WITH CTE_Source AS
(
SELECT b.field_A ,
b.field_B,
c.field_C,
a.field_D,
a.field_E,
GETDATE() AS field_F,
a.field_G,
GETDATE() AS field_H,
a.field_I
FROM dbo.source_tbl a
LEFT JOIN dbo.base_element_tbl l
ON a.obj_id = l.obj_id AND a.element_id = l.element_id
INNER JOIN dbo.base_obj_tbl b
ON a.obj_id = b.obj_id
INNER JOIN dbo.element_tbl c
ON a.element_id = c.element_id
WHERE a.ID_B = #ID_B
AND a.ID_A = #ID_A;
)
INSERT INTO MY_REMOTE_TARGET_TABLE (field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I)
SELECT field_A, field_B, field_C, field_D, field_E, field_F, field_G, field_H, field_I
FROM CTE_Soure src
LEFT JOIN MY_REMOTE_TARGET_TABLE trgt ON src.field_A = trgt.field_A AND src.field_B = trgt.field_B AND src.field_C = trgt.field_C AND src.field_E = trgt.field_E
WHERE trgt.field_A IS NULL