This structure allows you to query Issues and Actions independently, or together, as desired, and is simple to understand and maintain.
CREATE TABLE Calls
(
CallID INT CONSTRAINT pk_Calls PRIMARY KEY IDENTITY(1,1)
, CallCreated DATETIME
, LastUpdated DATETIME
);
CREATE TABLE Issues
(
IssueID INT CONSTRAINT pk_Issues PRIMARY KEY IDENTITY(1,1)
, CallID INT
, IssueText NVARCHAR(255)
, Created DATETIME
, LastUpdated DATETIME
);
CREATE TABLE Actions
(
ActionID INT CONSTRAINT pk_Actions PRIMARY KEY IDENTITY(1,1)
, CallID INT
, IssueID INT
, ActionText NVARCHAR(255)
, Created DATETIME
, LastUpdated DATETIME
)
INSERT INTO Calls (CallCreated, LastUpdated) VALUES (GETDATE(), GETDATE());
INSERT INTO Calls (CallCreated, LastUpdated) VALUES (GETDATE()-1, GETDATE());
INSERT INTO Issues (CallID, IssueText, Created, LastUpdated) VALUES (1, 'this is a test issue on CallID 1', GETDATE(), GETDATE());
INSERT INTO Issues (CallID, IssueText, Created, LastUpdated) VALUES (1, 'this is a 2nd test issue on CallID 1', GETDATE(), GETDATE());
INSERT INTO Issues (CallID, IssueText, Created, LastUpdated) VALUES (2, 'this is a test issue on CallID 2', GETDATE(), GETDATE());
INSERT INTO Issues (CallID, IssueText, Created, LastUpdated) VALUES (2, 'this is a 2nd test issue on CallID 2', GETDATE(), GETDATE());
INSERT INTO Actions (CallID, IssueID, ActionText, Created, LastUpdated) VALUES (1, 1, 'test action on CallID 1, issue 1', GETDATE(), GETDATE());
INSERT INTO Actions (CallID, IssueID, ActionText, Created, LastUpdated) VALUES (1, 2, 'test action on CallID 1, issue 2', GETDATE(), GETDATE());
INSERT INTO Actions (CallID, IssueID, ActionText, Created, LastUpdated) VALUES (2, 1, 'test action on CallID 2, issue 1', GETDATE(), GETDATE());
INSERT INTO Actions (CallID, IssueID, ActionText, Created, LastUpdated) VALUES (2, 2, 'test action on CallID 2, issue 2', GETDATE(), GETDATE());
/* This shows Calls */
SELECT *
FROM Calls;
/* This shows Calls, and Issues */
SELECT Calls.*, Issues.IssueText, Issues.Created, Issues.LastUpdated
FROM Calls
INNER JOIN Issues ON Calls.CallID = Issues.CallID;
/* This shows Calls, Issues, and Actions Taken */
SELECT Calls.*, Issues.IssueText, Issues.Created, Issues.LastUpdated, Actions.ActionText, Actions.Created, Actions.LastUpdated
FROM Calls
INNER JOIN Issues ON Calls.CallID = Issues.CallID
INNER JOIN Actions ON Issues.IssueID = Actions.IssueID;
/* This returns a list of Calls, along with Actions taken */
SELECT Calls.*, Actions.ActionText, Actions.Created, Actions.LastUpdated
FROM Calls
INNER JOIN Actions ON Calls.CallID = Actions.CallID;
This could be extended to implement 2nd and 3rd level (ad-infinitum) tech support by adding a ParentCallID
field to the Calls table that ties Calls records to a parent call record. See my answer to a post regarding how to do that here: https://softwareengineering.stackexchange.com/a/162695/62883