Reputation: 105
Scenario
Company XYZ sells products. Company measures their performance by checking how long does it take to complete the entire order. Each order goes through multiple status (Example : Open, Pending, Close)
They count days for each status to know how many days an order was on a particular status. the days are calculated in two different ways, Working Days and Calendar Days
Please refer to the below table:
Question
How to turn this table into a pivot table shown in below picture? also how to add to additional columns which is total of each Working and business day status.
Desired Result:
Upvotes: 1
Views: 74
Reputation: 79969
You can do this:
SELECT *
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
DayCount
FROM CalendarTable
) AS t
PIVOT
(
MAX(DayCount)
For StatusType IN(OpenWorking,
OpenCalendar,
CloseWorking,
CloseCalendar,
PendingWorking,
PendingCalendar,
TotalWorking,
TotalCalendar)
) AS p;
This will give you:
If you don't want to write down all the statuses manually, then you can do ti dynamically:
DECLARE @cols AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);
SELECT @cols = STUFF((SELECT distinct ',' +
QUOTENAME(StatusType)
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
DayCount
FROM CalendarTable
) AS t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT @query = 'SELECT *
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = ''Working'' THEN ''TotalWorking'' ELSE ''TotalCalendar'' END,
DayCount
FROM CalendarTable
) AS t
PIVOT
(
MAX(DayCount)
For StatusType IN(' + @cols + ')' +
') p';
execute(@query);
Update:
For column names you can create a new variable @colnames
and populate it with the names you want. For the Totals, you can add a WHERE
clause to get the total for statuses active and pending only. So your query will be like this:
DECLARE @cols AS NVARCHAR(MAX);
DECLARE @colnames AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);
SELECT @cols = STUFF((SELECT distinct ',' +
QUOTENAME(StatusType)
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
DayCount
FROM CalendarTable
WHERE OrderStatus IN('Active', 'Pending')
) AS t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT @colnames = STUFF((SELECT distinct ',' +
QUOTENAME(StatusType) + ' AS ' + QUOTENAME(StatusTypeName)
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount,
OrderStatus + CASE WHEN CountType = 'Working' THEN 'WorkDays' ELSE 'CalDays' END AS StatusTypeName
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
DayCount,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END
FROM CalendarTable
WHERE OrderStatus IN('Active', 'Pending')
) AS t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT @query = 'SELECT OrderID , ' + @colnames + '
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = ''Working'' THEN ''TotalWorking'' ELSE ''TotalCalendar'' END,
DayCount
FROM CalendarTable
WHERE OrderStatus IN(''Active'', ''Pending'')
) AS t
PIVOT
(
SUM(DayCount)
For StatusType IN(' + @cols + ')' +
') p';
execute(@query);
This will give you:
If you want to add a where clause to the manual pivot query, you can do this:
SELECT *
FROM
(
SELECT
OrderID,
OrderStatus + CountType AS StatusType,
DayCount
FROM CalendarTable
WHERE ...
UNION ALL
SELECT
OrderID,
CASE WHEN CountType = 'Working' THEN 'TotalWorking' ELSE 'TotalCalendar' END,
DayCount
FROM CalendarTable
WHERE ...
) AS t
PIVOT
(
MAX(DayCount)
For StatusType IN(OpenWorking,
OpenCalendar,
CloseWorking,
CloseCalendar,
PendingWorking,
PendingCalendar,
TotalWorking,
TotalCalendar)
) AS p;
Upvotes: 1