PlotDirector/PlotLine/Sql/006_Phase1E_Characters.sql
2026-06-01 09:03:59 +01:00

822 lines
38 KiB
Transact-SQL

SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
IF OBJECT_ID(N'dbo.CharacterRoleInSceneTypes', N'U') IS NULL
BEGIN
CREATE TABLE dbo.CharacterRoleInSceneTypes
(
CharacterRoleInSceneTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterRoleInSceneTypes PRIMARY KEY,
TypeName nvarchar(100) NOT NULL,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_CharacterRoleInSceneTypes_IsActive DEFAULT 1,
CONSTRAINT UQ_CharacterRoleInSceneTypes_TypeName UNIQUE (TypeName)
);
END;
GO
IF OBJECT_ID(N'dbo.PresenceTypes', N'U') IS NULL
BEGIN
CREATE TABLE dbo.PresenceTypes
(
PresenceTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_PresenceTypes PRIMARY KEY,
TypeName nvarchar(100) NOT NULL,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_PresenceTypes_IsActive DEFAULT 1,
CONSTRAINT UQ_PresenceTypes_TypeName UNIQUE (TypeName)
);
END;
GO
IF OBJECT_ID(N'dbo.Characters', N'U') IS NULL
BEGIN
CREATE TABLE dbo.Characters
(
CharacterID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_Characters 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,
DefaultDescription nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_Characters_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_Characters_UpdatedDate DEFAULT SYSUTCDATETIME(),
IsArchived bit NOT NULL CONSTRAINT DF_Characters_IsArchived DEFAULT 0,
CONSTRAINT FK_Characters_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
CONSTRAINT FK_Characters_AgeReferenceScene FOREIGN KEY (AgeReferenceSceneID) REFERENCES dbo.Scenes(SceneID)
);
END;
GO
IF OBJECT_ID(N'dbo.SceneCharacters', N'U') IS NULL
BEGIN
CREATE TABLE dbo.SceneCharacters
(
SceneCharacterID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SceneCharacters PRIMARY KEY,
SceneID int NOT NULL,
CharacterID int NOT NULL,
RoleInSceneTypeID int NULL,
PresenceTypeID int NULL,
LocationID int NULL,
EntryLocationID int NULL,
ExitLocationID int NULL,
AppearanceNotes nvarchar(max) NULL,
OutfitDescription nvarchar(max) NULL,
PhysicalCondition nvarchar(max) NULL,
EmotionalState nvarchar(max) NULL,
KnowledgeNotes nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_SceneCharacters_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_SceneCharacters_UpdatedDate DEFAULT SYSUTCDATETIME(),
CONSTRAINT FK_SceneCharacters_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
CONSTRAINT FK_SceneCharacters_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID),
CONSTRAINT FK_SceneCharacters_RoleTypes FOREIGN KEY (RoleInSceneTypeID) REFERENCES dbo.CharacterRoleInSceneTypes(CharacterRoleInSceneTypeID),
CONSTRAINT FK_SceneCharacters_PresenceTypes FOREIGN KEY (PresenceTypeID) REFERENCES dbo.PresenceTypes(PresenceTypeID)
);
END;
GO
IF OBJECT_ID(N'dbo.CharacterAttributeTypes', N'U') IS NULL
BEGIN
CREATE TABLE dbo.CharacterAttributeTypes
(
CharacterAttributeTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterAttributeTypes PRIMARY KEY,
ProjectID int NULL,
AttributeName nvarchar(100) NOT NULL,
DataType nvarchar(50) NOT NULL CONSTRAINT DF_CharacterAttributeTypes_DataType DEFAULT N'Text',
IsNormallyStable bit NOT NULL CONSTRAINT DF_CharacterAttributeTypes_IsNormallyStable DEFAULT 0,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_CharacterAttributeTypes_IsActive DEFAULT 1,
CONSTRAINT FK_CharacterAttributeTypes_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID)
);
END;
GO
IF OBJECT_ID(N'dbo.CharacterAttributeEvents', N'U') IS NULL
BEGIN
CREATE TABLE dbo.CharacterAttributeEvents
(
CharacterAttributeEventID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterAttributeEvents PRIMARY KEY,
CharacterID int NOT NULL,
CharacterAttributeTypeID int NOT NULL,
SceneID int NOT NULL,
AttributeValue nvarchar(500) NOT NULL,
Description nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterAttributeEvents_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterAttributeEvents_UpdatedDate DEFAULT SYSUTCDATETIME(),
CONSTRAINT FK_CharacterAttributeEvents_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID),
CONSTRAINT FK_CharacterAttributeEvents_Types FOREIGN KEY (CharacterAttributeTypeID) REFERENCES dbo.CharacterAttributeTypes(CharacterAttributeTypeID),
CONSTRAINT FK_CharacterAttributeEvents_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID)
);
END;
GO
IF OBJECT_ID(N'dbo.KnowledgeStates', N'U') IS NULL
BEGIN
CREATE TABLE dbo.KnowledgeStates
(
KnowledgeStateID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_KnowledgeStates PRIMARY KEY,
StateName nvarchar(100) NOT NULL,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_KnowledgeStates_IsActive DEFAULT 1,
CONSTRAINT UQ_KnowledgeStates_StateName UNIQUE (StateName)
);
END;
GO
IF OBJECT_ID(N'dbo.CharacterKnowledge', N'U') IS NULL
BEGIN
CREATE TABLE dbo.CharacterKnowledge
(
CharacterKnowledgeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterKnowledge PRIMARY KEY,
CharacterID int NOT NULL,
StoryAssetID int NULL,
PlotThreadID int NULL,
SceneID int NOT NULL,
KnowledgeStateID int NOT NULL,
SourceEventID int NULL,
Description nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterKnowledge_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterKnowledge_UpdatedDate DEFAULT SYSUTCDATETIME(),
CONSTRAINT FK_CharacterKnowledge_Characters FOREIGN KEY (CharacterID) REFERENCES dbo.Characters(CharacterID),
CONSTRAINT FK_CharacterKnowledge_StoryAssets FOREIGN KEY (StoryAssetID) REFERENCES dbo.StoryAssets(StoryAssetID),
CONSTRAINT FK_CharacterKnowledge_PlotThreads FOREIGN KEY (PlotThreadID) REFERENCES dbo.PlotThreads(PlotThreadID),
CONSTRAINT FK_CharacterKnowledge_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
CONSTRAINT FK_CharacterKnowledge_States FOREIGN KEY (KnowledgeStateID) REFERENCES dbo.KnowledgeStates(KnowledgeStateID)
);
END;
GO
IF OBJECT_ID(N'dbo.RelationshipTypes', N'U') IS NULL
BEGIN
CREATE TABLE dbo.RelationshipTypes
(
RelationshipTypeID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_RelationshipTypes PRIMARY KEY,
TypeName nvarchar(100) NOT NULL,
IsPermanentDefault bit NOT NULL CONSTRAINT DF_RelationshipTypes_IsPermanentDefault DEFAULT 0,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_RelationshipTypes_IsActive DEFAULT 1,
CONSTRAINT UQ_RelationshipTypes_TypeName UNIQUE (TypeName)
);
END;
GO
IF OBJECT_ID(N'dbo.RelationshipStates', N'U') IS NULL
BEGIN
CREATE TABLE dbo.RelationshipStates
(
RelationshipStateID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_RelationshipStates PRIMARY KEY,
StateName nvarchar(100) NOT NULL,
SortOrder int NOT NULL,
IsActive bit NOT NULL CONSTRAINT DF_RelationshipStates_IsActive DEFAULT 1,
CONSTRAINT UQ_RelationshipStates_StateName UNIQUE (StateName)
);
END;
GO
IF OBJECT_ID(N'dbo.CharacterRelationships', N'U') IS NULL
BEGIN
CREATE TABLE dbo.CharacterRelationships
(
CharacterRelationshipID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_CharacterRelationships PRIMARY KEY,
ProjectID int NOT NULL,
CharacterAID int NOT NULL,
CharacterBID int NOT NULL,
RelationshipTypeID int NOT NULL,
IsPermanent bit NOT NULL CONSTRAINT DF_CharacterRelationships_IsPermanent DEFAULT 0,
StartSceneID int NULL,
EndSceneID int NULL,
IsKnownToReader bit NOT NULL CONSTRAINT DF_CharacterRelationships_IsKnownToReader DEFAULT 0,
Notes nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterRelationships_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_CharacterRelationships_UpdatedDate DEFAULT SYSUTCDATETIME(),
IsArchived bit NOT NULL CONSTRAINT DF_CharacterRelationships_IsArchived DEFAULT 0,
CONSTRAINT FK_CharacterRelationships_Projects FOREIGN KEY (ProjectID) REFERENCES dbo.Projects(ProjectID),
CONSTRAINT FK_CharacterRelationships_CharacterA FOREIGN KEY (CharacterAID) REFERENCES dbo.Characters(CharacterID),
CONSTRAINT FK_CharacterRelationships_CharacterB FOREIGN KEY (CharacterBID) REFERENCES dbo.Characters(CharacterID),
CONSTRAINT FK_CharacterRelationships_Types FOREIGN KEY (RelationshipTypeID) REFERENCES dbo.RelationshipTypes(RelationshipTypeID),
CONSTRAINT FK_CharacterRelationships_StartScene FOREIGN KEY (StartSceneID) REFERENCES dbo.Scenes(SceneID),
CONSTRAINT FK_CharacterRelationships_EndScene FOREIGN KEY (EndSceneID) REFERENCES dbo.Scenes(SceneID)
);
END;
GO
IF OBJECT_ID(N'dbo.RelationshipEvents', N'U') IS NULL
BEGIN
CREATE TABLE dbo.RelationshipEvents
(
RelationshipEventID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_RelationshipEvents PRIMARY KEY,
CharacterRelationshipID int NOT NULL,
SceneID int NOT NULL,
RelationshipStateID int NOT NULL,
Intensity int NULL,
IsKnownToOtherCharacter bit NOT NULL CONSTRAINT DF_RelationshipEvents_IsKnownToOtherCharacter DEFAULT 0,
Description nvarchar(max) NULL,
CreatedDate datetime2 NOT NULL CONSTRAINT DF_RelationshipEvents_CreatedDate DEFAULT SYSUTCDATETIME(),
UpdatedDate datetime2 NOT NULL CONSTRAINT DF_RelationshipEvents_UpdatedDate DEFAULT SYSUTCDATETIME(),
CONSTRAINT FK_RelationshipEvents_Relationships FOREIGN KEY (CharacterRelationshipID) REFERENCES dbo.CharacterRelationships(CharacterRelationshipID),
CONSTRAINT FK_RelationshipEvents_Scenes FOREIGN KEY (SceneID) REFERENCES dbo.Scenes(SceneID),
CONSTRAINT FK_RelationshipEvents_States FOREIGN KEY (RelationshipStateID) REFERENCES dbo.RelationshipStates(RelationshipStateID),
CONSTRAINT CK_RelationshipEvents_Intensity CHECK (Intensity IS NULL OR Intensity BETWEEN 1 AND 10)
);
END;
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_Characters_ProjectID' AND object_id = OBJECT_ID(N'dbo.Characters'))
CREATE INDEX IX_Characters_ProjectID ON dbo.Characters(ProjectID, IsArchived, CharacterName);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_SceneCharacters_SceneID' AND object_id = OBJECT_ID(N'dbo.SceneCharacters'))
CREATE INDEX IX_SceneCharacters_SceneID ON dbo.SceneCharacters(SceneID, CharacterID);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_CharacterKnowledge_SceneID' AND object_id = OBJECT_ID(N'dbo.CharacterKnowledge'))
CREATE INDEX IX_CharacterKnowledge_SceneID ON dbo.CharacterKnowledge(SceneID, CharacterID);
GO
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'IX_RelationshipEvents_SceneID' AND object_id = OBJECT_ID(N'dbo.RelationshipEvents'))
CREATE INDEX IX_RelationshipEvents_SceneID ON dbo.RelationshipEvents(SceneID, CharacterRelationshipID);
GO
MERGE dbo.CharacterRoleInSceneTypes AS target
USING (VALUES
(N'POV Character', 10), (N'Main Participant', 20), (N'Supporting Participant', 30), (N'Witness', 40),
(N'Background', 50), (N'Mentioned Only', 60), (N'Hidden', 70), (N'Overhearing', 80)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder) VALUES (source.TypeName, source.SortOrder);
GO
MERGE dbo.PresenceTypes AS target
USING (VALUES
(N'Present', 10), (N'Arrives', 20), (N'Leaves', 30), (N'Nearby', 40), (N'Hidden', 50),
(N'Overhearing', 60), (N'Mentioned Only', 70), (N'Off-screen', 80), (N'Unknown', 90)
) AS source (TypeName, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, SortOrder) VALUES (source.TypeName, source.SortOrder);
GO
MERGE dbo.CharacterAttributeTypes AS target
USING (VALUES
(N'Hair Colour', N'Text', 1, 10), (N'Hair Style', N'Text', 0, 20), (N'Injury', N'Text', 0, 30),
(N'Disguise', N'Text', 0, 40), (N'Public Name', N'Text', 1, 50), (N'Mental State', N'Text', 0, 60),
(N'Physical Condition', N'Text', 0, 70), (N'Reputation', N'Text', 0, 80), (N'Confidence', N'Number', 0, 90),
(N'Clothing Note', N'Text', 0, 100)
) AS source (AttributeName, DataType, IsNormallyStable, SortOrder)
ON target.ProjectID IS NULL AND target.AttributeName = source.AttributeName
WHEN NOT MATCHED THEN INSERT (AttributeName, DataType, IsNormallyStable, SortOrder) VALUES (source.AttributeName, source.DataType, source.IsNormallyStable, source.SortOrder);
GO
MERGE dbo.KnowledgeStates AS target
USING (VALUES
(N'Unaware', 10), (N'Suspects', 20), (N'Partially Knows', 30), (N'Knows', 40),
(N'Misunderstands', 50), (N'Hiding', 60), (N'Lying About', 70)
) AS source (StateName, SortOrder)
ON target.StateName = source.StateName
WHEN NOT MATCHED THEN INSERT (StateName, SortOrder) VALUES (source.StateName, source.SortOrder);
GO
MERGE dbo.RelationshipTypes AS target
USING (VALUES
(N'Parent', 1, 10), (N'Child', 1, 20), (N'Sibling', 1, 30), (N'Half-sibling', 1, 40),
(N'Adoptive Parent', 1, 50), (N'Biological Parent', 1, 60), (N'Guardian', 1, 70),
(N'Friend', 0, 80), (N'Enemy', 0, 90), (N'Lover', 0, 100), (N'Ex-lover', 0, 110),
(N'Spouse', 1, 120), (N'Ally', 0, 130), (N'Rival', 0, 140), (N'Protector', 0, 150),
(N'Suspicious Of', 0, 160), (N'Afraid Of', 0, 170), (N'Manipulating', 0, 180), (N'Estranged From', 0, 190)
) AS source (TypeName, IsPermanentDefault, SortOrder)
ON target.TypeName = source.TypeName
WHEN NOT MATCHED THEN INSERT (TypeName, IsPermanentDefault, SortOrder) VALUES (source.TypeName, source.IsPermanentDefault, source.SortOrder);
GO
MERGE dbo.RelationshipStates AS target
USING (VALUES
(N'Unknown', 10), (N'Positive', 20), (N'Neutral', 30), (N'Negative', 40), (N'Tense', 50),
(N'Friendly', 60), (N'Romantic', 70), (N'Sexual Tension', 80), (N'In Love', 90),
(N'Distrustful', 100), (N'Hostile', 110), (N'Protective', 120), (N'Estranged', 130),
(N'Broken', 140), (N'Reconciled', 150)
) AS source (StateName, SortOrder)
ON target.StateName = source.StateName
WHEN NOT MATCHED THEN INSERT (StateName, SortOrder) VALUES (source.StateName, source.SortOrder);
GO
CREATE OR ALTER PROCEDURE dbo.CharacterLookup_All
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 ORDER BY SortOrder;
SELECT KnowledgeStateID, StateName, SortOrder, IsActive FROM dbo.KnowledgeStates WHERE IsActive = 1 ORDER BY SortOrder;
SELECT RelationshipTypeID, TypeName, IsPermanentDefault, SortOrder, IsActive FROM dbo.RelationshipTypes WHERE IsActive = 1 ORDER BY SortOrder;
SELECT RelationshipStateID, StateName, SortOrder, IsActive FROM dbo.RelationshipStates WHERE IsActive = 1 ORDER BY SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Character_ListByProject
@ProjectID int
AS
BEGIN
SET NOCOUNT ON;
SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
Height, EyeColour, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
FROM dbo.Characters
WHERE ProjectID = @ProjectID AND IsArchived = 0
ORDER BY CharacterName;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Character_Get
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
SELECT CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
Height, EyeColour, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
FROM dbo.Characters
WHERE CharacterID = @CharacterID AND IsArchived = 0;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Character_Save
@CharacterID int = NULL,
@ProjectID int,
@CharacterName nvarchar(200),
@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,
@DefaultDescription nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @CharacterID IS NULL OR @CharacterID = 0
BEGIN
INSERT dbo.Characters (ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID, Height, EyeColour, DefaultDescription)
VALUES (@ProjectID, @CharacterName, @ShortName, @Sex, @BirthDate, @AgeAtSeriesStart, @AgeReferenceSceneID, @Height, @EyeColour, @DefaultDescription);
SET @CharacterID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.Characters
SET CharacterName = @CharacterName, ShortName = @ShortName, Sex = @Sex, BirthDate = @BirthDate,
AgeAtSeriesStart = @AgeAtSeriesStart, AgeReferenceSceneID = @AgeReferenceSceneID,
Height = @Height, EyeColour = @EyeColour, DefaultDescription = @DefaultDescription,
UpdatedDate = SYSUTCDATETIME()
WHERE CharacterID = @CharacterID;
END
SELECT @CharacterID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Character_Archive
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Characters SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE CharacterID = @CharacterID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.SceneCharacter_ListByScene
@SceneID int
AS
BEGIN
SET NOCOUNT ON;
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.AppearanceNotes, sc.OutfitDescription, sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes,
sc.CreatedDate, sc.UpdatedDate
FROM dbo.SceneCharacters sc
INNER JOIN dbo.Characters 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
WHERE sc.SceneID = @SceneID AND c.IsArchived = 0
ORDER BY role.SortOrder, c.CharacterName;
END;
GO
CREATE OR ALTER PROCEDURE dbo.SceneCharacter_Save
@SceneCharacterID int = NULL,
@SceneID int,
@CharacterID int,
@RoleInSceneTypeID int = NULL,
@PresenceTypeID int = NULL,
@AppearanceNotes nvarchar(max) = NULL,
@OutfitDescription nvarchar(max) = NULL,
@PhysicalCondition nvarchar(max) = NULL,
@EmotionalState nvarchar(max) = NULL,
@KnowledgeNotes nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @SceneCharacterID IS NULL OR @SceneCharacterID = 0
BEGIN
SELECT @SceneCharacterID = SceneCharacterID FROM dbo.SceneCharacters WHERE SceneID = @SceneID AND CharacterID = @CharacterID;
END
IF @SceneCharacterID IS NULL OR @SceneCharacterID = 0
BEGIN
INSERT dbo.SceneCharacters (SceneID, CharacterID, RoleInSceneTypeID, PresenceTypeID, AppearanceNotes, OutfitDescription, PhysicalCondition, EmotionalState, KnowledgeNotes)
VALUES (@SceneID, @CharacterID, @RoleInSceneTypeID, @PresenceTypeID, @AppearanceNotes, @OutfitDescription, @PhysicalCondition, @EmotionalState, @KnowledgeNotes);
SET @SceneCharacterID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.SceneCharacters
SET CharacterID = @CharacterID, RoleInSceneTypeID = @RoleInSceneTypeID, PresenceTypeID = @PresenceTypeID,
AppearanceNotes = @AppearanceNotes, OutfitDescription = @OutfitDescription, PhysicalCondition = @PhysicalCondition,
EmotionalState = @EmotionalState, KnowledgeNotes = @KnowledgeNotes, UpdatedDate = SYSUTCDATETIME()
WHERE SceneCharacterID = @SceneCharacterID;
END
SELECT @SceneCharacterID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.SceneCharacter_Delete
@SceneCharacterID int
AS
BEGIN
SET NOCOUNT ON;
DELETE FROM dbo.SceneCharacters WHERE SceneCharacterID = @SceneCharacterID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterAttributeEvent_ListByCharacter
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
SELECT cae.CharacterAttributeEventID, cae.CharacterID, c.CharacterName, cae.CharacterAttributeTypeID, cat.AttributeName,
cae.SceneID, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle, cae.AttributeValue, cae.Description, cae.CreatedDate, cae.UpdatedDate
FROM dbo.CharacterAttributeEvents cae
INNER JOIN dbo.Characters c ON c.CharacterID = cae.CharacterID
INNER JOIN dbo.CharacterAttributeTypes cat ON cat.CharacterAttributeTypeID = cae.CharacterAttributeTypeID
INNER JOIN dbo.Scenes s ON s.SceneID = cae.SceneID
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
WHERE cae.CharacterID = @CharacterID
ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder, cat.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterAttributeEvent_Save
@CharacterAttributeEventID int = NULL,
@CharacterID int,
@CharacterAttributeTypeID int,
@SceneID int,
@AttributeValue nvarchar(500),
@Description nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @CharacterAttributeEventID IS NULL OR @CharacterAttributeEventID = 0
BEGIN
INSERT dbo.CharacterAttributeEvents (CharacterID, CharacterAttributeTypeID, SceneID, AttributeValue, Description)
VALUES (@CharacterID, @CharacterAttributeTypeID, @SceneID, @AttributeValue, @Description);
SET @CharacterAttributeEventID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.CharacterAttributeEvents
SET CharacterID = @CharacterID, CharacterAttributeTypeID = @CharacterAttributeTypeID, SceneID = @SceneID,
AttributeValue = @AttributeValue, Description = @Description, UpdatedDate = SYSUTCDATETIME()
WHERE CharacterAttributeEventID = @CharacterAttributeEventID;
END
SELECT @CharacterAttributeEventID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterKnowledge_ListByScene
@SceneID int
AS
BEGIN
SET NOCOUNT ON;
SELECT ck.CharacterKnowledgeID, ck.CharacterID, c.CharacterName, ck.StoryAssetID, sa.AssetName, ck.PlotThreadID, pt.ThreadTitle,
ck.SceneID, ck.KnowledgeStateID, ks.StateName AS KnowledgeStateName, ck.SourceEventID, ck.Description, ck.CreatedDate, ck.UpdatedDate
FROM dbo.CharacterKnowledge ck
INNER JOIN dbo.Characters c ON c.CharacterID = ck.CharacterID
INNER JOIN dbo.KnowledgeStates ks ON ks.KnowledgeStateID = ck.KnowledgeStateID
LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ck.StoryAssetID
LEFT JOIN dbo.PlotThreads pt ON pt.PlotThreadID = ck.PlotThreadID
WHERE ck.SceneID = @SceneID
ORDER BY c.CharacterName, ks.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterKnowledge_ListByCharacter
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
SELECT ck.CharacterKnowledgeID, ck.CharacterID, c.CharacterName, ck.StoryAssetID, sa.AssetName, ck.PlotThreadID, pt.ThreadTitle,
ck.SceneID, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle,
ck.KnowledgeStateID, ks.StateName AS KnowledgeStateName, ck.SourceEventID, ck.Description, ck.CreatedDate, ck.UpdatedDate
FROM dbo.CharacterKnowledge ck
INNER JOIN dbo.Characters c ON c.CharacterID = ck.CharacterID
INNER JOIN dbo.KnowledgeStates ks ON ks.KnowledgeStateID = ck.KnowledgeStateID
INNER JOIN dbo.Scenes s ON s.SceneID = ck.SceneID
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
LEFT JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ck.StoryAssetID
LEFT JOIN dbo.PlotThreads pt ON pt.PlotThreadID = ck.PlotThreadID
WHERE ck.CharacterID = @CharacterID
ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterKnowledge_Save
@CharacterKnowledgeID int = NULL,
@CharacterID int,
@StoryAssetID int = NULL,
@PlotThreadID int = NULL,
@SceneID int,
@KnowledgeStateID int,
@SourceEventID int = NULL,
@Description nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @CharacterKnowledgeID IS NULL OR @CharacterKnowledgeID = 0
BEGIN
INSERT dbo.CharacterKnowledge (CharacterID, StoryAssetID, PlotThreadID, SceneID, KnowledgeStateID, SourceEventID, Description)
VALUES (@CharacterID, @StoryAssetID, @PlotThreadID, @SceneID, @KnowledgeStateID, @SourceEventID, @Description);
SET @CharacterKnowledgeID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.CharacterKnowledge
SET CharacterID = @CharacterID, StoryAssetID = @StoryAssetID, PlotThreadID = @PlotThreadID, SceneID = @SceneID,
KnowledgeStateID = @KnowledgeStateID, SourceEventID = @SourceEventID, Description = @Description, UpdatedDate = SYSUTCDATETIME()
WHERE CharacterKnowledgeID = @CharacterKnowledgeID;
END
SELECT @CharacterKnowledgeID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Relationship_ListByCharacter
@CharacterID 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.IsArchived = 0 AND @CharacterID IN (cr.CharacterAID, cr.CharacterBID)
ORDER BY ca.CharacterName, cb.CharacterName, rt.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Relationship_ListByProject
@ProjectID 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.ProjectID = @ProjectID AND cr.IsArchived = 0
ORDER BY ca.CharacterName, cb.CharacterName, rt.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Relationship_Save
@CharacterRelationshipID int = NULL,
@ProjectID int,
@CharacterAID int,
@CharacterBID int,
@RelationshipTypeID int,
@IsPermanent bit,
@StartSceneID int = NULL,
@EndSceneID int = NULL,
@IsKnownToReader bit,
@Notes nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @CharacterRelationshipID IS NULL OR @CharacterRelationshipID = 0
BEGIN
INSERT dbo.CharacterRelationships (ProjectID, CharacterAID, CharacterBID, RelationshipTypeID, IsPermanent, StartSceneID, EndSceneID, IsKnownToReader, Notes)
VALUES (@ProjectID, @CharacterAID, @CharacterBID, @RelationshipTypeID, @IsPermanent, @StartSceneID, @EndSceneID, @IsKnownToReader, @Notes);
SET @CharacterRelationshipID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.CharacterRelationships
SET CharacterAID = @CharacterAID, CharacterBID = @CharacterBID, RelationshipTypeID = @RelationshipTypeID,
IsPermanent = @IsPermanent, StartSceneID = @StartSceneID, EndSceneID = @EndSceneID,
IsKnownToReader = @IsKnownToReader, Notes = @Notes, UpdatedDate = SYSUTCDATETIME()
WHERE CharacterRelationshipID = @CharacterRelationshipID;
END
SELECT @CharacterRelationshipID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.Relationship_Archive
@CharacterRelationshipID int
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.CharacterRelationships SET IsArchived = 1, UpdatedDate = SYSUTCDATETIME() WHERE CharacterRelationshipID = @CharacterRelationshipID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.RelationshipEvent_ListByCharacter
@CharacterID int
AS
BEGIN
SET NOCOUNT ON;
SELECT re.RelationshipEventID, re.CharacterRelationshipID, cr.ProjectID, cr.CharacterAID, ca.CharacterName AS CharacterAName,
cr.CharacterBID, cb.CharacterName AS CharacterBName, rt.TypeName AS RelationshipTypeName,
re.SceneID, s.SceneNumber, s.SceneTitle, ch.ChapterNumber, b.BookTitle,
re.RelationshipStateID, rs.StateName AS RelationshipStateName, re.Intensity, re.IsKnownToOtherCharacter,
re.Description, re.CreatedDate, re.UpdatedDate
FROM dbo.RelationshipEvents re
INNER JOIN dbo.CharacterRelationships cr ON cr.CharacterRelationshipID = re.CharacterRelationshipID
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
INNER JOIN dbo.RelationshipStates rs ON rs.RelationshipStateID = re.RelationshipStateID
INNER JOIN dbo.Scenes s ON s.SceneID = re.SceneID
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
WHERE @CharacterID IN (cr.CharacterAID, cr.CharacterBID)
ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder;
END;
GO
CREATE OR ALTER PROCEDURE dbo.RelationshipEvent_ListByScene
@SceneID int
AS
BEGIN
SET NOCOUNT ON;
SELECT re.RelationshipEventID, re.CharacterRelationshipID, cr.ProjectID, cr.CharacterAID, ca.CharacterName AS CharacterAName,
cr.CharacterBID, cb.CharacterName AS CharacterBName, rt.TypeName AS RelationshipTypeName,
re.SceneID, re.RelationshipStateID, rs.StateName AS RelationshipStateName, re.Intensity, re.IsKnownToOtherCharacter,
re.Description, re.CreatedDate, re.UpdatedDate
FROM dbo.RelationshipEvents re
INNER JOIN dbo.CharacterRelationships cr ON cr.CharacterRelationshipID = re.CharacterRelationshipID
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
INNER JOIN dbo.RelationshipStates rs ON rs.RelationshipStateID = re.RelationshipStateID
WHERE re.SceneID = @SceneID
ORDER BY ca.CharacterName, cb.CharacterName;
END;
GO
CREATE OR ALTER PROCEDURE dbo.RelationshipEvent_Save
@RelationshipEventID int = NULL,
@CharacterRelationshipID int,
@SceneID int,
@RelationshipStateID int,
@Intensity int = NULL,
@IsKnownToOtherCharacter bit,
@Description nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @RelationshipEventID IS NULL OR @RelationshipEventID = 0
BEGIN
INSERT dbo.RelationshipEvents (CharacterRelationshipID, SceneID, RelationshipStateID, Intensity, IsKnownToOtherCharacter, Description)
VALUES (@CharacterRelationshipID, @SceneID, @RelationshipStateID, @Intensity, @IsKnownToOtherCharacter, @Description);
SET @RelationshipEventID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.RelationshipEvents
SET CharacterRelationshipID = @CharacterRelationshipID, SceneID = @SceneID, RelationshipStateID = @RelationshipStateID,
Intensity = @Intensity, IsKnownToOtherCharacter = @IsKnownToOtherCharacter,
Description = @Description, UpdatedDate = SYSUTCDATETIME()
WHERE RelationshipEventID = @RelationshipEventID;
END
SELECT @RelationshipEventID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.CharacterTimeline_GetByProject
@ProjectID int,
@BookID int = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP (12) CharacterID, ProjectID, CharacterName, ShortName, Sex, BirthDate, AgeAtSeriesStart, AgeReferenceSceneID,
Height, EyeColour, DefaultDescription, CreatedDate, UpdatedDate, IsArchived
FROM dbo.Characters
WHERE ProjectID = @ProjectID AND IsArchived = 0
ORDER BY 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.AppearanceNotes, sc.OutfitDescription, sc.PhysicalCondition, sc.EmotionalState, sc.KnowledgeNotes,
sc.CreatedDate, sc.UpdatedDate
FROM dbo.SceneCharacters sc
INNER JOIN dbo.Characters c ON c.CharacterID = sc.CharacterID
INNER JOIN dbo.Scenes s ON s.SceneID = sc.SceneID
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
LEFT JOIN dbo.CharacterRoleInSceneTypes role ON role.CharacterRoleInSceneTypeID = sc.RoleInSceneTypeID
LEFT JOIN dbo.PresenceTypes presence ON presence.PresenceTypeID = sc.PresenceTypeID
WHERE c.ProjectID = @ProjectID AND c.IsArchived = 0 AND (@BookID IS NULL OR b.BookID = @BookID)
ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder, c.CharacterName;
END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_Save
@AssetCustodyEventID int = NULL,
@StoryAssetID int,
@SceneID int,
@AssetCustodyEventTypeID int,
@Description nvarchar(max) = NULL,
@CustodianNames nvarchar(max) = NULL,
@CustodianCharacterIds nvarchar(max) = NULL,
@CustodyRoleID int
AS
BEGIN
SET NOCOUNT ON;
IF @AssetCustodyEventID IS NULL OR @AssetCustodyEventID = 0
BEGIN
INSERT dbo.AssetCustodyEvents (StoryAssetID, SceneID, AssetCustodyEventTypeID, Description)
VALUES (@StoryAssetID, @SceneID, @AssetCustodyEventTypeID, @Description);
SET @AssetCustodyEventID = CAST(SCOPE_IDENTITY() AS int);
END
ELSE
BEGIN
UPDATE dbo.AssetCustodyEvents
SET StoryAssetID = @StoryAssetID, SceneID = @SceneID, AssetCustodyEventTypeID = @AssetCustodyEventTypeID,
Description = @Description, UpdatedDate = SYSUTCDATETIME()
WHERE AssetCustodyEventID = @AssetCustodyEventID;
END
DELETE FROM dbo.AssetCustodyEventCharacters WHERE AssetCustodyEventID = @AssetCustodyEventID;
INSERT dbo.AssetCustodyEventCharacters (AssetCustodyEventID, CharacterID, CharacterNameText, CustodyRoleID)
SELECT @AssetCustodyEventID, TRY_CAST(value AS int), NULL, @CustodyRoleID
FROM STRING_SPLIT(ISNULL(@CustodianCharacterIds, N''), N',')
WHERE TRY_CAST(value AS int) IS NOT NULL;
INSERT dbo.AssetCustodyEventCharacters (AssetCustodyEventID, CharacterNameText, CustodyRoleID)
SELECT @AssetCustodyEventID, LTRIM(RTRIM(value)), @CustodyRoleID
FROM STRING_SPLIT(REPLACE(ISNULL(@CustodianNames, N''), CHAR(10), N','), N',')
WHERE LTRIM(RTRIM(value)) <> N'';
SELECT @AssetCustodyEventID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_ListByScene
@SceneID int
AS
BEGIN
SET NOCOUNT ON;
SELECT ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID,
ace.AssetCustodyEventTypeID, acet.TypeName AS CustodyEventTypeName, ace.Description,
STRING_AGG(CONCAT(COALESCE(c.CharacterName, aec.CharacterNameText), N' (', cr.RoleName, N')'), N', ') AS CustodianSummary,
ace.CreatedDate, ace.UpdatedDate
FROM dbo.AssetCustodyEvents ace
INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
INNER JOIN dbo.AssetCustodyEventTypes acet ON acet.AssetCustodyEventTypeID = ace.AssetCustodyEventTypeID
LEFT JOIN dbo.AssetCustodyEventCharacters aec ON aec.AssetCustodyEventID = ace.AssetCustodyEventID
LEFT JOIN dbo.Characters c ON c.CharacterID = aec.CharacterID
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = aec.CustodyRoleID
WHERE ace.SceneID = @SceneID
GROUP BY ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID, ace.AssetCustodyEventTypeID, acet.TypeName, ace.Description, ace.CreatedDate, ace.UpdatedDate
ORDER BY sa.AssetName, ace.AssetCustodyEventID;
END;
GO
CREATE OR ALTER PROCEDURE dbo.AssetCustodyEvent_ListByAsset
@StoryAssetID int
AS
BEGIN
SET NOCOUNT ON;
SELECT ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID,
ace.AssetCustodyEventTypeID, acet.TypeName AS CustodyEventTypeName, ace.Description,
STRING_AGG(CONCAT(COALESCE(c.CharacterName, aec.CharacterNameText), N' (', cr.RoleName, N')'), N', ') AS CustodianSummary,
ace.CreatedDate, ace.UpdatedDate, b.BookTitle, ch.ChapterNumber, s.SceneNumber, s.SceneTitle
FROM dbo.AssetCustodyEvents ace
INNER JOIN dbo.StoryAssets sa ON sa.StoryAssetID = ace.StoryAssetID
INNER JOIN dbo.AssetCustodyEventTypes acet ON acet.AssetCustodyEventTypeID = ace.AssetCustodyEventTypeID
INNER JOIN dbo.Scenes s ON s.SceneID = ace.SceneID
INNER JOIN dbo.Chapters ch ON ch.ChapterID = s.ChapterID
INNER JOIN dbo.Books b ON b.BookID = ch.BookID
LEFT JOIN dbo.AssetCustodyEventCharacters aec ON aec.AssetCustodyEventID = ace.AssetCustodyEventID
LEFT JOIN dbo.Characters c ON c.CharacterID = aec.CharacterID
LEFT JOIN dbo.CustodyRoles cr ON cr.CustodyRoleID = aec.CustodyRoleID
WHERE ace.StoryAssetID = @StoryAssetID
GROUP BY ace.AssetCustodyEventID, ace.StoryAssetID, sa.AssetName, ace.SceneID, ace.AssetCustodyEventTypeID, acet.TypeName, ace.Description, ace.CreatedDate, ace.UpdatedDate, b.BookTitle, ch.ChapterNumber, s.SceneNumber, s.SceneTitle, b.SortOrder, ch.SortOrder, s.SortOrder
ORDER BY b.SortOrder, ch.SortOrder, s.SortOrder, ace.AssetCustodyEventID;
END;
GO