SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF OBJECT_ID(N'dbo.WordCompanionSceneAssets', N'U') IS NULL BEGIN CREATE TABLE dbo.WordCompanionSceneAssets ( WordCompanionSceneAssetID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_WordCompanionSceneAssets PRIMARY KEY, SceneID int NOT NULL, StoryAssetID int NOT NULL, CreatedDate datetime2 NOT NULL CONSTRAINT DF_WordCompanionSceneAssets_CreatedDate DEFAULT SYSUTCDATETIME(), UpdatedDate datetime2 NOT NULL CONSTRAINT DF_WordCompanionSceneAssets_UpdatedDate DEFAULT SYSUTCDATETIME(), CONSTRAINT FK_WordCompanionSceneAssets_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID), CONSTRAINT FK_WordCompanionSceneAssets_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID), CONSTRAINT UQ_WordCompanionSceneAssets UNIQUE (SceneID, StoryAssetID) ); END; GO IF OBJECT_ID(N'dbo.WordCompanionSceneLocations', N'U') IS NULL BEGIN CREATE TABLE dbo.WordCompanionSceneLocations ( WordCompanionSceneLocationID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_WordCompanionSceneLocations PRIMARY KEY, SceneID int NOT NULL, LocationID int NOT NULL, CreatedDate datetime2 NOT NULL CONSTRAINT DF_WordCompanionSceneLocations_CreatedDate DEFAULT SYSUTCDATETIME(), UpdatedDate datetime2 NOT NULL CONSTRAINT DF_WordCompanionSceneLocations_UpdatedDate DEFAULT SYSUTCDATETIME(), CONSTRAINT FK_WordCompanionSceneLocations_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID), CONSTRAINT FK_WordCompanionSceneLocations_Locations FOREIGN KEY (LocationID) REFERENCES dbo.Locations(LocationID), CONSTRAINT UQ_WordCompanionSceneLocations UNIQUE (SceneID, LocationID) ); END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Project_List @UserID int AS BEGIN SET NOCOUNT ON; SELECT p.ProjectID AS ProjectId, p.ProjectName AS Title FROM dbo.Projects p INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE pua.UserID = @UserID AND pua.IsActive = 1 AND p.IsArchived = 0 ORDER BY p.ProjectName, p.ProjectID; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Book_ListByProject @ProjectID int, @UserID int AS BEGIN SET NOCOUNT ON; IF NOT EXISTS ( SELECT 1 FROM dbo.ProjectUserAccess pua INNER JOIN dbo.Projects p ON p.ProjectID = pua.ProjectID WHERE pua.ProjectID = @ProjectID AND pua.UserID = @UserID AND pua.IsActive = 1 AND p.IsArchived = 0 ) RETURN; SELECT b.BookID AS BookId, b.BookTitle AS Title, b.SortOrder FROM dbo.Books b WHERE b.ProjectID = @ProjectID AND b.IsArchived = 0 ORDER BY b.SortOrder, b.BookNumber, b.BookTitle, b.BookID; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Book_Structure @BookID int, @UserID int AS BEGIN SET NOCOUNT ON; IF NOT EXISTS ( SELECT 1 FROM dbo.Books b INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE b.BookID = @BookID AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1 ) RETURN; SELECT @BookID AS BookId; SELECT c.ChapterID AS ChapterId, c.ChapterTitle AS Title, c.SortOrder FROM dbo.Chapters c WHERE c.BookID = @BookID AND c.IsArchived = 0 ORDER BY c.SortOrder, c.ChapterNumber, c.ChapterID; SELECT s.ChapterID AS ChapterId, s.SceneID AS SceneId, s.SceneTitle AS Title, s.SortOrder, rs.StatusName AS RevisionStatus, sw.EstimatedWordCount AS EstimatedWords, sw.ActualWordCount AS ActualWords FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.RevisionStatuses rs ON rs.RevisionStatusID = s.RevisionStatusID LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID WHERE c.BookID = @BookID AND c.IsArchived = 0 AND s.IsArchived = 0 ORDER BY c.SortOrder, s.SortOrder, s.SceneNumber, s.SceneID; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Scene_Resolve @BookID int, @UserID int, @ChapterTitle nvarchar(200), @SceneTitle nvarchar(200) AS BEGIN SET NOCOUNT ON; IF NOT EXISTS ( SELECT 1 FROM dbo.Books b INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE b.BookID = @BookID AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1 ) BEGIN SELECT CAST(0 AS bit) AS Matched, CAST(NULL AS int) AS ChapterId, CAST(NULL AS int) AS SceneId, CAST(NULL AS nvarchar(50)) AS MatchType; RETURN; END; DECLARE @ChapterID int; DECLARE @SceneID int; SELECT TOP (1) @ChapterID = c.ChapterID, @SceneID = s.SceneID FROM dbo.Chapters c INNER JOIN dbo.Scenes s ON s.ChapterID = c.ChapterID WHERE c.BookID = @BookID AND c.IsArchived = 0 AND s.IsArchived = 0 AND UPPER(LTRIM(RTRIM(c.ChapterTitle))) = UPPER(LTRIM(RTRIM(@ChapterTitle))) AND UPPER(LTRIM(RTRIM(s.SceneTitle))) = UPPER(LTRIM(RTRIM(@SceneTitle))) ORDER BY c.SortOrder, s.SortOrder, s.SceneID; SELECT CAST(CASE WHEN @SceneID IS NULL THEN 0 ELSE 1 END AS bit) AS Matched, @ChapterID AS ChapterId, @SceneID AS SceneId, CASE WHEN @SceneID IS NULL THEN CAST(NULL AS nvarchar(50)) ELSE N'ExactTitle' END AS MatchType; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Scene_Companion @SceneID int, @UserID int AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int; DECLARE @BookID int; SELECT @ProjectID = b.ProjectID, @BookID = b.BookID FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE s.SceneID = @SceneID AND s.IsArchived = 0 AND c.IsArchived = 0 AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; IF @ProjectID IS NULL RETURN; SELECT s.SceneID, c.ChapterID, c.ChapterTitle, s.SceneTitle, sw.ActualWordCount AS ActualWords, sw.EstimatedWordCount AS EstimatedWords, s.ScenePurposeNotes AS WritingBrief, COALESCE(sw.IsBlocked, 0) AS Blocked, sw.BlockedReason FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID LEFT JOIN dbo.SceneWorkflow sw ON sw.SceneID = s.SceneID WHERE s.SceneID = @SceneID; SELECT ch.CharacterID, ch.CharacterName AS Name, CAST(CASE WHEN EXISTS (SELECT 1 FROM dbo.SceneCharacters sc WHERE sc.SceneID = @SceneID AND sc.CharacterID = ch.CharacterID) THEN 1 ELSE 0 END AS bit) AS Linked FROM dbo.Characters ch WHERE ch.ProjectID = @ProjectID AND ch.IsArchived = 0 ORDER BY ch.CharacterName, ch.CharacterID; SELECT sa.StoryAssetID AS AssetId, sa.AssetName AS Name, CAST(CASE WHEN EXISTS (SELECT 1 FROM dbo.WordCompanionSceneAssets wcsa WHERE wcsa.SceneID = @SceneID AND wcsa.StoryAssetID = sa.StoryAssetID) OR EXISTS (SELECT 1 FROM dbo.AssetEvents ae WHERE ae.SceneID = @SceneID AND ae.StoryAssetID = sa.StoryAssetID) OR EXISTS (SELECT 1 FROM dbo.SceneAssetLocations sal WHERE sal.SceneID = @SceneID AND sal.StoryAssetID = sa.StoryAssetID) THEN 1 ELSE 0 END AS bit) AS Linked FROM dbo.StoryAssets sa WHERE sa.ProjectID = @ProjectID AND sa.IsArchived = 0 ORDER BY sa.AssetName, sa.StoryAssetID; SELECT l.LocationID, l.LocationName AS Name, CAST(CASE WHEN EXISTS (SELECT 1 FROM dbo.WordCompanionSceneLocations wcsl WHERE wcsl.SceneID = @SceneID AND wcsl.LocationID = l.LocationID) OR EXISTS (SELECT 1 FROM dbo.Scenes s WHERE s.SceneID = @SceneID AND s.PrimaryLocationID = l.LocationID) OR EXISTS (SELECT 1 FROM dbo.SceneCharacters sc WHERE sc.SceneID = @SceneID AND (sc.LocationID = l.LocationID OR sc.EntryLocationID = l.LocationID OR sc.ExitLocationID = l.LocationID)) OR EXISTS (SELECT 1 FROM dbo.SceneAssetLocations sal WHERE sal.SceneID = @SceneID AND sal.LocationID = l.LocationID) THEN 1 ELSE 0 END AS bit) AS Linked FROM dbo.Locations l WHERE l.ProjectID = @ProjectID AND l.IsArchived = 0 ORDER BY l.LocationName, l.LocationID; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Scene_UpdateWordCount @SceneID int, @UserID int, @ActualWords int AS BEGIN SET NOCOUNT ON; IF @ActualWords < 0 RETURN; IF NOT EXISTS ( SELECT 1 FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE s.SceneID = @SceneID AND s.IsArchived = 0 AND c.IsArchived = 0 AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1 ) RETURN; IF EXISTS (SELECT 1 FROM dbo.SceneWorkflow WHERE SceneID = @SceneID) BEGIN UPDATE dbo.SceneWorkflow SET ActualWordCount = @ActualWords, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID; END ELSE BEGIN INSERT dbo.SceneWorkflow (SceneID, ActualWordCount) VALUES (@SceneID, @ActualWords); END; SELECT @SceneID AS SceneId, @ActualWords AS ActualWords, N'Word count updated.' AS Message; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Scene_Sync @BookID int, @UserID int, @ChapterTitle nvarchar(200), @ChapterSortOrder int = NULL, @SceneTitle nvarchar(200), @SceneSortOrder int = NULL, @ActualWords int, @DocumentId nvarchar(200) = NULL, @ContentHash nvarchar(200) = NULL AS BEGIN SET NOCOUNT ON; IF @ActualWords < 0 OR NULLIF(LTRIM(RTRIM(@ChapterTitle)), N'') IS NULL OR NULLIF(LTRIM(RTRIM(@SceneTitle)), N'') IS NULL RETURN; DECLARE @ProjectID int; SELECT @ProjectID = b.ProjectID FROM dbo.Books b INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE b.BookID = @BookID AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; IF @ProjectID IS NULL RETURN; DECLARE @ChapterID int; DECLARE @SceneID int; DECLARE @ChapterCreated bit = 0; DECLARE @SceneCreated bit = 0; DECLARE @PlannedRevisionStatusID int = (SELECT TOP (1) RevisionStatusID FROM dbo.RevisionStatuses WHERE StatusName = N'Planned' ORDER BY SortOrder); DECLARE @UnknownTimeModeID int = (SELECT TOP (1) TimeModeID FROM dbo.TimeModes WHERE TimeModeName = N'Unknown' ORDER BY SortOrder); DECLARE @UnknownTimeConfidenceID int = (SELECT TOP (1) TimeConfidenceID FROM dbo.TimeConfidences WHERE TimeConfidenceName = N'Unknown' ORDER BY SortOrder); SELECT TOP (1) @ChapterID = ChapterID FROM dbo.Chapters WHERE BookID = @BookID AND IsArchived = 0 AND UPPER(LTRIM(RTRIM(ChapterTitle))) = UPPER(LTRIM(RTRIM(@ChapterTitle))) ORDER BY SortOrder, ChapterID; IF @ChapterID IS NULL BEGIN DECLARE @NextChapterNumber decimal(9,2) = ISNULL((SELECT MAX(ChapterNumber) FROM dbo.Chapters WHERE BookID = @BookID), 0) + 1; DECLARE @NextChapterOrder int = ISNULL((SELECT MAX(SortOrder) FROM dbo.Chapters WHERE BookID = @BookID), 0) + 10; INSERT dbo.Chapters (BookID, ChapterNumber, ChapterTitle, SortOrder, RevisionStatusID) VALUES (@BookID, @NextChapterNumber, LTRIM(RTRIM(@ChapterTitle)), COALESCE(NULLIF(@ChapterSortOrder, 0), @NextChapterOrder), @PlannedRevisionStatusID); SET @ChapterID = CAST(SCOPE_IDENTITY() AS int); SET @ChapterCreated = 1; END; SELECT TOP (1) @SceneID = SceneID FROM dbo.Scenes WHERE ChapterID = @ChapterID AND IsArchived = 0 AND UPPER(LTRIM(RTRIM(SceneTitle))) = UPPER(LTRIM(RTRIM(@SceneTitle))) ORDER BY SortOrder, SceneID; IF @SceneID IS NULL BEGIN DECLARE @NextSceneNumber decimal(9,2) = ISNULL((SELECT MAX(SceneNumber) FROM dbo.Scenes WHERE ChapterID = @ChapterID), 0) + 1; DECLARE @NextSceneOrder int = ISNULL((SELECT MAX(SortOrder) FROM dbo.Scenes WHERE ChapterID = @ChapterID), 0) + 10; INSERT dbo.Scenes (ChapterID, SceneNumber, SceneTitle, SortOrder, TimeModeID, TimeConfidenceID, RevisionStatusID) VALUES (@ChapterID, @NextSceneNumber, LTRIM(RTRIM(@SceneTitle)), COALESCE(NULLIF(@SceneSortOrder, 0), @NextSceneOrder), @UnknownTimeModeID, @UnknownTimeConfidenceID, @PlannedRevisionStatusID); SET @SceneID = CAST(SCOPE_IDENTITY() AS int); SET @SceneCreated = 1; END; IF EXISTS (SELECT 1 FROM dbo.SceneWorkflow WHERE SceneID = @SceneID) BEGIN UPDATE dbo.SceneWorkflow SET ActualWordCount = @ActualWords, UpdatedDate = SYSUTCDATETIME() WHERE SceneID = @SceneID; END ELSE BEGIN INSERT dbo.SceneWorkflow (SceneID, ActualWordCount) VALUES (@SceneID, @ActualWords); END; SELECT @ChapterID AS ChapterId, @SceneID AS SceneId, @ChapterCreated AS ChapterCreated, @SceneCreated AS SceneCreated, CAST(1 AS bit) AS ActualWordsUpdated, N'Scene synced successfully.' AS Message; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_Manuscript_Sync @BookID int, @UserID int, @DocumentId nvarchar(200) = NULL, @StructureJson nvarchar(max) AS BEGIN SET NOCOUNT ON; IF ISJSON(@StructureJson) <> 1 RETURN; IF NOT EXISTS ( SELECT 1 FROM dbo.Books b INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE b.BookID = @BookID AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1 ) RETURN; DECLARE @ChaptersCreated int = 0; DECLARE @ChaptersUpdated int = 0; DECLARE @ScenesCreated int = 0; DECLARE @ScenesUpdated int = 0; DECLARE @PlannedRevisionStatusID int = (SELECT TOP (1) RevisionStatusID FROM dbo.RevisionStatuses WHERE StatusName = N'Planned' ORDER BY SortOrder); DECLARE chapter_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT Title, SortOrder, WordCount, ScenesJson FROM OPENJSON(@StructureJson) WITH ( Title nvarchar(200) '$.Title', SortOrder int '$.SortOrder', WordCount int '$.WordCount', ScenesJson nvarchar(max) '$.Scenes' AS JSON ) WHERE NULLIF(LTRIM(RTRIM(Title)), N'') IS NOT NULL AND ISNULL(WordCount, 0) >= 0; DECLARE @ChapterTitle nvarchar(200); DECLARE @ChapterSortOrder int; DECLARE @ChapterWordCount int; DECLARE @ScenesJson nvarchar(max); OPEN chapter_cursor; FETCH NEXT FROM chapter_cursor INTO @ChapterTitle, @ChapterSortOrder, @ChapterWordCount, @ScenesJson; WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @ChapterID int = NULL; DECLARE @BeforeChapterCount int; SELECT @BeforeChapterCount = COUNT(*) FROM dbo.Chapters WHERE BookID = @BookID AND IsArchived = 0; SELECT TOP (1) @ChapterID = ChapterID FROM dbo.Chapters WHERE BookID = @BookID AND IsArchived = 0 AND UPPER(LTRIM(RTRIM(ChapterTitle))) = UPPER(LTRIM(RTRIM(@ChapterTitle))) ORDER BY SortOrder, ChapterID; IF @ChapterID IS NULL BEGIN DECLARE @NextChapterNumber decimal(9,2) = ISNULL((SELECT MAX(ChapterNumber) FROM dbo.Chapters WHERE BookID = @BookID), 0) + 1; DECLARE @NextChapterOrder int = ISNULL((SELECT MAX(SortOrder) FROM dbo.Chapters WHERE BookID = @BookID), 0) + 10; INSERT dbo.Chapters (BookID, ChapterNumber, ChapterTitle, SortOrder, RevisionStatusID) VALUES (@BookID, @NextChapterNumber, LTRIM(RTRIM(@ChapterTitle)), COALESCE(NULLIF(@ChapterSortOrder, 0), @NextChapterOrder), @PlannedRevisionStatusID); SET @ChapterID = CAST(SCOPE_IDENTITY() AS int); SET @ChaptersCreated += 1; END ELSE BEGIN SET @ChaptersUpdated += 1; END; DECLARE scene_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT Title, SortOrder, WordCount, ContentHash FROM OPENJSON(ISNULL(@ScenesJson, N'[]')) WITH ( Title nvarchar(200) '$.Title', SortOrder int '$.SortOrder', WordCount int '$.WordCount', ContentHash nvarchar(200) '$.ContentHash' ) WHERE NULLIF(LTRIM(RTRIM(Title)), N'') IS NOT NULL AND ISNULL(WordCount, 0) >= 0; DECLARE @SceneTitle nvarchar(200); DECLARE @SceneSortOrder int; DECLARE @SceneWordCount int; DECLARE @ContentHash nvarchar(200); OPEN scene_cursor; FETCH NEXT FROM scene_cursor INTO @SceneTitle, @SceneSortOrder, @SceneWordCount, @ContentHash; WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @SceneResponse TABLE (ChapterId int, SceneId int, ChapterCreated bit, SceneCreated bit, ActualWordsUpdated bit, Message nvarchar(200)); INSERT @SceneResponse EXEC dbo.WordCompanion_Scene_Sync @BookID = @BookID, @UserID = @UserID, @ChapterTitle = @ChapterTitle, @ChapterSortOrder = @ChapterSortOrder, @SceneTitle = @SceneTitle, @SceneSortOrder = @SceneSortOrder, @ActualWords = @SceneWordCount, @DocumentId = @DocumentId, @ContentHash = @ContentHash; IF EXISTS (SELECT 1 FROM @SceneResponse WHERE SceneCreated = 1) SET @ScenesCreated += 1; ELSE SET @ScenesUpdated += 1; FETCH NEXT FROM scene_cursor INTO @SceneTitle, @SceneSortOrder, @SceneWordCount, @ContentHash; END; CLOSE scene_cursor; DEALLOCATE scene_cursor; FETCH NEXT FROM chapter_cursor INTO @ChapterTitle, @ChapterSortOrder, @ChapterWordCount, @ScenesJson; END; CLOSE chapter_cursor; DEALLOCATE chapter_cursor; SELECT @ChaptersCreated AS ChaptersCreated, @ChaptersUpdated AS ChaptersUpdated, @ScenesCreated AS ScenesCreated, @ScenesUpdated AS ScenesUpdated, N'Manuscript sync completed.' AS Message; END; GO CREATE OR ALTER PROCEDURE dbo.WordCompanion_SceneLinks_Update @SceneID int, @UserID int, @CharacterIds nvarchar(max) = NULL, @AssetIds nvarchar(max) = NULL, @LocationIds nvarchar(max) = NULL AS BEGIN SET NOCOUNT ON; DECLARE @ProjectID int; SELECT @ProjectID = b.ProjectID FROM dbo.Scenes s INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID INNER JOIN dbo.Projects p ON p.ProjectID = b.ProjectID INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE s.SceneID = @SceneID AND s.IsArchived = 0 AND c.IsArchived = 0 AND b.IsArchived = 0 AND p.IsArchived = 0 AND pua.UserID = @UserID AND pua.IsActive = 1; IF @ProjectID IS NULL RETURN; DECLARE @Characters TABLE (ID int PRIMARY KEY); DECLARE @Assets TABLE (ID int PRIMARY KEY); DECLARE @Locations TABLE (ID int PRIMARY KEY); INSERT @Characters (ID) SELECT DISTINCT TRY_CONVERT(int, value) FROM STRING_SPLIT(ISNULL(@CharacterIds, N''), N',') WHERE TRY_CONVERT(int, value) IS NOT NULL; INSERT @Assets (ID) SELECT DISTINCT TRY_CONVERT(int, value) FROM STRING_SPLIT(ISNULL(@AssetIds, N''), N',') WHERE TRY_CONVERT(int, value) IS NOT NULL; INSERT @Locations (ID) SELECT DISTINCT TRY_CONVERT(int, value) FROM STRING_SPLIT(ISNULL(@LocationIds, N''), N',') WHERE TRY_CONVERT(int, value) IS NOT NULL; IF EXISTS (SELECT 1 FROM @Characters requested WHERE NOT EXISTS (SELECT 1 FROM dbo.Characters c WHERE c.CharacterID = requested.ID AND c.ProjectID = @ProjectID AND c.IsArchived = 0)) RETURN; IF EXISTS (SELECT 1 FROM @Assets requested WHERE NOT EXISTS (SELECT 1 FROM dbo.StoryAssets sa WHERE sa.StoryAssetID = requested.ID AND sa.ProjectID = @ProjectID AND sa.IsArchived = 0)) RETURN; IF EXISTS (SELECT 1 FROM @Locations requested WHERE NOT EXISTS (SELECT 1 FROM dbo.Locations l WHERE l.LocationID = requested.ID AND l.ProjectID = @ProjectID AND l.IsArchived = 0)) RETURN; DELETE sc FROM dbo.SceneCharacters sc WHERE sc.SceneID = @SceneID AND NOT EXISTS (SELECT 1 FROM @Characters requested WHERE requested.ID = sc.CharacterID) AND sc.RoleInSceneTypeID IS NULL AND sc.PresenceTypeID IS NULL AND sc.LocationID IS NULL AND sc.EntryLocationID IS NULL AND sc.ExitLocationID IS NULL AND sc.AppearanceNotes IS NULL AND sc.OutfitDescription IS NULL AND sc.PhysicalCondition IS NULL AND sc.EmotionalState IS NULL AND sc.KnowledgeNotes IS NULL; INSERT dbo.SceneCharacters (SceneID, CharacterID) SELECT @SceneID, requested.ID FROM @Characters requested WHERE NOT EXISTS (SELECT 1 FROM dbo.SceneCharacters sc WHERE sc.SceneID = @SceneID AND sc.CharacterID = requested.ID); DELETE wcsa FROM dbo.WordCompanionSceneAssets wcsa WHERE wcsa.SceneID = @SceneID AND NOT EXISTS (SELECT 1 FROM @Assets requested WHERE requested.ID = wcsa.StoryAssetID); INSERT dbo.WordCompanionSceneAssets (SceneID, StoryAssetID) SELECT @SceneID, requested.ID FROM @Assets requested WHERE NOT EXISTS (SELECT 1 FROM dbo.WordCompanionSceneAssets wcsa WHERE wcsa.SceneID = @SceneID AND wcsa.StoryAssetID = requested.ID); DELETE wcsl FROM dbo.WordCompanionSceneLocations wcsl WHERE wcsl.SceneID = @SceneID AND NOT EXISTS (SELECT 1 FROM @Locations requested WHERE requested.ID = wcsl.LocationID); INSERT dbo.WordCompanionSceneLocations (SceneID, LocationID) SELECT @SceneID, requested.ID FROM @Locations requested WHERE NOT EXISTS (SELECT 1 FROM dbo.WordCompanionSceneLocations wcsl WHERE wcsl.SceneID = @SceneID AND wcsl.LocationID = requested.ID); SELECT @SceneID AS SceneId, (SELECT COUNT(*) FROM @Characters) AS CharactersUpdated, (SELECT COUNT(*) FROM @Assets) AS AssetsUpdated, (SELECT COUNT(*) FROM @Locations) AS LocationsUpdated, N'Scene links updated.' AS Message; END; GO