SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF COL_LENGTH(N'dbo.Chapters', N'POVSource') IS NULL ALTER TABLE dbo.Chapters ADD POVSource nvarchar(40) NULL; GO IF COL_LENGTH(N'dbo.Chapters', N'POVConfidence') IS NULL ALTER TABLE dbo.Chapters ADD POVConfidence decimal(5,2) NULL; GO IF COL_LENGTH(N'dbo.Chapters', N'POVEvidence') IS NULL ALTER TABLE dbo.Chapters ADD POVEvidence nvarchar(500) NULL; GO IF COL_LENGTH(N'dbo.Chapters', N'POVSuggestedName') IS NULL ALTER TABLE dbo.Chapters ADD POVSuggestedName nvarchar(200) NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'POVSource') IS NULL ALTER TABLE dbo.Scenes ADD POVSource nvarchar(40) NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'POVConfidence') IS NULL ALTER TABLE dbo.Scenes ADD POVConfidence decimal(5,2) NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'POVEvidence') IS NULL ALTER TABLE dbo.Scenes ADD POVEvidence nvarchar(500) NULL; GO IF COL_LENGTH(N'dbo.Scenes', N'POVSuggestedName') IS NULL ALTER TABLE dbo.Scenes ADD POVSuggestedName nvarchar(200) NULL; GO UPDATE dbo.Chapters SET POVSource = N'Legacy' WHERE POVCharacterID IS NOT NULL AND POVSource IS NULL; GO UPDATE dbo.Scenes SET POVSource = N'Legacy' WHERE POVCharacterID IS NOT NULL AND POVSource IS NULL; GO CREATE OR ALTER PROCEDURE dbo.Chapter_ListByBook @BookID int AS BEGIN SET NOCOUNT ON; SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, pov.CharacterName AS POVCharacterName, c.POVSource, c.POVConfidence, c.POVEvidence, c.POVSuggestedName, c.Summary, c.ChapterPurposeID, cpt.PurposeName AS ChapterPurposeName, c.SortOrder, c.RevisionStatusID, rs.StatusName AS RevisionStatusName, c.CreatedDate, c.UpdatedDate, c.IsArchived, c.IsLinkedToManuscript, c.ManuscriptDocumentID, c.ExternalReference, c.LinkedUtc FROM dbo.Chapters c INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID LEFT JOIN dbo.ChapterPurposeTypes cpt ON cpt.ChapterPurposeID = c.ChapterPurposeID LEFT JOIN dbo.Characters pov ON pov.CharacterID = c.POVCharacterID WHERE c.BookID = @BookID AND c.IsArchived = 0 ORDER BY c.SortOrder, c.ChapterNumber; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_Get @ChapterID int AS BEGIN SET NOCOUNT ON; SELECT c.ChapterID, c.BookID, c.ChapterNumber, c.ChapterTitle, c.POVCharacterID, pov.CharacterName AS POVCharacterName, c.POVSource, c.POVConfidence, c.POVEvidence, c.POVSuggestedName, c.Summary, c.ChapterPurposeID, cpt.PurposeName AS ChapterPurposeName, c.SortOrder, c.RevisionStatusID, rs.StatusName AS RevisionStatusName, c.CreatedDate, c.UpdatedDate, c.IsArchived, c.IsLinkedToManuscript, c.ManuscriptDocumentID, c.ExternalReference, c.LinkedUtc FROM dbo.Chapters c INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = c.RevisionStatusID LEFT JOIN dbo.ChapterPurposeTypes cpt ON cpt.ChapterPurposeID = c.ChapterPurposeID LEFT JOIN dbo.Characters pov ON pov.CharacterID = c.POVCharacterID WHERE c.ChapterID = @ChapterID AND c.IsArchived = 0; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_ListByChapter @ChapterID int AS BEGIN SET NOCOUNT ON; SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.Summary, s.StructuralSummary, s.POVCharacterID, pov.CharacterName AS POVCharacterName, s.POVSource, s.POVConfidence, s.POVEvidence, s.POVSuggestedName, s.PrimaryLocationID, s.FloorPlanID, s.InitialFloorPlanFloorID, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived, s.ArchivedDate, s.ArchivedReason, s.IsLinkedToManuscript, s.ManuscriptDocumentID, s.ExternalReference, s.LinkedUtc, s.ImportSource, s.ImportRunID, s.SourceStartParagraph, s.SourceEndParagraph FROM dbo.Scenes s INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID LEFT JOIN dbo.Characters pov ON pov.CharacterID = s.POVCharacterID WHERE s.ChapterID = @ChapterID AND s.IsArchived = 0 ORDER BY s.SortOrder, s.SceneNumber, s.SceneTitle; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_Get @SceneID int AS BEGIN SET NOCOUNT ON; EXEC dbo.SceneMetric_EnsureDefaults @SceneID; SELECT s.SceneID, s.ChapterID, s.SceneNumber, s.SceneTitle, s.SceneTitleSource, s.Summary, s.StructuralSummary, s.POVCharacterID, pov.CharacterName AS POVCharacterName, s.POVSource, s.POVConfidence, s.POVEvidence, s.POVSuggestedName, s.PrimaryLocationID, s.FloorPlanID, s.InitialFloorPlanFloorID, location.LocationName AS PrimaryLocationName, location.LocationPath AS PrimaryLocationPath, s.SortOrder, s.TimeModeID, tm.TimeModeName, s.StartDateTime, s.EndDateTime, s.DurationAmount, s.DurationUnitID, du.DurationUnitName, s.RelativeTimeText, s.TimeConfidenceID, tc.TimeConfidenceName, s.ScenePurposeNotes, s.SceneOutcomeNotes, s.RevisionStatusID, rs.StatusName AS RevisionStatusName, s.CreatedDate, s.UpdatedDate, s.IsArchived, s.ArchivedDate, s.ArchivedReason, s.IsLinkedToManuscript, s.ManuscriptDocumentID, s.ExternalReference, s.LinkedUtc, s.ImportSource, s.ImportRunID, s.SourceStartParagraph, s.SourceEndParagraph FROM dbo.Scenes s INNER JOIN dbo.TimeModes tm ON tm.TimeModeID = s.TimeModeID INNER JOIN dbo.TimeConfidences tc ON tc.TimeConfidenceID = s.TimeConfidenceID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID LEFT JOIN dbo.DurationUnits du ON du.DurationUnitID = s.DurationUnitID LEFT JOIN dbo.LocationPaths location ON location.LocationID = s.PrimaryLocationID LEFT JOIN dbo.Characters pov ON pov.CharacterID = s.POVCharacterID WHERE s.SceneID = @SceneID AND s.IsArchived = 0; SELECT ScenePurposeTypeID FROM dbo.ScenePurposes WHERE SceneID = @SceneID; EXEC dbo.SceneMetric_ListByScene @SceneID; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_Save @ChapterID int = NULL, @BookID int, @ChapterNumber decimal(9,2), @ChapterTitle nvarchar(200), @Summary nvarchar(max) = NULL, @ChapterPurposeID int = NULL, @RevisionStatusID int, @POVCharacterID int = NULL AS BEGIN SET NOCOUNT ON; IF @POVCharacterID IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM dbo.Characters ch INNER JOIN dbo.Books b ON b.ProjectID = ch.ProjectID WHERE ch.CharacterID = @POVCharacterID AND b.BookID = @BookID AND ch.IsArchived = 0 ) SET @POVCharacterID = NULL; IF @ChapterID IS NULL OR @ChapterID = 0 BEGIN DECLARE @NextChapterOrder int = ISNULL((SELECT MAX(SortOrder) FROM dbo.Chapters WHERE BookID = @BookID), 0) + 10; INSERT dbo.Chapters (BookID, ChapterNumber, ChapterTitle, POVCharacterID, POVSource, Summary, ChapterPurposeID, SortOrder, RevisionStatusID) VALUES (@BookID, @ChapterNumber, @ChapterTitle, @POVCharacterID, CASE WHEN @POVCharacterID IS NULL THEN NULL ELSE N'Author' END, @Summary, @ChapterPurposeID, @NextChapterOrder, @RevisionStatusID); SELECT CAST(SCOPE_IDENTITY() AS int) AS ChapterID; RETURN; END; UPDATE dbo.Chapters SET ChapterNumber = @ChapterNumber, ChapterTitle = @ChapterTitle, POVCharacterID = @POVCharacterID, POVSource = CASE WHEN ISNULL(POVCharacterID, 0) <> ISNULL(@POVCharacterID, 0) THEN CASE WHEN @POVCharacterID IS NULL THEN NULL ELSE N'Author' END ELSE POVSource END, Summary = @Summary, ChapterPurposeID = @ChapterPurposeID, RevisionStatusID = @RevisionStatusID, UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @ChapterID; SELECT @ChapterID AS ChapterID; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_UpdatePovCharacter @ChapterID int, @POVCharacterID int = NULL, @POVSource nvarchar(40) = N'Author', @POVConfidence decimal(5,2) = NULL, @POVEvidence nvarchar(500) = NULL, @POVSuggestedName nvarchar(200) = NULL AS BEGIN SET NOCOUNT ON; DECLARE @BookID int, @ProjectID int; SELECT @BookID = c.BookID, @ProjectID = b.ProjectID FROM dbo.Chapters c INNER JOIN dbo.Books b ON b.BookID = c.BookID WHERE c.ChapterID = @ChapterID; IF @BookID IS NULL THROW 51000, 'Chapter could not be found.', 1; IF @POVCharacterID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Characters WHERE CharacterID = @POVCharacterID AND ProjectID = @ProjectID AND IsArchived = 0) THROW 51000, 'POV character does not belong to this project.', 1; UPDATE dbo.Chapters SET POVCharacterID = @POVCharacterID, POVSource = CASE WHEN @POVCharacterID IS NULL AND NULLIF(@POVSuggestedName, N'') IS NULL THEN NULL ELSE @POVSource END, POVConfidence = @POVConfidence, POVEvidence = NULLIF(LTRIM(RTRIM(@POVEvidence)), N''), POVSuggestedName = NULLIF(LTRIM(RTRIM(@POVSuggestedName)), N''), UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @ChapterID; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_Save @SceneID int = NULL, @ChapterID int, @SceneNumber decimal(10,2), @SceneTitle nvarchar(200), @Summary nvarchar(max) = NULL, @TimeModeID int, @StartDateTime datetime2 = NULL, @EndDateTime datetime2 = NULL, @DurationAmount decimal(10,2) = NULL, @DurationUnitID int = NULL, @RelativeTimeText nvarchar(200) = NULL, @TimeConfidenceID int, @ScenePurposeNotes nvarchar(max) = NULL, @SceneOutcomeNotes nvarchar(max) = NULL, @RevisionStatusID int, @PrimaryLocationID int = NULL, @FloorPlanID int = NULL, @InitialFloorPlanFloorID int = NULL, @POVCharacterID int = NULL AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int; SELECT @ProjectID = b.ProjectID FROM dbo.Chapters c INNER JOIN dbo.Books b ON b.BookID = c.BookID WHERE c.ChapterID = @ChapterID; IF @POVCharacterID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Characters WHERE CharacterID = @POVCharacterID AND ProjectID = @ProjectID AND IsArchived = 0) SET @POVCharacterID = NULL; DECLARE @NextSortOrder int; DECLARE @CleanSceneTitle nvarchar(200) = ISNULL(LEFT(LTRIM(RTRIM(@SceneTitle)), 200), N''); IF @SceneID IS NULL OR @SceneID = 0 BEGIN SELECT @NextSortOrder = ISNULL(MAX(SortOrder), 0) + 10 FROM dbo.Scenes WHERE ChapterID = @ChapterID; INSERT dbo.Scenes (ChapterID, SceneNumber, SceneTitle, SceneTitleSource, Summary, POVCharacterID, POVSource, SortOrder, TimeModeID, StartDateTime, EndDateTime, DurationAmount, DurationUnitID, RelativeTimeText, TimeConfidenceID, ScenePurposeNotes, SceneOutcomeNotes, RevisionStatusID, PrimaryLocationID, FloorPlanID, InitialFloorPlanFloorID) VALUES (@ChapterID, @SceneNumber, @CleanSceneTitle, CASE WHEN NULLIF(@CleanSceneTitle, N'') IS NULL THEN NULL ELSE N'Author' END, @Summary, @POVCharacterID, CASE WHEN @POVCharacterID IS NULL THEN NULL ELSE N'Author' END, @NextSortOrder, @TimeModeID, @StartDateTime, @EndDateTime, @DurationAmount, @DurationUnitID, @RelativeTimeText, @TimeConfidenceID, @ScenePurposeNotes, @SceneOutcomeNotes, @RevisionStatusID, @PrimaryLocationID, @FloorPlanID, @InitialFloorPlanFloorID); SET @SceneID = CAST(SCOPE_IDENTITY() AS int); END ELSE BEGIN UPDATE dbo.Scenes SET SceneNumber = @SceneNumber, SceneTitle = @CleanSceneTitle, SceneTitleSource = CASE WHEN ISNULL(SceneTitle, N'') <> @CleanSceneTitle THEN CASE WHEN NULLIF(@CleanSceneTitle, N'') IS NULL THEN NULL ELSE N'Author' END ELSE SceneTitleSource END, Summary = @Summary, POVCharacterID = @POVCharacterID, POVSource = CASE WHEN ISNULL(POVCharacterID, 0) <> ISNULL(@POVCharacterID, 0) THEN CASE WHEN @POVCharacterID IS NULL THEN NULL ELSE N'Author' END ELSE POVSource END, TimeModeID = @TimeModeID, StartDateTime = @StartDateTime, EndDateTime = @EndDateTime, DurationAmount = @DurationAmount, DurationUnitID = @DurationUnitID, RelativeTimeText = @RelativeTimeText, TimeConfidenceID = @TimeConfidenceID, ScenePurposeNotes = @ScenePurposeNotes, SceneOutcomeNotes = @SceneOutcomeNotes, RevisionStatusID = @RevisionStatusID, PrimaryLocationID = @PrimaryLocationID, FloorPlanID = @FloorPlanID, InitialFloorPlanFloorID = @InitialFloorPlanFloorID, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID; END SELECT @SceneID; END; GO CREATE OR ALTER PROCEDURE dbo.Scene_UpdatePovCharacter @SceneID int, @POVCharacterID int = NULL, @POVSource nvarchar(40) = N'Author', @POVConfidence decimal(5,2) = NULL, @POVEvidence nvarchar(500) = NULL, @POVSuggestedName nvarchar(200) = NULL, @OverwriteAuthor bit = 0 AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int, @ExistingSource nvarchar(40); SELECT @ProjectID = b.ProjectID, @ExistingSource = s.POVSource FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID WHERE s.SceneID = @SceneID; IF @ProjectID IS NULL THROW 51000, 'Scene could not be found.', 1; IF @POVCharacterID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Characters WHERE CharacterID = @POVCharacterID AND ProjectID = @ProjectID AND IsArchived = 0) THROW 51000, 'POV character does not belong to this project.', 1; IF @ExistingSource = N'Author' AND ISNULL(@POVSource, N'') <> N'Author' AND @OverwriteAuthor = 0 RETURN; UPDATE dbo.Scenes SET POVCharacterID = @POVCharacterID, POVSource = CASE WHEN @POVCharacterID IS NULL AND NULLIF(@POVSuggestedName, N'') IS NULL THEN NULL ELSE @POVSource END, POVConfidence = @POVConfidence, POVEvidence = NULLIF(LTRIM(RTRIM(@POVEvidence)), N''), POVSuggestedName = NULLIF(LTRIM(RTRIM(@POVSuggestedName)), N''), UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID; END; GO CREATE OR ALTER PROCEDURE dbo.Chapter_SetScenesPov @ChapterID int, @POVCharacterID int = NULL, @OverwriteAuthor bit = 0 AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int; SELECT @ProjectID = b.ProjectID FROM dbo.Chapters c INNER JOIN dbo.Books b ON b.BookID = c.BookID WHERE c.ChapterID = @ChapterID; IF @ProjectID IS NULL THROW 51000, 'Chapter could not be found.', 1; IF @POVCharacterID IS NOT NULL AND NOT EXISTS (SELECT 1 FROM dbo.Characters WHERE CharacterID = @POVCharacterID AND ProjectID = @ProjectID AND IsArchived = 0) THROW 51000, 'POV character does not belong to this project.', 1; UPDATE dbo.Scenes SET POVCharacterID = @POVCharacterID, POVSource = CASE WHEN @POVCharacterID IS NULL THEN NULL ELSE N'Author' END, POVConfidence = NULL, POVEvidence = NULL, POVSuggestedName = NULL, UpdatedDate = SYSUTCDATETIME() WHERE ChapterID = @ChapterID AND IsArchived = 0 AND (@OverwriteAuthor = 1 OR ISNULL(POVSource, N'') <> N'Author'); SELECT @@ROWCOUNT AS ScenesUpdated; END; GO CREATE OR ALTER PROCEDURE dbo.Character_Merge @SourceCharacterID int, @TargetCharacterID int, @UserID int = NULL AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; IF @SourceCharacterID IS NULL OR @TargetCharacterID IS NULL OR @SourceCharacterID = @TargetCharacterID THROW 51000, 'Choose two different characters to merge.', 1; DECLARE @ProjectID int, @SourceName nvarchar(400), @TargetName nvarchar(400), @Now datetime2 = SYSUTCDATETIME(); SELECT @ProjectID = ProjectID, @SourceName = CharacterName FROM dbo.Characters WHERE CharacterID = @SourceCharacterID AND IsArchived = 0; SELECT @TargetName = CharacterName FROM dbo.Characters WHERE CharacterID = @TargetCharacterID AND IsArchived = 0; IF @ProjectID IS NULL OR @TargetName IS NULL THROW 51000, 'Both characters must exist and be active before they can be merged.', 1; IF NOT EXISTS (SELECT 1 FROM dbo.Characters WHERE CharacterID = @TargetCharacterID AND ProjectID = @ProjectID) THROW 51000, 'Characters must belong to the same project before they can be merged.', 1; BEGIN TRANSACTION; INSERT dbo.CharacterAliases (CharacterID, Alias, SortOrder) SELECT @TargetCharacterID, AliasValue, ISNULL((SELECT MAX(SortOrder) FROM dbo.CharacterAliases WHERE CharacterID = @TargetCharacterID), 0) + ROW_NUMBER() OVER (ORDER BY AliasValue) * 10 FROM ( SELECT LTRIM(RTRIM(@SourceName)) AS AliasValue UNION SELECT LTRIM(RTRIM(ShortName)) FROM dbo.Characters WHERE CharacterID = @SourceCharacterID UNION SELECT LTRIM(RTRIM(Alias)) FROM dbo.CharacterAliases WHERE CharacterID = @SourceCharacterID ) aliases WHERE NULLIF(AliasValue, N'') IS NOT NULL AND AliasValue <> @TargetName AND NOT EXISTS ( SELECT 1 FROM dbo.CharacterAliases existing WHERE existing.CharacterID = @TargetCharacterID AND UPPER(LTRIM(RTRIM(existing.Alias))) = UPPER(AliasValue) ); UPDATE dbo.Chapters SET POVCharacterID = @TargetCharacterID, UpdatedDate = @Now WHERE POVCharacterID = @SourceCharacterID; UPDATE dbo.Scenes SET POVCharacterID = @TargetCharacterID, UpdatedDate = @Now WHERE POVCharacterID = @SourceCharacterID; DELETE sourceRows FROM dbo.SceneCharacters sourceRows WHERE sourceRows.CharacterID = @SourceCharacterID AND EXISTS ( SELECT 1 FROM dbo.SceneCharacters targetRows WHERE targetRows.SceneID = sourceRows.SceneID AND targetRows.CharacterID = @TargetCharacterID ); UPDATE dbo.SceneCharacters SET CharacterID = @TargetCharacterID, UpdatedDate = @Now WHERE CharacterID = @SourceCharacterID; DELETE sourceRows FROM dbo.SceneCharacterSuggestions sourceRows WHERE sourceRows.CharacterID = @SourceCharacterID AND EXISTS ( SELECT 1 FROM dbo.SceneCharacterSuggestions targetRows WHERE targetRows.SceneID = sourceRows.SceneID AND targetRows.CharacterID = @TargetCharacterID AND targetRows.Status = sourceRows.Status ); UPDATE dbo.SceneCharacterSuggestions SET CharacterID = @TargetCharacterID WHERE CharacterID = @SourceCharacterID; DELETE sourceRows FROM dbo.SceneFloorPlanOccupancy sourceRows WHERE sourceRows.CharacterID = @SourceCharacterID AND EXISTS ( SELECT 1 FROM dbo.SceneFloorPlanOccupancy targetRows WHERE targetRows.SceneID = sourceRows.SceneID AND targetRows.CharacterID = @TargetCharacterID ); UPDATE dbo.SceneFloorPlanOccupancy SET CharacterID = @TargetCharacterID, ModifiedDate = @Now WHERE CharacterID = @SourceCharacterID; UPDATE dbo.AssetCustodyEventCharacters SET CharacterID = @TargetCharacterID WHERE CharacterID = @SourceCharacterID; UPDATE dbo.CharacterAttributeEvents SET CharacterID = @TargetCharacterID, UpdatedDate = @Now WHERE CharacterID = @SourceCharacterID; UPDATE dbo.CharacterKnowledge SET CharacterID = @TargetCharacterID, UpdatedDate = @Now WHERE CharacterID = @SourceCharacterID; UPDATE dbo.CharacterImages SET CharacterID = @TargetCharacterID WHERE CharacterID = @SourceCharacterID; UPDATE dbo.ContinuityWarningAcknowledgements SET CharacterID = @TargetCharacterID WHERE CharacterID = @SourceCharacterID; UPDATE dbo.OnboardingManuscriptBuildCharacterMap SET CharacterID = @TargetCharacterID WHERE CharacterID = @SourceCharacterID; DECLARE relationship_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT CharacterRelationshipID, CASE WHEN CharacterAID = @SourceCharacterID THEN @TargetCharacterID ELSE CharacterAID END AS NewAID, CASE WHEN CharacterBID = @SourceCharacterID THEN @TargetCharacterID ELSE CharacterBID END AS NewBID FROM dbo.CharacterRelationships WHERE IsArchived = 0 AND (CharacterAID = @SourceCharacterID OR CharacterBID = @SourceCharacterID); DECLARE @RelationshipID int, @NewAID int, @NewBID int, @ExistingRelationshipID int; OPEN relationship_cursor; FETCH NEXT FROM relationship_cursor INTO @RelationshipID, @NewAID, @NewBID; WHILE @@FETCH_STATUS = 0 BEGIN IF @NewAID = @NewBID BEGIN UPDATE dbo.CharacterRelationships SET IsArchived = 1, ArchivedDate = @Now, ArchivedReason = N'Archived during character merge to avoid a self-relationship.', UpdatedDate = @Now, ModifiedByUserID = @UserID, ModifiedDateUTC = @Now WHERE CharacterRelationshipID = @RelationshipID; END ELSE BEGIN SELECT TOP (1) @ExistingRelationshipID = CharacterRelationshipID FROM dbo.CharacterRelationships WHERE ProjectID = @ProjectID AND IsArchived = 0 AND CharacterRelationshipID <> @RelationshipID AND ((CharacterAID = @NewAID AND CharacterBID = @NewBID) OR (CharacterAID = @NewBID AND CharacterBID = @NewAID)) ORDER BY CharacterRelationshipID; IF @ExistingRelationshipID IS NOT NULL BEGIN UPDATE dbo.RelationshipEvents SET CharacterRelationshipID = @ExistingRelationshipID, UpdatedDate = @Now, ModifiedByUserID = @UserID, ModifiedDateUTC = @Now WHERE CharacterRelationshipID = @RelationshipID; UPDATE dbo.CharacterRelationships SET IsArchived = 1, ArchivedDate = @Now, ArchivedReason = N'Merged into another relationship during character merge.', UpdatedDate = @Now, ModifiedByUserID = @UserID, ModifiedDateUTC = @Now WHERE CharacterRelationshipID = @RelationshipID; END ELSE BEGIN UPDATE dbo.CharacterRelationships SET CharacterAID = @NewAID, CharacterBID = @NewBID, UpdatedDate = @Now, ModifiedByUserID = @UserID, ModifiedDateUTC = @Now WHERE CharacterRelationshipID = @RelationshipID; END END SET @ExistingRelationshipID = NULL; FETCH NEXT FROM relationship_cursor INTO @RelationshipID, @NewAID, @NewBID; END CLOSE relationship_cursor; DEALLOCATE relationship_cursor; UPDATE dbo.Characters SET IsArchived = 1, ArchivedDate = @Now, ArchivedReason = CONCAT(N'Merged into ', @TargetName, N' (CharacterID ', @TargetCharacterID, N').'), UpdatedDate = @Now, ModifiedByUserID = @UserID, ModifiedDateUTC = @Now WHERE CharacterID = @SourceCharacterID; COMMIT TRANSACTION; SELECT @TargetCharacterID AS TargetCharacterID, @SourceCharacterID AS SourceCharacterID, @SourceName AS SourceCharacterName, @TargetName AS TargetCharacterName; END; GO