SQL Server trigger on a field that's updated - sql

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.

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

how to make inner join query for getting multiple tables selected column

i just working out project school management. now i just made query for retrieve other table columns. here is my query :
ALTER PROCEDURE [dbo].[GetTeacherList]
(
#teacherid varchar(5) = null,
#classid varchar(5) = null,
#sectionid varchar(5) = null,
#subjectid varchar(5) = null
)
AS
BEGIN
SET NOCOUNT ON;
select *,right('00000' + CAST(t.[PK_PID] AS varchar(5)) ,5) as ID, c.ClassName, su.SubjectName, s.SectionName
from teachers t
inner join teacherclassassign tc on t.PK_PID = tc.TeacherID or (t.PK_PID is null and tc.TeacherID is null )
inner join classes c on c.PK_PID = tc.ClassID or (c.PK_PID is not null and tc.ClassID is null)
inner join sections s on s.PK_PID = tc.SectionID or (s.PK_PID is not null and tc.SectionID is null)
inner join subjects su on su.PK_PID = tc.SubjectID or (su.PK_PID is not null and tc.SubjectID is null)
where 1=1
and (#teacherid is null or tc.[TeacherID] = CONVERT(INT,#teacherid))
and (#classid is null or tc.[ClassID] = CONVERT(INT,#classid))
and (#sectionid is null or tc.[SectionID] = CONVERT(INT,#sectionid))
and (#subjectid is null or tc.[SubjectID] = CONVERT(INT,#subjectid))
order by t.PK_PID asc
END
how ever it's return me two rows how ever i want all rows from table teachers.
here is rows data i want :
and here is all data of teachers :
how i achieve this result..please guys help me.
You need to replace the first inner join with the LEFT Join as you want all teachers.
Below i have changed the query,See if this fixes the problem
SET NOCOUNT ON;
select *,right('00000' + CAST(t.[PK_PID] AS varchar(5)) ,5) as ID, c.ClassName, su.SubjectName, s.SectionName
from teachers t
LEFT join teacherclassassign tc on t.PK_PID = tc.TeacherID or (t.PK_PID is null and tc.TeacherID is null )
inner join classes c on c.PK_PID = tc.ClassID or (c.PK_PID is not null and tc.ClassID is null)
inner join sections s on s.PK_PID = tc.SectionID or (s.PK_PID is not null and tc.SectionID is null)
inner join subjects su on su.PK_PID = tc.SubjectID or (su.PK_PID is not null and tc.SubjectID is null)
where 1=1
and (#teacherid is null or tc.[TeacherID] = CONVERT(INT,#teacherid))
and (#classid is null or tc.[ClassID] = CONVERT(INT,#classid))
and (#sectionid is null or tc.[SectionID] = CONVERT(INT,#sectionid))
and (#subjectid is null or tc.[SubjectID] = CONVERT(INT,#subjectid))
order by t.PK_PID asc
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

Querying Different Table If First Result is Empty

I'm writing a stored procedure to look in two tables PersonTbl, UserTbl. First search the PersonTbl for an userID and if the userID is there get an email address from the UserTbl and return both. However if the ID is not there then search two other tables (PersonsPendingTbl, UsersPendingTbl) for the ID and email. If the ID is not found once again, return null/nulls. So far this is what I've come up with, but not sure if it's the best way of writing it. Let me know if there's any changes you would recommend;
create PROCEDURE [dbo].[MyNewSP]
#ID VARCHAR(MAX)
AS
DECLARE #userID VARCHAR(50)
DECLARE #Email VARCHAR(100)
DECLARE #currentlyActive CHAR
BEGIN
SELECT
#userID = userTbl.ID ,
#Email = personTbl.EMAIL,
#currentlyActive = 'Y'
FROM
personTbl
INNER JOIN userTbl ON personTbl.person_id = userTbl.person_id
WHERE
( userTbl.ID = #ID )
IF ( #userID != #ID ) --Check to see if null
BEGIN
SELECT #currentlyActive = 'N'
SELECT
upt.ID ,
ppt.EMAIL,
#currentlyActive
FROM
PersonsPendingTbl ppt
INNER JOIN dbo.UsersPendingTbl upt ON ppt.person_id = upt.person_id
WHERE
( upt.ID = #ID )
END
ELSE
BEGIN
SELECT
#userID ,
#Email ,
#currentlyActive
END
END
Make a union of both results, but always pick the first row. If the user is registered as Active AND Inactive, it'll return the Active one:
Select *
from (
SELECT userTbl.ID AS UID, personTbl.EMAIL as email, 'Y' as active
FROM personTbl
JOIN userTbl ON personTbl.person_id = userTbl.person_id
WHERE (userTbl.ID = #ID)
union all
SELECT upt.ID AS UID, ppt.EMAIL as email, 'N' as active
FROM PersonsPendingTbl ppt
INNER JOIN dbo.UsersPendingTbl upt ON ppt.person_id = upt.person_id
WHERE (upt.ID = #ID)) user
limit 0,1
I'm not sure about uniqueness of values between your pending and non-pending table, but this should be close enough to get you going.
select
case
when p.PersonId is null and pp.personPendingId is null then null
else userid
end as userid,
case
when p.PersonId is not null then p.email
when p.PersonId is null and pp.PersonPendingID is not null then pp.email
else null
end as email,
case
when p.PersonId is not null then 'Y'
when p.PersonId is null and pp.PersonPendingID is not null then 'N'
else null
end as CurrentlyActive
from userTbl u
left join PersonTbl p on u.Person_id = p.PersonId
left join userPendingTbl up on u.UserId = up.UserPendingId
left join PersonPendingTbl pp on up.personPendingId = pp.PersonPendingID
where u.UserId = #ID