I have a working dynamic pivot query but am having a bit of trouble getting my Total row to display as a single row. Instead, it is giving me a Total row for each technician and a total row for my total column and invoiced amount column The invoiced column is also showing an incorrect total whereas the total column is correct.
Here is a sample of the result im currently getting. I've left off the Chargeable Utilzation as that is all correct by the looks of it.
| callID | StartDate | custMrName | Tech1 | Tech2 | Tech3 | Tech4 | Tech5 | Total | Invoiced | Chargeable Utilization |
|---|---|---|---|---|---|---|---|---|---|---|
| Total | 1.6 | |||||||||
| Total | ||||||||||
| Total | 2.2 | |||||||||
| Total | 1.46 | |||||||||
| Total | 4.55 | |||||||||
| Total | 2.77 | |||||||||
| Total | 12.58 | 28 | ||||||||
| 123 | 1.12.23 | Cust1 | 0.65 | 0.34 | 0.99 | 1 | ||||
| 234 | 1.12.23 | Cust2 | 1.10 | 1.10 | 2 | |||||
| 456 | 1.12.23 | Cust3 | 1.12 | 1.12 | 2 | |||||
| 567 | 1.12.23 | Cust4 | 0.67 | 0.67 | 1 | |||||
| 678 | 1.12.23 | Cust5 | 0.50 | 1.64 | 2.14 | 2 | ||||
| 789 | 1.12.23 | Cust6 | 4.55 | 4.55 | 5 | |||||
| 890 | 1.12.23 | Cust7 | 0.88 | 1.13 | 2.01 | 2 |
And what Im trying to get is this.
| callID | StartDate | custMrName | Tech1 | Tech2 | Tech3 | Tech4 | Tech5 | Total | Invoiced | Chargeable Utilization |
|---|---|---|---|---|---|---|---|---|---|---|
| 123 | 1.12.23 | Cust1 | 0.65 | 0.34 | 0.99 | 1 | ||||
| 234 | 1.12.23 | Cust2 | 1.10 | 1.10 | 2 | |||||
| 456 | 1.12.23 | Cust3 | 1.12 | 1.12 | 2 | |||||
| 567 | 1.12.23 | Cust4 | 0.67 | 0.67 | 1 | |||||
| 678 | 1.12.23 | Cust5 | 0.50 | 1.64 | 2.14 | 2 | ||||
| 789 | 1.12.23 | Cust6 | 4.55 | 4.55 | 5 | |||||
| 890 | 1.12.23 | Cust7 | 0.88 | 1.13 | 2.01 | 2 | ||||
| Total | 2.2 | 1.6 | 1.46 | 4.55 | 2.77 | 12.58 | 15 |
Here is the code for the query, it is quite long so ive removed a couple sections related to calculating the technician times and invoiced amount.
DECLARE @FRDATE DATE = /* SELECT FROM OINV T0 WHERE T0.DocDate >= */ [%0];
DECLARE @TODATE DATE = /* SELECT FROM OINV T0 WHERE T0.DocDate <= */ [%1];
DECLARE @columns NVARCHAR(MAX);
DECLARE @sql NVARCHAR(MAX);
SELECT @columns = STUFF((SELECT DISTINCT ',' + QUOTENAME(CONCAT(firstName, ' ', lastName)) [Technician]
FROM SCL6
INNER JOIN OHEM ON SCL6.Technician = OHEM.empID
INNER JOIN HEM6 ON HEM6.[empID] = OHEM.[empID]
INNER JOIN HTM1 ON HTM1.[empID] = OHEM.[empID]
WHERE HEM6.roleID = -2 AND HTM1.teamID IN (1, 2) AND OHEM.Active = 'Y'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
DECLARE @techTime NVARCHAR(MAX);
SET @techTime = ' /* section of code for calculating tech time';
DECLARE @invoiceQuantity NVARCHAR(MAX);
SET @invoiceQuantity = ' /* section of code for calculating amount invoiced ';
SELECT @sql = '
;WITH CTE AS (
SELECT T0.callID,
T4.StartDate,
T0.custMrName,
CONCAT(OHEM.firstName, '' '', OHEM.lastName) AS Tech,
' + @techTime + ' AS Dur,
B.Invoiced
FROM OSCL T0
INNER JOIN SCL6 T4 ON T0.callID = T4.SrcvCallID
INNER JOIN OHEM ON T4.Technician = OHEM.empID
INNER JOIN HEM6 ON HEM6.[empID] = OHEM.[empID]
INNER JOIN HTM1 ON HTM1.[empID] = OHEM.[empID]
' + @invoiceQuantity + '
WHERE T4.[Close] = ''Y'' AND
T4.Technician <> 104 AND
HEM6.roleID = -2 AND
HTM1.teamID IN (1, 2) AND
T0.customer <> ''C003435'' AND
T4.StartDate BETWEEN @FRDATE AND @TODATE
GROUP BY T0.callID, T4.StartDate, OHEM.firstName, OHEM.lastName, T4.Technician, T4.StartTime, T4.EndDate, T4.ChkInTime, T4.ChkOutTime, T4.EndTime, T4.ChkInDate, T4.ChkOutDate, B.Invoiced, T0.custMrName
UNION ALL
SELECT T0.callID,
T4.StartDate,
T0.custMrName,
''Total'' AS ''Total'',
' + @techTime + ' AS Dur,
B.Invoiced
FROM OSCL T0
INNER JOIN SCL6 T4 ON T0.callID = T4.SrcvCallID
INNER JOIN OHEM ON T4.Technician = OHEM.empID
INNER JOIN HEM6 ON HEM6.[empID] = OHEM.[empID]
INNER JOIN HTM1 ON HTM1.[empID] = OHEM.[empID]
' + @invoiceQuantity + '
WHERE T4.[Close] = ''Y'' AND
T4.Technician <> 104 AND
HEM6.roleID = -2 AND
HTM1.teamID IN (1, 2) AND
T0.customer <> ''C003435'' AND
T4.StartDate BETWEEN @FRDATE AND @TODATE
GROUP BY T0.callID, T4.StartDate, T4.Technician, OHEM.firstName, OHEM.lastName, T4.StartTime, T4.EndDate, T4.ChkInTime, T4.ChkOutTime, T4.EndTime, T4.ChkInDate, T4.ChkOutDate, B.Invoiced, T0.custMrName
)
SELECT p.callID,
p.StartDate,
p.custMrName,
' + @columns + ',
Total,
Invoiced,
CASE WHEN ISNULL(Invoiced, 0) = 0 THEN NULL ELSE CAST(CAST(ROUND(Invoiced / NULLIF(Total, 0) * 100,0) AS INT) AS VARCHAR) + ''%'' END AS [Chargeable Utilization]
FROM (
SELECT callID, StartDate, custMrName, Tech, Dur, Invoiced FROM CTE
UNION ALL
SELECT
NULL AS callID,
NULL AS StartDate,
''Total'' AS custMrName,
Tech,
SUM(Dur) AS Dur,
SUM(Invoiced) AS Invoiced
FROM CTE
GROUP BY Tech
) AS t
PIVOT (SUM(Dur) FOR Tech IN (' + @columns + ',Total)) p
ORDER BY p.StartDate ASC';
EXEC sp_executesql @sql, N'@FRDATE DATE, @TODATE DATE', @FRDATE, @TODATE
I move here from the comments. Test something like this
in the final part pay attention when using CallID and StartDate in the join. In the "total" records you have some nulls to manage: if CallId is a positive integer I think that isnull(..,0) is a good solution; about StartDate I suggest '99991231', but the important thing is to choose a "fake" value, so outside of the actual range of values you can observe on StartDate. Otherwise I think that without these isnulls the join on total records is not going to work.