PlotDirector/PlotLine/Sql/018_Phase1R_Dynamics.sql
Nick Beckley 4c8f97d048 Phase 1R
2026-06-01 14:32:42 +01:00

323 lines
20 KiB
Transact-SQL

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
MERGE dbo.WarningTypes AS target
USING (VALUES
(N'Knowledge Continuity', N'Character may act on information before a recorded knowledge event.', 220),
(N'Abrupt Relationship Change', N'Relationship intensity changes sharply between nearby scenes.', 230),
(N'Long Character Absence', N'Character disappears for a long stretch of narrative scenes.', 240),
(N'Character Underused', N'Character appears lightly compared with their story connections.', 250),
(N'Scene Character Overload', N'Scene contains a large number of character appearances.', 260)
) AS source (TypeName, Description, SortOrder)
ON target.TypeName = source.TypeName
WHEN MATCHED THEN UPDATE SET Description = source.Description, SortOrder = source.SortOrder, IsActive = 1
WHEN NOT MATCHED THEN INSERT (TypeName, Description, SortOrder, IsActive) VALUES (source.TypeName, source.Description, source.SortOrder, 1);
GO
CREATE OR ALTER PROCEDURE dbo.Dynamics_CharacterArc
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ProjectID int = (SELECT ProjectID FROM dbo.Characters WHERE CharacterID = @CharacterID);
SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
Height, EyeColour, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
FROM dbo.Characters
WHERE CharacterID = @CharacterID;
SELECT sc.SceneID, nso.BookTitle, nso.ChapterNumber, nso.SceneNumber, nso.SceneTitle, nso.GlobalSceneIndex,
CAST(CASE WHEN COALESCE(s.POVCharacterID, c.POVCharacterID) = @CharacterID THEN 1 ELSE 0 END AS bit) AS IsPov,
MAX(CASE WHEN smt.MetricName = N'Emotional Weight' THEN smv.Value END) AS EmotionalWeight,
MAX(CASE WHEN smt.MetricName = N'Tension' THEN smv.Value END) AS Tension,
MAX(CASE WHEN smt.MetricName = N'Romance' THEN smv.Value END) AS Romance,
MAX(CASE WHEN smt.MetricName = N'Action' THEN smv.Value END) AS Action,
MAX(CASE WHEN smt.MetricName = N'Darkness' THEN smv.Value END) AS Darkness,
MAX(CASE WHEN smt.MetricName = N'Hope / Lightness' THEN smv.Value END) AS HopeLightness,
MAX(CASE WHEN smt.MetricName = N'Overall Intensity' THEN smv.Value END) AS OverallIntensity,
role.TypeName AS RoleInSceneTypeName,
presence.TypeName AS PresenceTypeName,
sc.EmotionalState,
sc.AppearanceNotes,
notes.KeyNotes
FROM dbo.SceneCharacters sc
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = sc.SceneID
INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID
INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID
LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
LEFT JOIN dbo.SceneMetricValues smv ON smv.SceneID = sc.SceneID
LEFT JOIN dbo.SceneMetricTypes smt ON smt.MetricTypeID = smv.MetricTypeID
OUTER APPLY
(
SELECT STRING_AGG(CONVERT(nvarchar(max), COALESCE(sn.NoteTitle, sn.NoteText)), N' | ') AS KeyNotes
FROM dbo.SceneNotes sn
INNER JOIN dbo.SceneNoteTypes snt ON snt.SceneNoteTypeID = sn.SceneNoteTypeID
WHERE sn.SceneID = sc.SceneID AND sn.IsResolved = 0
AND snt.TypeName IN (N'Emotional Intent', N'Character Reminder', N'Revision Note', N'TODO')
) notes
WHERE sc.CharacterID = @CharacterID
GROUP BY sc.SceneID, nso.BookTitle, nso.ChapterNumber, nso.SceneNumber, nso.SceneTitle, nso.GlobalSceneIndex,
s.POVCharacterID, c.POVCharacterID, role.TypeName, presence.TypeName, sc.EmotionalState, sc.AppearanceNotes, notes.KeyNotes
ORDER BY nso.GlobalSceneIndex;
EXEC dbo.RelationshipEvent_ListByCharacter @CharacterID;
EXEC dbo.CharacterKnowledge_ListByCharacter @CharacterID;
SELECT N'Character Presence' AS Category, ws.SeverityName, cw.Message AS Title, cw.Details AS Detail, cw.SceneID, cw.EntityID, cw.EntityType
FROM dbo.ContinuityWarnings cw
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
WHERE cw.ProjectID = @ProjectID AND cw.IsDismissed = 0
AND (
(cw.EntityType = N'Character' AND cw.EntityID = @CharacterID)
OR cw.SceneID IN (SELECT SceneID FROM dbo.SceneCharacters WHERE CharacterID = @CharacterID)
)
AND wt.TypeName IN (N'Knowledge Continuity', N'Long Character Absence', N'Character Underused', N'Scene Character Overload');
END;
GO
CREATE OR ALTER PROCEDURE dbo.Dynamics_RelationshipEvolution
@CharacterRelationshipID int
AS
BEGIN
SET NOCOUNT ON;
SELECT cr.CharacterRelationshipID, cr.ProjectID, cr.CharacterAID, ca.CharacterName AS CharacterAName,
cr.CharacterBID, cb.CharacterName AS CharacterBName, cr.RelationshipTypeID, rt.TypeName AS RelationshipTypeName,
cr.IsPermanent, cr.StartSceneID, cr.EndSceneID, cr.IsKnownToReader, cr.Notes, cr.CreatedDate, cr.UpdatedDate, cr.IsArchived
FROM dbo.CharacterRelationships cr
INNER JOIN dbo.Characters ca ON ca.CharacterID = cr.CharacterAID
INNER JOIN dbo.Characters cb ON cb.CharacterID = cr.CharacterBID
INNER JOIN dbo.RelationshipTypes rt ON rt.RelationshipTypeID = cr.RelationshipTypeID
WHERE cr.CharacterRelationshipID = @CharacterRelationshipID;
SELECT re.RelationshipEventID, re.CharacterRelationshipID, re.SceneID, nso.BookTitle, nso.ChapterNumber, nso.SceneNumber,
nso.SceneTitle, nso.GlobalSceneIndex, rs.StateName AS RelationshipStateName, re.Intensity, re.IsKnownToOtherCharacter, re.Description
FROM dbo.RelationshipEvents re
INNER JOIN dbo.RelationshipStates rs ON rs.RelationshipStateID = re.RelationshipStateID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = re.SceneID
WHERE re.CharacterRelationshipID = @CharacterRelationshipID
ORDER BY nso.GlobalSceneIndex, re.RelationshipEventID;
SELECT N'Relationship Continuity' AS Category, ws.SeverityName, cw.Message AS Title, cw.Details AS Detail, cw.SceneID, cw.EntityID, cw.EntityType
FROM dbo.ContinuityWarnings cw
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
WHERE cw.IsDismissed = 0 AND cw.EntityType = N'Relationship' AND cw.EntityID = @CharacterRelationshipID
AND wt.TypeName = N'Abrupt Relationship Change';
END;
GO
CREATE OR ALTER PROCEDURE dbo.Dynamics_KnowledgeTimeline
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @ProjectID int = (SELECT ProjectID FROM dbo.Characters WHERE CharacterID = @CharacterID);
SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
Height, EyeColour, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
FROM dbo.Characters
WHERE CharacterID = @CharacterID;
EXEC dbo.CharacterKnowledge_ListByCharacter @CharacterID;
SELECT N'Knowledge Continuity' AS Category, ws.SeverityName, cw.Message AS Title, cw.Details AS Detail, cw.SceneID, cw.EntityID, cw.EntityType
FROM dbo.ContinuityWarnings cw
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
WHERE cw.ProjectID = @ProjectID AND cw.IsDismissed = 0
AND cw.EntityType = N'Character' AND cw.EntityID = @CharacterID
AND wt.TypeName = N'Knowledge Continuity';
END;
GO
CREATE OR ALTER PROCEDURE dbo.Dynamics_StoryDashboard
@ProjectID int
AS
BEGIN
SET NOCOUNT ON;
;WITH Pairings AS
(
SELECT a.CharacterID AS CharacterAID, ca.CharacterName AS CharacterAName,
b.CharacterID AS CharacterBID, cb.CharacterName AS CharacterBName,
a.SceneID, nso.GlobalSceneIndex,
CONCAT(nso.BookTitle, N' / Ch ', nso.ChapterNumber, N' / Scene ', nso.SceneNumber, N': ', nso.SceneTitle) AS SceneLabel
FROM dbo.SceneCharacters a
INNER JOIN dbo.SceneCharacters b ON b.SceneID = a.SceneID AND b.CharacterID > a.CharacterID
INNER JOIN dbo.Characters ca ON ca.CharacterID = a.CharacterID
INNER JOIN dbo.Characters cb ON cb.CharacterID = b.CharacterID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = a.SceneID
WHERE ca.ProjectID = @ProjectID AND cb.ProjectID = @ProjectID AND ca.IsArchived = 0 AND cb.IsArchived = 0
),
Ranked AS
(
SELECT CharacterAID, CharacterAName, CharacterBID, CharacterBName, COUNT(*) AS SharedSceneCount,
MIN(GlobalSceneIndex) AS FirstIndex, MAX(GlobalSceneIndex) AS LastIndex
FROM Pairings
GROUP BY CharacterAID, CharacterAName, CharacterBID, CharacterBName
)
SELECT TOP (40) r.CharacterAID, r.CharacterAName, r.CharacterBID, r.CharacterBName, r.SharedSceneCount,
firstScene.SceneLabel AS FirstSceneLabel,
lastScene.SceneLabel AS LastSceneLabel
FROM Ranked r
OUTER APPLY (SELECT TOP (1) SceneLabel FROM Pairings p WHERE p.CharacterAID = r.CharacterAID AND p.CharacterBID = r.CharacterBID ORDER BY p.GlobalSceneIndex) firstScene
OUTER APPLY (SELECT TOP (1) SceneLabel FROM Pairings p WHERE p.CharacterAID = r.CharacterAID AND p.CharacterBID = r.CharacterBID ORDER BY p.GlobalSceneIndex DESC) lastScene
ORDER BY r.SharedSceneCount DESC, r.CharacterAName, r.CharacterBName;
SELECT Category, SeverityName, Title, Detail, SceneID, EntityID, EntityType
FROM
(
SELECT N'Continuity' AS Category, ws.SeverityName, cw.Message AS Title, cw.Details AS Detail, cw.SceneID, cw.EntityID, cw.EntityType
FROM dbo.ContinuityWarnings cw
INNER JOIN dbo.WarningSeverities ws ON ws.WarningSeverityID = cw.WarningSeverityID
INNER JOIN dbo.WarningTypes wt ON wt.WarningTypeID = cw.WarningTypeID
WHERE cw.ProjectID = @ProjectID AND cw.IsDismissed = 0
AND wt.TypeName IN (N'Knowledge Continuity', N'Abrupt Relationship Change', N'Long Character Absence', N'Character Underused', N'Scene Character Overload')
) issues
ORDER BY SeverityName DESC, Title;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Dynamics_RunContinuityChecks
@ProjectID int,
@BookID int = NULL,
@SceneID int = NULL
AS
BEGIN
SET NOCOUNT ON;
;WITH RelationshipSteps AS
(
SELECT cr.CharacterRelationshipID, cr.ProjectID, nso.BookID, nso.ChapterID, re.SceneID,
ca.CharacterName AS CharacterAName, cb.CharacterName AS CharacterBName, re.Intensity,
LAG(re.Intensity) OVER (PARTITION BY cr.CharacterRelationshipID ORDER BY nso.GlobalSceneIndex, re.RelationshipEventID) AS PreviousIntensity,
LAG(nso.SceneTitle) OVER (PARTITION BY cr.CharacterRelationshipID ORDER BY nso.GlobalSceneIndex, re.RelationshipEventID) AS PreviousSceneTitle
FROM dbo.RelationshipEvents re
INNER JOIN dbo.CharacterRelationships cr ON cr.CharacterRelationshipID = re.CharacterRelationshipID AND cr.IsArchived = 0
INNER JOIN dbo.Characters ca ON ca.CharacterID = cr.CharacterAID
INNER JOIN dbo.Characters cb ON cb.CharacterID = cr.CharacterBID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = re.SceneID
WHERE cr.ProjectID = @ProjectID
)
INSERT dbo.ContinuityWarnings (ProjectID, BookID, ChapterID, SceneID, EntityType, EntityID, WarningTypeID, WarningSeverityID, Message, Details)
SELECT rs.ProjectID, rs.BookID, rs.ChapterID, rs.SceneID, N'Relationship', rs.CharacterRelationshipID,
wt.WarningTypeID, ws.WarningSeverityID,
N'Possible emotional transition issue. Relationship intensity changes sharply between scenes.',
CONCAT(rs.CharacterAName, N' / ', rs.CharacterBName, N' changes from ', rs.PreviousIntensity, N' to ', rs.Intensity, N'. Previous scene: ', rs.PreviousSceneTitle, N'.')
FROM RelationshipSteps rs
CROSS JOIN dbo.WarningTypes wt
CROSS JOIN dbo.WarningSeverities ws
WHERE wt.TypeName = N'Abrupt Relationship Change' AND ws.SeverityName = N'Info'
AND rs.Intensity IS NOT NULL AND rs.PreviousIntensity IS NOT NULL AND ABS(rs.Intensity - rs.PreviousIntensity) >= 5
AND (@BookID IS NULL OR rs.BookID = @BookID) AND (@SceneID IS NULL OR rs.SceneID = @SceneID)
AND NOT EXISTS (SELECT 1 FROM dbo.ContinuityWarnings existing WHERE existing.ProjectID = rs.ProjectID AND existing.SceneID = rs.SceneID AND existing.EntityType = N'Relationship' AND existing.EntityID = rs.CharacterRelationshipID AND existing.WarningTypeID = wt.WarningTypeID AND existing.IsDismissed = 0 AND existing.IsIntentional = 0);
;WITH Appearances AS
(
SELECT sc.CharacterID, ch.CharacterName, nso.ProjectID, nso.BookID, nso.ChapterID, sc.SceneID, nso.GlobalSceneIndex,
LAG(nso.GlobalSceneIndex) OVER (PARTITION BY sc.CharacterID ORDER BY nso.GlobalSceneIndex) AS PreviousIndex
FROM dbo.SceneCharacters sc
INNER JOIN dbo.Characters ch ON ch.CharacterID = sc.CharacterID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = sc.SceneID
WHERE ch.ProjectID = @ProjectID AND ch.IsArchived = 0
)
INSERT dbo.ContinuityWarnings (ProjectID, BookID, ChapterID, SceneID, EntityType, EntityID, WarningTypeID, WarningSeverityID, Message, Details)
SELECT ProjectID, BookID, ChapterID, SceneID, N'Character', CharacterID, wt.WarningTypeID, ws.WarningSeverityID,
CONCAT(N'Possible review: ', CharacterName, N' is absent for ', GlobalSceneIndex - PreviousIndex - 1, N' narrative scenes.'),
N'Long absences are sometimes useful, but this may be worth checking after a major beat.'
FROM Appearances
CROSS JOIN dbo.WarningTypes wt
CROSS JOIN dbo.WarningSeverities ws
WHERE wt.TypeName = N'Long Character Absence' AND ws.SeverityName = N'Info'
AND PreviousIndex IS NOT NULL AND GlobalSceneIndex - PreviousIndex - 1 >= 12
AND (@BookID IS NULL OR BookID = @BookID) AND (@SceneID IS NULL OR SceneID = @SceneID)
AND NOT EXISTS (SELECT 1 FROM dbo.ContinuityWarnings existing WHERE existing.ProjectID = Appearances.ProjectID AND existing.SceneID = Appearances.SceneID AND existing.EntityType = N'Character' AND existing.EntityID = Appearances.CharacterID AND existing.WarningTypeID = wt.WarningTypeID AND existing.IsDismissed = 0 AND existing.IsIntentional = 0);
;WITH CharacterUsage AS
(
SELECT ch.ProjectID, ch.CharacterID, ch.CharacterName,
COUNT(DISTINCT sc.SceneID) AS AppearanceCount,
COUNT(DISTINCT cr.CharacterRelationshipID) AS RelationshipCount
FROM dbo.Characters ch
LEFT JOIN dbo.SceneCharacters sc ON sc.CharacterID = ch.CharacterID
LEFT JOIN dbo.CharacterRelationships cr ON cr.ProjectID = ch.ProjectID
AND cr.IsArchived = 0
AND ch.CharacterID IN (cr.CharacterAID, cr.CharacterBID)
WHERE ch.ProjectID = @ProjectID AND ch.IsArchived = 0 AND @SceneID IS NULL
GROUP BY ch.ProjectID, ch.CharacterID, ch.CharacterName
HAVING COUNT(DISTINCT cr.CharacterRelationshipID) >= 2 AND COUNT(DISTINCT sc.SceneID) <= 1
)
INSERT dbo.ContinuityWarnings (ProjectID, EntityType, EntityID, WarningTypeID, WarningSeverityID, Message, Details)
SELECT ProjectID, N'Character', CharacterID, wt.WarningTypeID, ws.WarningSeverityID,
CONCAT(N'Possible review: ', CharacterName, N' has several relationship links but very few scene appearances.'),
N'This may be intentional, but the character could be underused relative to their story connections.'
FROM CharacterUsage
CROSS JOIN dbo.WarningTypes wt
CROSS JOIN dbo.WarningSeverities ws
WHERE wt.TypeName = N'Character Underused' AND ws.SeverityName = N'Info'
AND NOT EXISTS (SELECT 1 FROM dbo.ContinuityWarnings existing WHERE existing.ProjectID = CharacterUsage.ProjectID AND existing.EntityType = N'Character' AND existing.EntityID = CharacterUsage.CharacterID AND existing.WarningTypeID = wt.WarningTypeID AND existing.IsDismissed = 0 AND existing.IsIntentional = 0);
;WITH SceneCounts AS
(
SELECT nso.ProjectID, nso.BookID, nso.ChapterID, nso.SceneID, nso.SceneTitle, COUNT(*) AS CharacterCount
FROM dbo.SceneCharacters sc
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = sc.SceneID
WHERE nso.ProjectID = @ProjectID AND (@BookID IS NULL OR nso.BookID = @BookID) AND (@SceneID IS NULL OR nso.SceneID = @SceneID)
GROUP BY nso.ProjectID, nso.BookID, nso.ChapterID, nso.SceneID, nso.SceneTitle
HAVING COUNT(*) >= 7
)
INSERT dbo.ContinuityWarnings (ProjectID, BookID, ChapterID, SceneID, EntityType, EntityID, WarningTypeID, WarningSeverityID, Message, Details)
SELECT ProjectID, BookID, ChapterID, SceneID, N'Scene', SceneID, wt.WarningTypeID, ws.WarningSeverityID,
CONCAT(N'Possible review: this scene has ', CharacterCount, N' character appearances.'),
N'Busy scenes can work well, but may need extra clarity around focus and blocking.'
FROM SceneCounts
CROSS JOIN dbo.WarningTypes wt
CROSS JOIN dbo.WarningSeverities ws
WHERE wt.TypeName = N'Scene Character Overload' AND ws.SeverityName = N'Info'
AND NOT EXISTS (SELECT 1 FROM dbo.ContinuityWarnings existing WHERE existing.ProjectID = SceneCounts.ProjectID AND existing.SceneID = SceneCounts.SceneID AND existing.EntityType = N'Scene' AND existing.EntityID = SceneCounts.SceneID AND existing.WarningTypeID = wt.WarningTypeID AND existing.IsDismissed = 0 AND existing.IsIntentional = 0);
;WITH Knowledge AS
(
SELECT ck.CharacterID, ch.CharacterName, ck.StoryAssetID, ck.PlotThreadID, ck.SceneID, nso.ProjectID, nso.BookID, nso.ChapterID, nso.GlobalSceneIndex,
MIN(nso.GlobalSceneIndex) OVER (PARTITION BY ck.CharacterID, ISNULL(ck.StoryAssetID, 0), ISNULL(ck.PlotThreadID, 0)) AS FirstKnownIndex
FROM dbo.CharacterKnowledge ck
INNER JOIN dbo.Characters ch ON ch.CharacterID = ck.CharacterID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = ck.SceneID
WHERE ch.ProjectID = @ProjectID
),
Candidate AS
(
SELECT DISTINCT sc.CharacterID, ch.CharacterName, te.PlotThreadID, ae.StoryAssetID, nso.ProjectID, nso.BookID, nso.ChapterID, sc.SceneID, nso.GlobalSceneIndex
FROM dbo.SceneCharacters sc
INNER JOIN dbo.Characters ch ON ch.CharacterID = sc.CharacterID
INNER JOIN dbo.NarrativeSceneOrder nso ON nso.SceneID = sc.SceneID
LEFT JOIN dbo.ThreadEvents te ON te.SceneID = sc.SceneID
LEFT JOIN dbo.AssetEvents ae ON ae.SceneID = sc.SceneID
WHERE ch.ProjectID = @ProjectID AND (@BookID IS NULL OR nso.BookID = @BookID) AND (@SceneID IS NULL OR sc.SceneID = @SceneID)
AND (te.PlotThreadID IS NOT NULL OR ae.StoryAssetID IS NOT NULL)
)
INSERT dbo.ContinuityWarnings (ProjectID, BookID, ChapterID, SceneID, EntityType, EntityID, WarningTypeID, WarningSeverityID, Message, Details)
SELECT c.ProjectID, c.BookID, c.ChapterID, c.SceneID, N'Character', c.CharacterID, wt.WarningTypeID, ws.WarningSeverityID,
CONCAT(N'Possible review: ', c.CharacterName, N' appears in a scene involving information without an earlier knowledge event.'),
N'This is advisory only. Add a knowledge event if the character is meant to know this, or mark the warning intentional.'
FROM Candidate c
CROSS JOIN dbo.WarningTypes wt
CROSS JOIN dbo.WarningSeverities ws
WHERE wt.TypeName = N'Knowledge Continuity' AND ws.SeverityName = N'Info'
AND NOT EXISTS
(
SELECT 1 FROM Knowledge k
WHERE k.CharacterID = c.CharacterID
AND ((c.StoryAssetID IS NOT NULL AND k.StoryAssetID = c.StoryAssetID) OR (c.PlotThreadID IS NOT NULL AND k.PlotThreadID = c.PlotThreadID))
AND k.FirstKnownIndex <= c.GlobalSceneIndex
)
AND NOT EXISTS (SELECT 1 FROM dbo.ContinuityWarnings existing WHERE existing.ProjectID = c.ProjectID AND existing.SceneID = c.SceneID AND existing.EntityType = N'Character' AND existing.EntityID = c.CharacterID AND existing.WarningTypeID = wt.WarningTypeID AND existing.IsDismissed = 0 AND existing.IsIntentional = 0);
END;
GO