Skip to content

Commit ec56e20

Browse files
authored
Merge pull request #1 from RootITUp/feature/kpis_integration
⬆️v1.0
2 parents 836981e + ff9d0d4 commit ec56e20

16 files changed

Lines changed: 962 additions & 88 deletions

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pbix filter=lfs diff=lfs merge=lfs -text

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# adesso.Matrix42.PowerBI
2+
3+
## Requirements
4+
This project requires Git Large File Storage (LFS). Please ensure you have it installed and configured in your Git environment.
5+
```powershell
6+
git lfs install
7+
```

adesso_se_matrix42_analytics.pbix

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:ff98c3410f91e847e44999f260cd94b144569ee0a5b59f4ff10c02214125d23c
3+
size 111801841
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:339ff70faed8e3295758dbf0de484d0c02ee382500dac2f0ba02a9054d8c4865
3+
size 135544138

matrix42/active_agents.sql

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
WITH ParticipatingRoles(TicketObjectId, ValidFrom, RoleId) AS (
2+
/*
3+
1. HISTORY OF ROLE ASSIGNMENTS
4+
Reconstructs the timeline of which Role was assigned to a ticket and when.
5+
Parses XML 'SolutionParams' to find the Target Role ID.
6+
*/
7+
SELECT
8+
[Expression-ObjectID],
9+
CreatedDate,
10+
-- Extract Role ID from XML for Ticket Creation
11+
TRY_CAST(SolutionParams AS XML).value(
12+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[1]',
13+
'uniqueidentifier'
14+
)
15+
FROM
16+
SPSActivityClassUnitOfWork AS CreateJournal
17+
WHERE
18+
ActivityAction = 1
19+
OR ActivityAction = 19 -- Ticket Creation (Service Desk/SSP) [18 from mail does not expose recipient role!]
20+
UNION
21+
SELECT
22+
[Expression-ObjectID],
23+
CreatedDate,
24+
-- Extract Role ID from XML for Forwarding
25+
TRY_CAST(SolutionParams AS XML).value(
26+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[1]',
27+
'uniqueidentifier'
28+
)
29+
FROM
30+
SPSActivityClassUnitOfWork AS ForwardJournal
31+
WHERE
32+
ActivityAction = 3 -- Forward to Role
33+
OR ActivityAction = 30 -- Forward to Role & User
34+
UNION
35+
SELECT
36+
[Expression-ObjectID],
37+
CreatedDate,
38+
-- Extract New Role ID from XML for Role Changes (Node [2] is usually the 'New' value)
39+
TRY_CAST(SolutionParams AS XML).value(
40+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[2]',
41+
'uniqueidentifier'
42+
)
43+
FROM
44+
SPSActivityClassUnitOfWork AS ChangeJournal
45+
WHERE
46+
ActivityAction = 74 -- Change Assigned Role
47+
),
48+
PaddedParticipatingRoles(TicketObjectId, ValidFrom, RoleId) AS (
49+
/*
50+
2. PAD ROLE HISTORY
51+
Adds a fallback entry for tickets that never had their role changed and no creation journal exists.
52+
Uses the Ticket's RecipientRole as the initial role assignment date.
53+
*/
54+
SELECT
55+
[Expression-ObjectID],
56+
COALESCE(
57+
MAX(ParticipatingRoles.ValidFrom),
58+
Ticket.CreatedDate
59+
),
60+
Ticket.RecipientRole
61+
FROM
62+
ParticipatingRoles
63+
INNER JOIN SPSActivityClassBase AS Ticket ON ParticipatingRoles.TicketObjectId = Ticket.[Expression-ObjectID]
64+
WHERE
65+
Ticket.RecipientRole IS NOT NULL
66+
GROUP BY
67+
[Expression-ObjectID],
68+
Ticket.CreatedDate,
69+
Ticket.RecipientRole
70+
),
71+
AgentInteractions(
72+
TicketObjectId,
73+
CreatedDate,
74+
Creator
75+
) AS (
76+
/*
77+
3. AGENT ACTIVITY
78+
Filters the journal for specific manual actions (Edits, Emails, Closures)
79+
performed by agents within the last 3 years.
80+
*/
81+
SELECT
82+
Ticket.[Expression-ObjectID],
83+
Journal.CreatedDate,
84+
Journal.Creator
85+
FROM
86+
dbo.SPSActivityClassUnitOfWork AS Journal
87+
INNER JOIN dbo.SPSActivityClassBase AS Ticket ON Journal.[Expression-ObjectID] = Ticket.[Expression-ObjectID]
88+
WHERE
89+
Journal.Creator IS NOT NULL
90+
AND Journal.CreatedDate >= DATEADD(year, -3, GETDATE())
91+
AND Journal.ActivityAction IN (
92+
-- 4: Editing/Taking over a Ticket
93+
-- 7: Accepting a Ticket
94+
-- 8: Closing a Ticket
95+
-- 9, 33, 34: Merging a Ticket
96+
-- 11: Sending an E-mail
97+
-- 66: Ticket to Incident Transformation
98+
-- 67: Ticket to Service Request Transformation
99+
-- 68: Incident to Service Request Transformation
100+
-- 69: Service Request to Incident Transformation
101+
-- 82 + 83: Pausing a Ticket
102+
-- 84: Resolving a Ticket
103+
4,
104+
7,
105+
8,
106+
9,
107+
11,
108+
33,
109+
34,
110+
66,
111+
67,
112+
68,
113+
69,
114+
82,
115+
83,
116+
84
117+
)
118+
AND (
119+
Ticket.UsedInTypeSPSActivityTypeTicket IS NOT NULL
120+
OR Ticket.UsedInTypeSPSActivityTypeIncident IS NOT NULL
121+
OR Ticket.UsedInTypeSPSActivityTypeServiceRequest IS NOT NULL
122+
)
123+
),
124+
RankedRolesPerInteraction AS (
125+
/*
126+
4. MATCH INTERACTION TO ACTIVE ROLE
127+
Joins interactions with role history.
128+
Uses ROW_NUMBER to find the MOST RECENT role assignment relative to the interaction date.
129+
*/
130+
SELECT
131+
AgentInteractions.TicketObjectId,
132+
AgentInteractions.CreatedDate AS InteractionDate,
133+
AgentInteractions.Creator,
134+
Roles.RoleId,
135+
-- Rank 1 is the most recent role assignment before the interaction happened
136+
ROW_NUMBER() OVER (
137+
PARTITION BY AgentInteractions.TicketObjectId,
138+
AgentInteractions.CreatedDate,
139+
AgentInteractions.Creator
140+
ORDER BY
141+
Roles.ValidFrom DESC
142+
) AS RoleRank
143+
FROM
144+
AgentInteractions
145+
INNER JOIN PaddedParticipatingRoles AS Roles ON AgentInteractions.TicketObjectId = Roles.TicketObjectId
146+
WHERE
147+
-- Ensure we only look at roles assigned BEFORE or AT the same time as the interaction
148+
Roles.ValidFrom <= AgentInteractions.CreatedDate
149+
AND -- This is an unlucky case where RoleId extraction might fail; we exclude NULLs here => Might falsify results slightly
150+
Roles.RoleId IS NOT NULL
151+
)
152+
/*
153+
5. FINAL OUTPUT
154+
Filters for Rank 1 to retrieve only the single active role for that specific interaction.
155+
*/
156+
SELECT
157+
CAST(InteractionDate AS date) AS [Date],
158+
Creator AS UserId,
159+
RoleId,
160+
COUNT(*) AS JournalInteractions
161+
FROM
162+
RankedRolesPerInteraction
163+
WHERE
164+
RoleRank = 1
165+
GROUP BY
166+
CAST(InteractionDate AS date),
167+
Creator,
168+
RoleId
169+
ORDER BY
170+
-- Optional: Sorts by date descending, then by Creator and RoleId to improve readability
171+
[Date] DESC,
172+
[Creator],
173+
[RoleId];

