SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO /* Timeline-focused performance pass. Scope: - Keep the initial Timeline page from loading full character/asset lane data just to render scene-card summaries. - Keep project/book filters as early as possible inside heavy Timeline queries. - Add narrow supporting indexes for the Timeline warning, character, asset, and scene-overview paths. */ IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_ContinuityWarnings_TimelineActiveList' AND object_id = OBJECT_ID(N'dbo.ContinuityWarnings')) BEGIN CREATE INDEX IX_ContinuityWarnings_TimelineActiveList ON dbo.ContinuityWarnings(ProjectID, BookID, WarningSeverityID, WarningTypeID, SceneID, LastDetectedDate DESC, ContinuityWarningID DESC) INCLUDE (ValidationRunID, ChapterID, EntityType, EntityID, Message, Details, CreatedDate) WHERE IsDismissed = 0 AND IsIntentional = 0; END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_ContinuityWarnings_TimelineList' AND object_id = OBJECT_ID(N'dbo.ContinuityWarnings')) BEGIN CREATE INDEX IX_ContinuityWarnings_TimelineList ON dbo.ContinuityWarnings(ProjectID, BookID, SceneID, EntityType, EntityID, WarningTypeID, WarningSeverityID) INCLUDE (IsDismissed, IsIntentional, LastDetectedDate, ValidationRunID, ChapterID, Message, Details, CreatedDate); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneCharacters_SceneID_TimelineOverview' AND object_id = OBJECT_ID(N'dbo.SceneCharacters')) BEGIN CREATE INDEX IX_SceneCharacters_SceneID_TimelineOverview ON dbo.SceneCharacters(SceneID, CharacterID) INCLUDE (SceneCharacterID, RoleInSceneTypeID, PresenceTypeID, LocationID, EntryLocationID, ExitLocationID, AppearanceNotes, OutfitDescription, PhysicalCondition, EmotionalState, KnowledgeNotes, CreatedDate, UpdatedDate); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Books_Project_Active_Timeline' AND object_id = OBJECT_ID(N'dbo.Books')) BEGIN CREATE INDEX IX_Books_Project_Active_Timeline ON dbo.Books(ProjectID, IsArchived, BookID) INCLUDE (BookTitle, Subtitle, SortOrder, BookNumber); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Chapters_Book_Active_Timeline' AND object_id = OBJECT_ID(N'dbo.Chapters')) BEGIN CREATE INDEX IX_Chapters_Book_Active_Timeline ON dbo.Chapters(BookID, IsArchived, ChapterID) INCLUDE (ChapterNumber, ChapterTitle, SortOrder); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Scenes_Chapter_Active_Timeline' AND object_id = OBJECT_ID(N'dbo.Scenes')) BEGIN CREATE INDEX IX_Scenes_Chapter_Active_Timeline ON dbo.Scenes(ChapterID, IsArchived, SceneID) INCLUDE (SceneNumber, SceneTitle, SortOrder, POVCharacterID, PrimaryLocationID, RevisionStatusID); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_StoryAssets_Project_TimelineList' AND object_id = OBJECT_ID(N'dbo.StoryAssets')) BEGIN CREATE INDEX IX_StoryAssets_Project_TimelineList ON dbo.StoryAssets(ProjectID, IsArchived, Importance DESC, AssetName) INCLUDE (AssetKindID, CurrentStateID, CurrentLocationID, IsResolved, ShowInQuickAddBar, ImagePath, ThumbnailPath, CreatedDate, UpdatedDate); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetEvents_SceneID_TimelineOverview' AND object_id = OBJECT_ID(N'dbo.AssetEvents')) BEGIN CREATE INDEX IX_AssetEvents_SceneID_TimelineOverview ON dbo.AssetEvents(SceneID, StoryAssetID, UpdatedDate DESC) INCLUDE (AssetEventTypeID, EventTitle); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_AssetStates_Active_Project_Sort' AND object_id = OBJECT_ID(N'dbo.AssetStates')) BEGIN CREATE INDEX IX_AssetStates_Active_Project_Sort ON dbo.AssetStates(IsActive, ProjectID, SortOrder) INCLUDE (AssetKindID, StateName, Description, IsResolvedState); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_CharacterAttributeTypes_Active_Project_Sort' AND object_id = OBJECT_ID(N'dbo.CharacterAttributeTypes')) BEGIN CREATE INDEX IX_CharacterAttributeTypes_Active_Project_Sort ON dbo.CharacterAttributeTypes(IsActive, ProjectID, SortOrder) INCLUDE (AttributeName, DataType, IsNormallyStable); END; GO CREATE OR ALTER PROCEDURE dbo.ContinuityWarning_List @ProjectID int, @BookID int = NULL, @SceneID int = NULL, @EntityType nvarchar(80) = NULL, @EntityID int = NULL, @WarningTypeID int = NULL, @WarningSeverityID int = NULL, @IncludeDismissed bit = 0, @IncludeIntentional bit = 0 AS BEGIN SET NOCOUNT ON; IF @IncludeDismissed = 0 AND @IncludeIntentional = 0 BEGIN SELECT cw.ContinuityWarningID, cw.ValidationRunID, cw.ProjectID, cw.BookID, b.BookTitle, b.Subtitle AS BookSubtitle, cw.ChapterID, c.ChapterNumber, c.ChapterTitle, cw.SceneID, s.SceneNumber, s.SceneTitle, cw.EntityType, cw.EntityID, cw.WarningTypeID, wt.TypeName AS WarningTypeName, cw.WarningSeverityID, ws.SeverityName, cw.Message, cw.Details, cw.IsDismissed, cw.IsIntentional, cw.CreatedDate, cw.LastDetectedDate FROM dbo.ContinuityWarnings cw INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID LEFT JOIN dbo.Books b ON b.BookID = cw.BookID LEFT JOIN dbo.Chapters c ON c.ChapterID = cw.ChapterID LEFT JOIN dbo.Scenes s ON s.SceneID = cw.SceneID WHERE cw.ProjectID = @ProjectID AND cw.IsDismissed = 0 AND cw.IsIntentional = 0 AND (@BookID IS NULL OR cw.BookID = @BookID) AND (@SceneID IS NULL OR cw.SceneID = @SceneID) AND (@EntityType IS NULL OR cw.EntityType = @EntityType) AND (@EntityID IS NULL OR cw.EntityID = @EntityID) AND (@WarningTypeID IS NULL OR cw.WarningTypeID = @WarningTypeID) AND (@WarningSeverityID IS NULL OR cw.WarningSeverityID = @WarningSeverityID) ORDER BY ws.SortOrder DESC, cw.LastDetectedDate DESC, cw.ContinuityWarningID DESC OPTION (RECOMPILE); RETURN; END; SELECT cw.ContinuityWarningID, cw.ValidationRunID, cw.ProjectID, cw.BookID, b.BookTitle, b.Subtitle AS BookSubtitle, cw.ChapterID, c.ChapterNumber, c.ChapterTitle, cw.SceneID, s.SceneNumber, s.SceneTitle, cw.EntityType, cw.EntityID, cw.WarningTypeID, wt.TypeName AS WarningTypeName, cw.WarningSeverityID, ws.SeverityName, cw.Message, cw.Details, cw.IsDismissed, cw.IsIntentional, cw.CreatedDate, cw.LastDetectedDate FROM dbo.ContinuityWarnings cw INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID LEFT JOIN dbo.Books b ON b.BookID = cw.BookID LEFT JOIN dbo.Chapters c ON c.ChapterID = cw.ChapterID LEFT JOIN dbo.Scenes s ON s.SceneID = cw.SceneID WHERE cw.ProjectID = @ProjectID AND (@BookID IS NULL OR cw.BookID = @BookID) AND (@SceneID IS NULL OR cw.SceneID = @SceneID) AND (@EntityType IS NULL OR cw.EntityType = @EntityType) AND (@EntityID IS NULL OR cw.EntityID = @EntityID) AND (@WarningTypeID IS NULL OR cw.WarningTypeID = @WarningTypeID) AND (@WarningSeverityID IS NULL OR cw.WarningSeverityID = @WarningSeverityID) AND (@IncludeDismissed = 1 OR cw.IsDismissed = 0) AND (@IncludeIntentional = 1 OR cw.IsIntentional = 0) ORDER BY ws.SortOrder DESC, cw.LastDetectedDate DESC, cw.ContinuityWarningID DESC OPTION (RECOMPILE); END; GO CREATE OR ALTER PROCEDURE dbo.StoryAsset_ListByProject @ProjectID int AS BEGIN SET NOCOUNT ON; CREATE TABLE #ProjectLocationPaths ( LocationID int NOT NULL PRIMARY KEY, LocationName nvarchar(200) NOT NULL, LocationPath nvarchar(max) NOT NULL ); ;WITH ProjectLocationTree AS ( SELECT LocationID, LocationName, CAST(LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations WHERE ProjectID = @ProjectID AND ParentLocationID IS NULL AND IsArchived = 0 UNION ALL SELECT child.LocationID, child.LocationName, CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations child INNER JOIN ProjectLocationTree parent ON parent.LocationID = child.ParentLocationID WHERE child.ProjectID = @ProjectID AND child.IsArchived = 0 ) INSERT #ProjectLocationPaths (LocationID, LocationName, LocationPath) SELECT LocationID, LocationName, LocationPath FROM ProjectLocationTree; SELECT sa.StoryAssetID, sa.ProjectID, sa.AssetName, sa.AssetKindID, ak.KindName, sa.Description, sa.Importance, sa.CurrentStateID, ast.StateName AS CurrentStateName, sa.CurrentLocationID, location.LocationName AS CurrentLocationName, location.LocationPath AS CurrentLocationPath, sa.IsResolved, sa.ShowInQuickAddBar, sa.ImagePath, sa.ThumbnailPath, sa.CreatedDate, sa.UpdatedDate, sa.IsArchived FROM dbo.StoryAssets sa INNER JOIN dbo.AssetKinds ak ON ak.AssetKindID = sa.AssetKindID LEFT JOIN dbo.AssetStates ast ON ast.AssetStateID = sa.CurrentStateID LEFT JOIN #ProjectLocationPaths location ON location.LocationID = sa.CurrentLocationID WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 ORDER BY sa.Importance DESC, sa.AssetName; END; GO CREATE OR ALTER PROCEDURE dbo.AssetLookup_All @ProjectID int = NULL AS BEGIN SET NOCOUNT ON; SELECT AssetKindID, KindName, SortOrder, IsActive FROM dbo.AssetKinds WHERE IsActive = 1 ORDER BY SortOrder; SELECT AssetStateID, ProjectID, AssetKindID, StateName, SortOrder, Description, IsResolvedState, IsActive FROM dbo.AssetStates WHERE IsActive = 1 AND (@ProjectID IS NULL OR ProjectID IS NULL OR ProjectID = @ProjectID) ORDER BY SortOrder; SELECT AssetEventTypeID, TypeName, MarkerText, SortOrder, IsActive FROM dbo.AssetEventTypes WHERE IsActive = 1 ORDER BY SortOrder; SELECT AssetDependencyTypeID, TypeName, SortOrder, IsValidatingDependency, IsActive FROM dbo.AssetDependencyTypes WHERE IsActive = 1 ORDER BY SortOrder; SELECT AssetCustodyEventTypeID, TypeName, SortOrder, IsActive FROM dbo.AssetCustodyEventTypes WHERE IsActive = 1 ORDER BY SortOrder; SELECT CustodyRoleID, RoleName, SortOrder, IsActive FROM dbo.CustodyRoles WHERE IsActive = 1 ORDER BY SortOrder; END; GO CREATE OR ALTER PROCEDURE dbo.CharacterLookup_All @ProjectID int = NULL AS BEGIN SET NOCOUNT ON; SELECT CharacterRoleInSceneTypeID, TypeName, SortOrder, IsActive FROM dbo.CharacterRoleInSceneTypes WHERE IsActive = 1 ORDER BY SortOrder; SELECT PresenceTypeID, TypeName, SortOrder, IsActive FROM dbo.PresenceTypes WHERE IsActive = 1 ORDER BY SortOrder; SELECT CharacterAttributeTypeID, ProjectID, AttributeName, DataType, IsNormallyStable, SortOrder, IsActive FROM dbo.CharacterAttributeTypes WHERE IsActive = 1 AND (@ProjectID IS NULL OR ProjectID IS NULL OR ProjectID = @ProjectID) ORDER BY SortOrder; SELECT KnowledgeStateID, StateName, SortOrder, IsActive FROM dbo.KnowledgeStates WHERE IsActive = 1 ORDER BY SortOrder; SELECT rt.RelationshipTypeID, rt.TypeName, rt.IsPermanentDefault, rt.SortOrder, rt.IsActive, rt.RelationshipCategoryID, rc.CategoryName AS RelationshipCategoryName, rc.SortOrder AS CategorySortOrder FROM dbo.RelationshipTypes rt LEFT JOIN dbo.RelationshipCategories rc ON rc.RelationshipCategoryID = rt.RelationshipCategoryID WHERE rt.IsActive = 1 ORDER BY COALESCE(rc.SortOrder, 900), rt.SortOrder, rt.TypeName; SELECT RelationshipStateID, StateName, SortOrder, IsActive FROM dbo.RelationshipStates WHERE IsActive = 1 ORDER BY SortOrder; SELECT RelationshipCategoryID, CategoryName, SortOrder, IsActive FROM dbo.RelationshipCategories WHERE IsActive = 1 ORDER BY SortOrder, CategoryName; END; GO CREATE OR ALTER PROCEDURE dbo.CharacterTimeline_GetByProject @ProjectID int, @BookID int = NULL WITH RECOMPILE AS BEGIN SET NOCOUNT ON; CREATE TABLE #TimelineScenes ( SceneID int NOT NULL PRIMARY KEY, SceneNumber decimal(9,2) NOT NULL, SceneTitle nvarchar(200) NOT NULL, ChapterNumber decimal(9,2) NOT NULL, BookTitle nvarchar(200) NOT NULL, BookSubtitle nvarchar(200) NULL, BookSortOrder int NOT NULL, ChapterSortOrder int NOT NULL, SceneSortOrder int NOT NULL ); INSERT #TimelineScenes (SceneID, SceneNumber, SceneTitle, ChapterNumber, BookTitle, BookSubtitle, BookSortOrder, ChapterSortOrder, SceneSortOrder) SELECT s.SceneID, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle, b.Subtitle, b.SortOrder, ch.SortOrder, s.SortOrder FROM dbo.Books b INNER JOIN dbo.Chapters ch ON ch.BookID = b.BookID INNER JOIN dbo.Scenes s ON s.ChapterID = ch.ChapterID WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND ch.IsArchived = 0 AND s.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID); CREATE TABLE #TimelineCharacters ( CharacterID int NOT NULL PRIMARY KEY, ProjectID int NOT NULL, CharacterName nvarchar(200) NOT NULL, ShortName nvarchar(100) NULL, Sex nvarchar(50) NULL, BirthDate date NULL, AgeAtSeriesStart int NULL, AgeReferenceSceneID int NULL, Height nvarchar(50) NULL, EyeColour nvarchar(50) NULL, CharacterImportance int NULL, ShowInQuickAddBar bit NOT NULL, DefaultDescription nvarchar(max) NULL, CreatedDate datetime2 NOT NULL, UpdatedDate datetime2 NOT NULL, IsArchived bit NOT NULL ); INSERT #TimelineCharacters (CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived) SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived FROM dbo.Characters WHERE ProjectID = @ProjectID AND IsArchived = 0; CREATE TABLE #ProjectLocationPaths ( LocationID int NOT NULL PRIMARY KEY, LocationName nvarchar(200) NOT NULL, LocationPath nvarchar(max) NOT NULL ); ;WITH ProjectLocationTree AS ( SELECT LocationID, LocationName, CAST(LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations WHERE ProjectID = @ProjectID AND ParentLocationID IS NULL AND IsArchived = 0 UNION ALL SELECT child.LocationID, child.LocationName, CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations child INNER JOIN ProjectLocationTree parent ON parent.LocationID = child.ParentLocationID WHERE child.ProjectID = @ProjectID AND child.IsArchived = 0 ) INSERT #ProjectLocationPaths (LocationID, LocationName, LocationPath) SELECT LocationID, LocationName, LocationPath FROM ProjectLocationTree; SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, CharacterImportance, ShowInQuickAddBar, DefaultDescription, CreatedDate, UpdatedDate, IsArchived FROM #TimelineCharacters ORDER BY ISNULL(CharacterImportance, 0) DESC, CharacterName; SELECT sc.SceneCharacterID, sc.SceneID, sc.CharacterID, c.ProjectID, c.CharacterName, c.ShortName, c.BirthDate, c.AgeAtSeriesStart, sc.RoleInSceneTypeID, role.TypeName AS RoleInSceneTypeName, sc.PresenceTypeID, presence.TypeName AS PresenceTypeName, sc.LocationID, location.LocationName, location.LocationPath, sc.EntryLocationID, entry.LocationName AS EntryLocationName, sc.ExitLocationID, exitLocation.LocationName AS ExitLocationName, sc.AppearanceNotes, sc.OutfitDescription, sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes, s.SceneNumber, s.SceneTitle, s.ChapterNumber, s.BookTitle, s.BookSubtitle, sc.CreatedDate, sc.UpdatedDate FROM #TimelineScenes s INNER JOIN dbo.SceneCharacters sc ON sc.SceneID = s.SceneID INNER JOIN #TimelineCharacters c ON c.CharacterID = sc.CharacterID LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID LEFT JOIN #ProjectLocationPaths location ON location.LocationID = sc.LocationID LEFT JOIN #ProjectLocationPaths entry ON entry.LocationID = sc.EntryLocationID LEFT JOIN #ProjectLocationPaths exitLocation ON exitLocation.LocationID = sc.ExitLocationID ORDER BY s.BookSortOrder, s.ChapterSortOrder, s.SceneSortOrder, c.CharacterName; END; GO CREATE OR ALTER PROCEDURE dbo.Timeline_SceneOverviews @ProjectID int, @BookID int = NULL AS BEGIN SET NOCOUNT ON; CREATE TABLE #TimelineScenes ( SceneID int NOT NULL PRIMARY KEY, BookSortOrder int NOT NULL, ChapterSortOrder int NOT NULL, SceneSortOrder int NOT NULL ); INSERT #TimelineScenes (SceneID, BookSortOrder, ChapterSortOrder, SceneSortOrder) SELECT s.SceneID, b.SortOrder, c.SortOrder, s.SortOrder FROM dbo.Books b INNER JOIN dbo.Chapters c ON c.BookID = b.BookID INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 AND c.IsArchived = 0 AND s.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID); CREATE TABLE #ProjectLocationPaths ( LocationID int NOT NULL PRIMARY KEY, LocationName nvarchar(200) NOT NULL, LocationPath nvarchar(max) NOT NULL ); ;WITH ProjectLocationTree AS ( SELECT LocationID, LocationName, CAST(LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations WHERE ProjectID = @ProjectID AND ParentLocationID IS NULL AND IsArchived = 0 UNION ALL SELECT child.LocationID, child.LocationName, CAST(parent.LocationPath + N' > ' + child.LocationName AS nvarchar(max)) AS LocationPath FROM dbo.Locations child INNER JOIN ProjectLocationTree parent ON parent.LocationID = child.ParentLocationID WHERE child.ProjectID = @ProjectID AND child.IsArchived = 0 ) INSERT #ProjectLocationPaths (LocationID, LocationName, LocationPath) SELECT LocationID, LocationName, LocationPath FROM ProjectLocationTree; SELECT ts.SceneID, sc.CharacterID, ch.CharacterName, CONVERT(bit, CASE WHEN role.TypeName LIKE N'%POV%' THEN 1 ELSE 0 END) AS IsPov, CONVERT(int, NULL) AS StoryAssetID, CONVERT(nvarchar(200), NULL) AS AssetName, CONVERT(int, NULL) AS AssetImportance, CONVERT(nvarchar(100), NULL) AS AssetEventTypeName, location.LocationPath AS LocationName FROM #TimelineScenes ts INNER JOIN dbo.SceneCharacters sc ON sc.SceneID = ts.SceneID INNER JOIN dbo.Characters ch ON ch.CharacterID = sc.CharacterID AND ch.ProjectID = @ProjectID AND ch.IsArchived = 0 LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID LEFT JOIN #ProjectLocationPaths location ON location.LocationID = sc.LocationID UNION ALL SELECT SceneID, CharacterID, CharacterName, IsPov, StoryAssetID, AssetName, AssetImportance, AssetEventTypeName, LocationName FROM ( SELECT ts.SceneID, CONVERT(int, NULL) AS CharacterID, CONVERT(nvarchar(200), NULL) AS CharacterName, CONVERT(bit, 0) AS IsPov, sa.StoryAssetID, sa.AssetName, sa.Importance AS AssetImportance, aet.TypeName AS AssetEventTypeName, CONVERT(nvarchar(max), NULL) AS LocationName, ROW_NUMBER() OVER (PARTITION BY ts.SceneID, sa.StoryAssetID ORDER BY ae.UpdatedDate DESC, ae.AssetEventID DESC) AS rn FROM #TimelineScenes ts INNER JOIN dbo.AssetEvents ae ON ae.SceneID = ts.SceneID INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ae.StoryAssetID AND sa.ProjectID = @ProjectID AND sa.IsArchived = 0 INNER JOIN dbo.AssetEventTypes aet ON aet.AssetEventTypeID = ae.AssetEventTypeID ) assetRows WHERE rn = 1 ORDER BY SceneID; END; GO