insert into select from inner join where not exists - sql

I have this SQL Server code. Everything works except it duplicates rows with same RightsId and UserId. The where not exists clause is not working.
Any help is appreciated.
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT
NEWID(),
#changedUserId,
N'Process ' + #rightsTypeSuffix,
ptm.ProcessInstance_id,
getdate(),
#loggedInUserId
FROM
dbo.ProcessTeamMembers ptm WITH (NOLOCK)
INNER JOIN
dbo.Users u WITH (NOLOCK) ON ptm.TeamMemberProfile_id = u.ProfileID
AND u.Id = #changedUserId
AND ptm.TenantId = #tenantId
INNER JOIN
dbo.ProcessInstances p_i WITH (NOLOCK) ON p_i.Id = ptm.ProcessInstance_id
AND p_i.DeletedOn IS NULL
WHERE
NOT EXISTS (SELECT *
FROM UserAccessRights uar WITH (NOLOCK)
WHERE uar.UserId = #changedUserId
AND uar.RightsId = ptm.ProcessInstance_id)

Your duplicates are probably coming from within the query, rather than from existing rows in the table. Possibly, the problem is that the select distinct isn't doing anything -- because newid() is always unique.
My recommendation is to change the id column to have a default value of newid(). Then you don't need to insert it and the select distinct will work. Absent that, you can fix the query:
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT NEWID(), #changedUserId, N'Process ' + #rightsTypeSuffix,
ProcessInstance_id, getdate(), #loggedInUserId
FROM (SELECT DISTINCT ptm.ProcessInstance_id
FROM dbo.ProcessTeamMembers ptm WITH (NOLOCK) INNER JOIN
dbo.Users u WITH (NOLOCK)
ON ptm.TeamMemberProfile_id = u.ProfileID AND
u.Id = #changedUserId AND
ptm.TenantId = #tenantId INNER JOIN
dbo.ProcessInstances p_i WITH (NOLOCK)
ON p_i.Id = ptm.ProcessInstance_id AND
p_i.DeletedOn IS NULL
WHERE NOT EXISTS (SELECT 1
FROM UserAccessRights uar WITH (NOLOCK)
WHERE uar.UserId = #changedUserId AND
uar.RightsId = ptm.ProcessInstance_id
)
) t;
Hmmm, as I think about this, perhaps you should be using TOP 1 rather than SELECT DISTINCT. I'm not sure which columns cause the problem on the distinct, but you are inserting the same value in many columns, so more than one row might cause an issue.

Try the "Left Excluding Join" (See Visual Representation of SQL Joins) instead of the WHERE NOT EXISTS clause.
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT
NEWID(),
#changedUserId,
N'Process ' + #rightsTypeSuffix,
ptm.ProcessInstance_id,
getdate(),
#loggedInUserId
FROM
dbo.ProcessTeamMembers ptm
INNER JOIN
dbo.Users u ON ptm.TeamMemberProfile_id = u.ProfileID
AND u.Id = #changedUserId
AND ptm.TenantId = #tenantId
INNER JOIN
dbo.ProcessInstances p_i ON p_i.Id = ptm.ProcessInstance_id
AND p_i.DeletedOn IS NULL
LEFT JOIN UserAccessRights uar
ON uar.UserId = u.Id
AND uar.RightsId = ptm.ProcessInstance_id
WHERE
uar.Id IS NULL -- Replace with the actual pkey on UserAccessRights if not Id

Related

SQL IN clause in where condition causing performance issue with large data