matrix42/install.sql

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- 1. Populate the Calendar table with dates from 2010-01-01 to 2099-12-31
2+
BEGIN TRANSACTION;
3+
SET DATEFIRST 1;
4+
-- Clear any existing data (if any)
5+
PRINT 'Clearing Calendar table...';
6+
DELETE FROM dbo.Ud_CalendarDateSeries;
7+
8+
-- Populate the table with dates from 2010-01-01 to 2099-12-31
9+
PRINT 'Populating Calendar table...';
10+
11+
DECLARE @StartDate DATE = '2010-01-01';
12+
DECLARE @EndDate DATE = '2099-12-31';
13+
DECLARE @NumberOfDays INT = DATEDIFF(day, @StartDate, @EndDate);
14+
15+
-- Use a recursive CTE to generate a sequence of numbers from 0 to @NumberOfDays.
16+
;WITH NumberSequence(n) AS (
17+
SELECT 0
18+
UNION ALL
19+
SELECT n + 1 FROM NumberSequence WHERE n < @NumberOfDays
20+
)
21+
22+
INSERT INTO dbo.Ud_CalendarDateSeries ([Value], [Ud_Date], [Ud_WeekDayNumber])
23+
SELECT
24+
n,
25+
DATEADD(day, n, @StartDate),
26+
DATEPART(weekday, DATEADD(day, n, @StartDate))
27+
FROM
28+
NumberSequence
29+
OPTION (MAXRECURSION 0); -- Required to allow recursion beyond the default 100 level limit.
30+
31+
PRINT 'Table dbo.Ud_CalendarDateSeries populated successfully.';
32+
COMMIT;
33+
34+
-- 2. Add a non-clustered index on WeekDayNumber for fast filtering and joins
35+
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_Ud_CalendarDateSeries_WeekDayNumber' AND object_id = OBJECT_ID('dbo.Ud_CalendarDateSeries'))
36+
BEGIN
37+
CREATE NONCLUSTERED INDEX IX_Ud_CalendarDateSeries_WeekDayNumber
38+
ON dbo.Ud_CalendarDateSeries (Ud_WeekDayNumber);
39+
PRINT 'Created non-clustered index on WeekDayNumber.';
40+
END;
41+
42+
-- 3. Add a non-clustered index on Date for fast filtering and joins
43+
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE name = 'IX_Ud_CalendarDateSeries_Date' AND object_id = OBJECT_ID('dbo.Ud_CalendarDateSeries'))
44+
BEGIN
45+
CREATE NONCLUSTERED INDEX IX_Ud_CalendarDateSeries_Date
46+
ON dbo.Ud_CalendarDateSeries (Ud_Date);
47+
PRINT 'Created non-clustered index on Date.';
48+
END;