The following query works fine in my database but it is giving huge performance issues in customer DB. I know that I am using the IN clause in the where condition which is giving me this problem. But I don't know how to fix this.
declare #AccountId int
set #AccountId = 1200
declare #IsLinkedAccountsNotes bit
set #IsLinkedAccountsNotes =1
declare #EventType varchar(100)
set #EventType = ''
SELECT
u.loginName as InteractionLoginName,
u.userName as InteractionUserName,
e.*
FROM
lat.events e
INNER JOIN dbo.MasterEvents me ON me.EventId = e.EventId
LEFT JOIN dbo.Users u ON e.UserId = u.ID
WHERE
(me.AccountId = #AccountId OR
(#IsLinkedAccountsNotes = 1 AND me.AccountId IN (SELECT DISTINCT [number] FROM dbo.Linking_LinkedAccounts WHERE linked_number = #AccountId) AND e.EventType = 'AccountNoteAdded'))
I know that the second condition in where clause is causing the problem. And I have seen in various posts that using a join will solve this problem. But I am not getting how to use join inside where condition.
Or is there any other approach for the same.
Please help.
Your problem is likely that this is a "catch all query". You can try splitting the cases out as below
SELECT u.loginName AS InteractionLoginName,
u.userName AS InteractionUserName,
e.*
FROM lat.events e
INNER JOIN dbo.MasterEvents me
ON me.EventId = e.EventId
LEFT JOIN dbo.Users u
ON e.UserId = u.ID
WHERE me.AccountId = #AccountId
UNION ALL
SELECT u.loginName AS InteractionLoginName,
u.userName AS InteractionUserName,
e.*
FROM lat.events e
INNER JOIN dbo.MasterEvents me
ON me.EventId = e.EventId
LEFT JOIN dbo.Users u
ON e.UserId = u.ID
WHERE #IsLinkedAccountsNotes = 1
AND e.EventType = 'AccountNoteAdded'
AND me.AccountId IN (SELECT [number]
FROM dbo.Linking_LinkedAccounts
WHERE linked_number = #AccountId
AND [number] <> #AccountId)
Could try something like
JOIN (SELECT DISTINCT [number] FROM dbo.Linking_LinkedAccounts WHERE linked_number = #AccountId) lla ON lla.number = me.AccountId
LEFT JOIN and filter out null values in where condition.
EXISTS instead of IN.

JOIN / LEFT JOIN conflict in SQL Server

I have a tricky query. I need to select all recent versions of 2 types of members of administrator groups. Here is the query:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
This query will return all the administrator groups. The next step will be getting the members of these groups. Since I have 2 types of memberships (Explicit, Computed), I will have to use a LEFT JOIN to make sure that I am not excluding any rows.
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
-- The JOIN bellow can be excluded but it is here just to clarify the architecture
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
The last piece in the puzzle is to get the latest version of each member. For that I will have to use JOIN to exclude older versions:
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
and
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The full query will be:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The issue is clear: The 2 JOIN to exclude old versions are also applied to the select statement and clearly no rows are returned. What would be the best solution to escape such situation and to return the intended values?
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ComputedMember
) cm ON refMem.ObjectUID = cm.GroupObjectID and cm.ID = cm.maxID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ExplicitMember
) em ON refMem.ObjectUID = em.GroupObjectID and em.ID = em.maxID
where cm.ID = cm.MaxID
What about using LEFT join in your last two joins?
LEFT JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
And then in Where clause filter values as:
WHERE MostRecentCM.MaxId IS NOT NULL
OR
MostRecentEM.MaxId IS NOT NULL

How to perform a LEFT JOIN in SQL Server between two SELECT statements?

I have two SELECT statements in SQL Server like these:
(SELECT [UserID] FROM [User])
(SELECT [TailUser], [Weight] FROM [Edge] WHERE [HeadUser] = 5043)
I want to perform a LEFT JOIN between these two SELECT statements on [UserID] attribute and [TailUser] attribute. I want to join existent records in second query with the corresponding records in first query and NULL value for absent records. How can I do this?
SELECT * FROM
(SELECT [UserID] FROM [User]) a
LEFT JOIN (SELECT [TailUser], [Weight] FROM [Edge] WHERE [HeadUser] = 5043) b
ON a.UserId = b.TailUser
SELECT [UserID] FROM [User] u LEFT JOIN (
SELECT [TailUser], [Weight] FROM [Edge] WHERE [HeadUser] = 5043) t on t.TailUser=u.USerID
select *
from user
left join edge
on user.userid = edge.tailuser
and edge.headuser = 5043
Try this:
SELECT user.userID, edge.TailUser, edge.Weight
FROM user
LEFT JOIN edge ON edge.HeadUser = User.UserID
WHERE edge.HeadUser=5043
OR
AND edge.HeadUser=5043
instead of a WHERE clause.

Single Line separated records in SQL SERVER Query result

I had a query that returned multiple rows from a table. Then I converted that query to this one:
;with mycte as
(select s.FirstName + ' ' + s.LastName as Name from ClientStaff cs
left outer join Staff s on s.Id = cs.StaffId
left outer join GeneralStatus gs on gs.Id = s.StatusId
where cs.ClientId = #clientId and gs.Name = 'Active')
select #staff = (select distinct staff = REPLACE(REPLACE(REPLACE((select Name AS [data()] FROM mycte a
order by a.Name for xml path),'</row><row>',', '),'</row>',''),'<row>','') from mycte b)
It returns those rows in a single comma-separated row.
Now I don't want comma-separated values, instead I want single-line-separated values.
Can anyone tell me if it is possible or not?
Thanks in advance.
declare #staff varchar(max)
;with mycte as
(
select distinct s.FirstName + ' ' + s.LastName as Name
from ClientStaff cs
left outer join Staff s on
s.Id = cs.StaffId
left outer join GeneralStatus gs on
gs.Id = s.StatusId
where cs.ClientId = #clientId and gs.Name = 'Active'
)
select #staff = isnull(#staff + char(13), '') + Name
from mycte b
print #staff