matrix42/participating_roles.sql

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
WITH ParticipatingRoles(TicketObjectId, ValidFrom, RoleId) AS (
2+
SELECT
3+
[Expression-ObjectID],
4+
CreatedDate,
5+
TRY_CAST(SolutionParams AS XML).value(
6+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[1]',
7+
'uniqueidentifier'
8+
)
9+
FROM
10+
SPSActivityClassUnitOfWork AS CreateJournal
11+
WHERE
12+
ActivityAction = 1 -- Ticket Creation in Service Desk
13+
OR ActivityAction = 19 -- Ticket Creation in Self Service Portal
14+
UNION
15+
SELECT
16+
[Expression-ObjectID],
17+
CreatedDate,
18+
TRY_CAST(SolutionParams AS XML).value(
19+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[1]',
20+
'uniqueidentifier'
21+
)
22+
FROM
23+
SPSActivityClassUnitOfWork AS ForwardJournal
24+
WHERE
25+
ActivityAction = 3 -- Forward to Role
26+
OR ActivityAction = 30 -- Forward to Role AND User
27+
UNION
28+
SELECT
29+
[Expression-ObjectID],
30+
CreatedDate,
31+
TRY_CAST(SolutionParams AS XML).value(
32+
'(/parameters/JournalEntryParameterBase/FragmentIds/fragmentId)[2]',
33+
'uniqueidentifier'
34+
)
35+
FROM
36+
SPSActivityClassUnitOfWork AS ChangeJournal
37+
WHERE
38+
ActivityAction = 74 -- Change Assigned Role From Old -> New
39+
UNION
40+
SELECT
41+
[Expression-ObjectID],
42+
COALESCE(ClosedDate, GETDATE()),
43+
RecipientRole
44+
FROM
45+
SPSActivityClassBase
46+
WHERE
47+
RecipientRole IS NOT NULL
48+
)
49+
SELECT
50+
*
51+
FROM
52+
ParticipatingRoles
53+
ORDER BY
54+
TicketObjectId,
55+
ValidFrom ASC;

0 commit comments

Comments
 (0)