TSQL Conditionally Select Specific Value

This is a follow-up to #1644748 where I successfully answered my own question, but Quassnoi helped me to realize that it was the wrong question. He gave me a solution that worked for my sample data, but I couldn't plug it back into the parent stored procedure because I fail at SQL 2005 syntax. So here is an attempt to paint the broader picture and ask what I actually need.
This is part of a stored procedure that returns a list of items in a bug tracking application I've inherited. There are are over 100 fields and 26 joins so I'm pulling out only the mostly relevant bits.
SELECT
tickets.ticketid,
tickets.tickettype,
tickets_tickettype_lu.tickettypedesc,
tickets.stage,
tickets.position,
tickets.sponsor,
tickets.dev,
tickets.qa,
DATEDIFF(DAY, ticket_history_assignment.savedate, GETDATE()) as 'daysinqueue'
FROM
dbo.tickets WITH (NOLOCK)
LEFT OUTER JOIN dbo.tickets_tickettype_lu WITH (NOLOCK) ON tickets.tickettype = tickets_tickettype_lu.tickettypeid
LEFT OUTER JOIN dbo.tickets_history_assignment WITH (NOLOCK) ON tickets_history_assignment.ticketid = tickets.ticketid
AND tickets_history_assignment.historyid = (
SELECT
MAX(historyid)
FROM
dbo.tickets_history_assignment WITH (NOLOCK)
WHERE
tickets_history_assignment.ticketid = tickets.ticketid
GROUP BY
tickets_history_assignment.ticketid
)
WHERE
tickets.sponsor = #sponsor
The area of interest is the daysinqueue subquery mess. The tickets_history_assignment table looks roughly as follows
declare #tickets_history_assignment table (
historyid int,
ticketid int,
sponsor int,
dev int,
qa int,
savedate datetime
)
insert into #tickets_history_assignment values (1521402, 92774,20,14, 20, '2009-10-27 09:17:59.527')
insert into #tickets_history_assignment values (1521399, 92774,20,14, 42, '2009-08-31 12:07:52.917')
insert into #tickets_history_assignment values (1521311, 92774,100,14, 42, '2008-12-08 16:15:49.887')
insert into #tickets_history_assignment values (1521336, 92774,100,14, 42, '2009-01-16 14:27:43.577')
Whenever a ticket is saved, the current values for sponsor, dev and qa are stored in the tickets_history_assignment table with the ticketid and a timestamp. So it is possible for someone to change the value for qa, but leave sponsor alone.
What I want to know, based on all of these conditions, is the historyid of the record in the tickets_history_assignment table where the sponsor value was last changed so that I can calculate the value for daysinqueue. If a record is inserted into the history table, and only the qa value has changed, I don't want that record. So simply relying on MAX(historyid) won't work for me.
Quassnoi came up with the following which seemed to work with my sample data, but I can't plug it into the larger query, SQL Manager bitches about the WITH statement.
;WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticketid ORDER BY savedate DESC) AS rn
FROM #Table
)
SELECT rl.sponsor, ro.savedate
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.savedate
FROM rows rc
JOIN rows rn
ON rn.ticketid = rc.ticketid
AND rn.rn = rc.rn + 1
AND rn.sponsor <> rc.sponsor
WHERE rc.ticketid = rl.ticketid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
I played with it yesterday afternoon and got nowhere because I don't fundamentally understand what is going on here and how it should fit into the larger context.
So, any takers?
UPDATE
Ok, here's the whole thing. I've been switching some of the table and column names in an attempt to simplify things so here's the full unedited mess.
snip - old bad code
Here are the errors:
Msg 102, Level 15, State 1, Procedure usp_GetProjectRecordsByAssignment, Line 159
Incorrect syntax near ';'.
Msg 102, Level 15, State 1, Procedure usp_GetProjectRecordsByAssignment, Line 179
Incorrect syntax near ')'.
Line numbers are of course not correct but refer to
;WITH rows AS
And the ')' char after the WHERE rl.rn = 1
)
Respectively
Is there a tag for extra super long question?
UPDATE #2
Here is the finished query for anyone who may need this:
CREATE PROCEDURE [dbo].[usp_GetProjectRecordsByAssignment]
(
#assigned numeric(18,0),
#assignedtype numeric(18,0)
)
AS
SET NOCOUNT ON
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY recordid ORDER BY savedate DESC) AS rn
FROM projects_history_assignment
)
SELECT projects_records.recordid,
projects_records.recordtype,
projects_recordtype_lu.recordtypedesc,
projects_records.stage,
projects_stage_lu.stagedesc,
projects_records.position,
projects_position_lu.positiondesc,
CASE projects_records.clientrequested
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS clientrequested,
projects_records.reportingmethod,
projects_reportingmethod_lu.reportingmethoddesc,
projects_records.clientaccess,
projects_clientaccess_lu.clientaccessdesc,
projects_records.clientnumber,
projects_records.project,
projects_lu.projectdesc,
projects_records.version,
projects_version_lu.versiondesc,
projects_records.projectedversion,
projects_version_lu_projected.versiondesc AS projectedversiondesc,
projects_records.sitetype,
projects_sitetype_lu.sitetypedesc,
projects_records.title,
projects_records.module,
projects_module_lu.moduledesc,
projects_records.component,
projects_component_lu.componentdesc,
projects_records.loginusername,
projects_records.loginpassword,
projects_records.assistedusername,
projects_records.browsername,
projects_browsername_lu.browsernamedesc,
projects_records.browserversion,
projects_records.osname,
projects_osname_lu.osnamedesc,
projects_records.osversion,
projects_records.errortype,
projects_errortype_lu.errortypedesc,
projects_records.gsipriority,
projects_gsipriority_lu.gsiprioritydesc,
projects_records.clientpriority,
projects_clientpriority_lu.clientprioritydesc,
projects_records.scheduledstartdate,
projects_records.scheduledcompletiondate,
projects_records.projectedhours,
projects_records.actualstartdate,
projects_records.actualcompletiondate,
projects_records.actualhours,
CASE projects_records.billclient
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS billclient,
projects_records.billamount,
projects_records.status,
projects_status_lu.statusdesc,
CASE CAST(projects_records.assigned AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
WHEN '20000' THEN 'Client'
WHEN '30000' THEN 'Tech Support'
WHEN '40000' THEN 'LMI Tech Support'
WHEN '50000' THEN 'Upload'
WHEN '60000' THEN 'Spider'
WHEN '70000' THEN 'DB Admin'
ELSE rtrim(users_assigned.nickname) + ' ' + rtrim(users_assigned.lastname)
END AS assigned,
CASE CAST(projects_records.assigneddev AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assigneddev.nickname) + ' ' + rtrim(users_assigneddev.lastname)
END AS assigneddev,
CASE CAST(projects_records.assignedqa AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assignedqa.nickname) + ' ' + rtrim(users_assignedqa.lastname)
END AS assignedqa,
CASE CAST(projects_records.assignedsponsor AS VARCHAR(5))
WHEN '0' THEN 'N/A'
WHEN '10000' THEN 'Unassigned'
ELSE rtrim(users_assignedsponsor.nickname) + ' ' + rtrim(users_assignedsponsor.lastname)
END AS assignedsponsor,
projects_records.clientcreated,
CASE projects_records.clientcreated
WHEN '1' THEN 'Yes'
WHEN '0' THEN 'No'
END AS clientcreateddesc,
CASE projects_records.clientcreated
WHEN '1' THEN rtrim(clientusers_createuser.firstname) + ' ' + rtrim(clientusers_createuser.lastname) + ' (Client)'
ELSE rtrim(users_createuser.nickname) + ' ' + rtrim(users_createuser.lastname)
END AS createuser,
projects_records.createdate,
projects_records.savedate,
projects_resolution.sitesaffected,
projects_sitesaffected_lu.sitesaffecteddesc,
DATEDIFF(DAY, projects_history_assignment.savedate, GETDATE()) as 'daysinqueue',
projects_records.iOnHitList,
projects_records.changetype
FROM
dbo.projects_records WITH (NOLOCK)
LEFT OUTER JOIN dbo.projects_recordtype_lu WITH (NOLOCK) ON projects_records.recordtype = projects_recordtype_lu.recordtypeid
LEFT OUTER JOIN dbo.projects_stage_lu WITH (NOLOCK) ON projects_records.stage = projects_stage_lu.stageid
LEFT OUTER JOIN dbo.projects_position_lu WITH (NOLOCK) ON projects_records.position = projects_position_lu.positionid
LEFT OUTER JOIN dbo.projects_reportingmethod_lu WITH (NOLOCK) ON projects_records.reportingmethod = projects_reportingmethod_lu.reportingmethodid
LEFT OUTER JOIN dbo.projects_lu WITH (NOLOCK) ON projects_records.project = projects_lu.projectid
LEFT OUTER JOIN dbo.projects_version_lu WITH (NOLOCK) ON projects_records.version = projects_version_lu.versionid
LEFT OUTER JOIN dbo.projects_version_lu projects_version_lu_projected WITH (NOLOCK) ON projects_records.projectedversion = projects_version_lu_projected.versionid
LEFT OUTER JOIN dbo.projects_sitetype_lu WITH (NOLOCK) ON projects_records.sitetype = projects_sitetype_lu.sitetypeid
LEFT OUTER JOIN dbo.projects_module_lu WITH (NOLOCK) ON projects_records.module = projects_module_lu.moduleid
LEFT OUTER JOIN dbo.projects_component_lu WITH (NOLOCK) ON projects_records.component = projects_component_lu.componentid
LEFT OUTER JOIN dbo.projects_browsername_lu WITH (NOLOCK) ON projects_records.browsername = projects_browsername_lu.browsernameid
LEFT OUTER JOIN dbo.projects_osname_lu WITH (NOLOCK) ON projects_records.osname = projects_osname_lu.osnameid
LEFT OUTER JOIN dbo.projects_errortype_lu WITH (NOLOCK) ON projects_records.errortype = projects_errortype_lu.errortypeid
LEFT OUTER JOIN dbo.projects_resolution WITH (NOLOCK) ON projects_records.recordid = projects_resolution.recordid
LEFT OUTER JOIN dbo.projects_sitesaffected_lu WITH (NOLOCK) ON projects_resolution.sitesaffected = projects_sitesaffected_lu.sitesaffectedid
LEFT OUTER JOIN dbo.projects_gsipriority_lu WITH (NOLOCK) ON projects_records.gsipriority = projects_gsipriority_lu.gsipriorityid
LEFT OUTER JOIN dbo.projects_clientpriority_lu WITH (NOLOCK) ON projects_records.clientpriority = projects_clientpriority_lu.clientpriorityid
LEFT OUTER JOIN dbo.projects_status_lu WITH (NOLOCK) ON projects_records.status = projects_status_lu.statusid
LEFT OUTER JOIN dbo.projects_clientaccess_lu WITH (NOLOCK) ON projects_records.clientaccess = projects_clientaccess_lu.clientaccessid
LEFT OUTER JOIN dbo.users users_assigned WITH (NOLOCK) ON projects_records.assigned = users_assigned.userid
LEFT OUTER JOIN dbo.users users_assigneddev WITH (NOLOCK) ON projects_records.assigneddev = users_assigneddev.userid
LEFT OUTER JOIN dbo.users users_assignedqa WITH (NOLOCK) ON projects_records.assignedqa = users_assignedqa.userid
LEFT OUTER JOIN dbo.users users_assignedsponsor WITH (NOLOCK) ON projects_records.assignedsponsor = users_assignedsponsor.userid
LEFT OUTER JOIN dbo.users users_createuser WITH (NOLOCK) ON projects_records.createuser = users_createuser.userid
LEFT OUTER JOIN dbo.clientusers clientusers_createuser WITH (NOLOCK) ON projects_records.createuser = clientusers_createuser.userid
LEFT OUTER JOIN dbo.projects_history_assignment WITH (NOLOCK) ON projects_history_assignment.recordid = projects_records.recordid
AND projects_history_assignment.historyid = (
SELECT ro.historyid
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.historyid
FROM rows rc
JOIN rows rn
ON rn.recordid = rc.recordid
AND rn.rn = rc.rn + 1
AND rn.assigned <> rc.assigned
WHERE rc.recordid = rl.recordid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
AND rl.recordid = projects_records.recordid
)
WHERE
(#assignedtype='0' and projects_records.assigned = #assigned)
OR (#assignedtype='1' and projects_records.assigneddev = #assigned)
OR (#assignedtype='2' and projects_records.assignedqa = #assigned)
OR (#assignedtype='3' and projects_records.assignedsponsor = #assigned)
OR (#assignedtype='4' and projects_records.createuser = #assigned)
WITH rows AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ticketid ORDER BY savedate DESC) AS rn
FROM #Table
)
SELECT projects_records.recordid,
projects_records.recordtype,
/* skipped */
AND projects_history_assignment.historyid = (
SELECT ro.historyid
FROM rows rl
CROSS APPLY
(
SELECT TOP 1 rc.savedate
FROM rows rc
JOIN rows rn
ON rn.recordid = rc.recordid
AND rn.rn = rc.rn + 1
AND rn.assigned <> rc.assigned
WHERE rc.recordid = rl.recordid
ORDER BY
rc.rn
) ro
WHERE rl.rn = 1
AND rl.recordid = projects_records.recordid
)
Well, if that query does not work out -- you could always consider a trigger on the tickets_history_assignment table. You could use INSTEAD OF INSERT, UPDATE which fires before any changes are made, so you would have full control of what is about to change and what to do.