Related
I have following SQL script which I hope to cross apply to select Chinese column name
CREATE TABLE #temp([color] varchar(5), [size] varchar(5),[AQty] varchar(10),[BQty] varchar(10),[CQty] varchar(10),[DQty] varchar(10));
INSERT INTO #temp([color], [size], [AQty], [BQty],[CQty],[DQty])
VALUES ('A1', 'L','1','2','3','4')
, ('A1', 'M','1','2','3','4')
, ('A1', 'S','1','2','3','4')
, ('A1', 'XL','1','2','3','4')
, ('B1', 'L','1','2','3','4')
, ('B1', 'M','1','2','3','4')
, ('B1', 'S','1','2','3','4')
, ('B1', 'XL','1','2','3','4')
, ('B1', 'XXL','1','2','3','4')
, ('C1', 'L','1','2','3','4')
, ('C1', 'S','1','2','3','4')
declare #cols as varchar(max), #sql varchar(max)
select #cols = STRING_AGG(col, ', ') from (
select distinct QUOTENAME(size) as col from #temp
) as t
set #sql = '
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select ''总数一'', cast(AQty as varchar(10)) union all
select ''总数二'', cast(BQty as varchar(10)) union all
select ''总数三'', cast(CQty as varchar(10)) union all
select ''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
But now exec SQL is display garbled when I hope to display Chinese column name
color total L M S XL XXL
A1 ??? 4 4 4 4 NULL
B1 ??? 4 4 4 4 4
C1 ??? 4 NULL4 NULLNULL
I tried to change it like this, change variable nvarchar, set #sql with N and change cross apply select with N, but now not work.
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + '
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
I have solved my problem by adding N after + #cols +
declare #cols as nvarchar(max), #sql nvarchar(max)
set #sql = N'
select color, col as total, ' + #cols + N'
from(
select color, size, col, [value]
from #temp
cross apply (
select N''总数一'', cast(AQty as varchar(10)) union all
select N''总数二'', cast(BQty as varchar(10)) union all
select N''总数三'', cast(CQty as varchar(10)) union all
select N''总数四'', cast(DQty as varchar(10))
) c(col, [value])
) d
pivot
(
max(value)
for size in (' + #cols + ')
) piv
order by color, total
'
exec(#sql)
In SQL Server 2008, I have a table tblStock with 4 columns:
PartCode (NVARCHAR (50))
Role (NVarchar(10))
StockQty (INT)
Location (NVARCHAR(50))
Some example data below:
I have written this code to get the following output:
IF OBJECT_ID('tempdb..#tblData') IS NOT NULL
DROP TABLE #tblData
SELECT *
INTO #tblData
FROM
(SELECT 'A' PartCode, 'Manager' As [Role], 10 StockQty, 'in-A' Location
UNION ALL
SELECT 'B', 'Director' As [Role], 22, 'in-A'
UNION ALL
SELECT 'A', 'Director' As [Role], 1, 'in-B'
UNION ALL
SELECT 'C', 'Director' As [Role], 20, 'in-A'
UNION ALL
SELECT 'D', 'Director' As [Role], 39, 'in-F'
UNION ALL
SELECT 'E', 'Director' As [Role], 3, 'in-D'
UNION ALL
SELECT 'F', 'Director' As [Role], 7, 'in-A'
UNION ALL
SELECT 'A', 'Director' As [Role], 9, 'in-C'
UNION ALL
SELECT 'D', 'Director' As [Role], 2, 'in-A'
UNION ALL
SELECT 'F', 'Director' As [Role], 54, 'in-E') TAB
SELECT *
FROM #tblData
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + Location + ']', '[' + Location + ']')
FROM (SELECT DISTINCT Location FROM #tblData) PV
ORDER BY Location
SELECT #cols += ',[Total]'
DECLARE #NulltoZeroCols NVARCHAR (MAX)
SELECT #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+Location+'],0) AS ['+Location+']'
FROM (SELECT DISTINCT Location FROM #tblData)TAB
ORDER BY Location FOR XML PATH('')),2,8000)
SELECT #NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT PartCode, Role, ' + #NulltoZeroCols + ' FROM
(
SELECT
ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode,
Role,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblData
GROUP BY Location,PartCode,Role
WITH CUBE
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + #cols + ')
) p
ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode'
EXEC SP_EXECUTESQL #query
Result for the above query is:
I want to get the result like this:
Please share your ideas - thanks!
Not MIN, use SUM. Also, you should not select the Role column.
Try this;
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + Location + ']', '[' + Location + ']')
FROM (SELECT DISTINCT Location FROM #tblData) PV
ORDER BY Location
SELECT #cols += ',[Total]'
DECLARE #NulltoZeroCols NVARCHAR (MAX)
SELECT #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+Location+'],0) AS ['+Location+']'
FROM (SELECT DISTINCT Location FROM #tblData)TAB
ORDER BY Location FOR XML PATH('')),2,8000)
DECLARE #SumCols NVARCHAR (MAX)
SELECT #SumCols = SUBSTRING((SELECT '+(ISNULL(['+Location+'],0))'
FROM (SELECT DISTINCT Location FROM #tblData)TAB
ORDER BY Location FOR XML PATH('')),2,8000)
PRINT #SumCols
SET #SumCols += ') AS [Total]'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT PartCode, (SELECT TOP 1 Role FROM #tblData WHERE PartCode=p.PartCode) Role, ' + #NulltoZeroCols +', ('+ #SumCols+' FROM
(
SELECT
ISNULL(CAST(PartCode AS VARCHAR(30)),''Total'')PartCode,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblData
GROUP BY Location,PartCode
WITH CUBE
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + #cols + ')
) p
ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode'
PRINT #query
EXEC SP_EXECUTESQL #query
Updated part will be,
SET #query = 'SELECT PartCode, Role, ' + #NulltoZeroCols + ' FROM
(
SELECT PartCode, Role, StockQty, Location
FROM #tblData
UNION ALL
SELECT PartCode, Role, SUM(StockQty), ''Total'' as Location
FROM #tblData
GROUP BY PartCode, Role
UNION ALL
SELECT
''Total'' PartCode,
''Total'' Role,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblData
GROUP BY Location
WITH cube
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + #cols + ')
) p
ORDER BY CASE WHEN (PartCode=''Total'') THEN 1 ELSE 0 END,PartCode'
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT p.PartCode, (SELECT TOP 1 Role FROM #tblData t3 WHERE t3.PartCode = p.PartCode and t3.Role = t2.Role ) Role, ' + #NullToZeroCols +', ('+ #SumCols+' FROM
(
SELECT
ISNULL(CAST(t1.PartCode AS VARCHAR(30)),''Total'')PartCode,
-- Role,
SUM(StockQty)StockQty ,
ISNULL(Location,''Total'')Location
FROM #tblData t1
GROUP BY Location,t1.PartCode
WITH CUBE
) x
PIVOT
(
MIN(StockQty)
FOR Location IN (' + #cols + ')
) p
left JOIN #tblData t2 on t2.PartCode = p.PartCode
GROUP BY t2.Role,p.PartCode, ' + #cols +'
ORDER BY CASE WHEN (p.PartCode=''Total'') THEN 1 ELSE 0 END,p.PartCode'
PRINT #query
EXEC (#query)
I have this stored procedure:
USE [Baxe]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[CreateTable]
AS
BEGIN
DECLARE #cols AS nvarchar( max) ,
#query AS nvarchar( max);
SET #cols = STUFF(( SELECT DISTINCT ',' + QUOTENAME( bmarke)
FROM subbuyer FOR XML PATH( '' ) , TYPE ).value( '.' , 'NVARCHAR(MAX)') , 1 , 1 , '');
SET #query = 'SELECT bdate, ' + #cols + ' from ( select bdate, bprice as q , bmarke from subbuyer ) x
pivot ( SUM(q)for bmarke in (' + #cols + ') ) p ';
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(convert(CHAR(10), bmarke, 120))
from subbuyer
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
PRINT #query;
PRINT #cols;
EXECUTE ( #query );
end
Which gives me this output:
Last row with TOTAL is what I need to add. How can I do this?
Put your query in CTE or temp table and use GROUP BY ROLLUP:
;WITH cte AS (
--your query here
)
SELECT ISNULL(bdate,'TOTAL') bdate,
SUM(Total) Total,
SUM(ACCESSORIES) ACCESSORIES,
SUM(NBB) NBB,
SUM(UNDERWARE) UNDERWARE
FROM cte
GROUP BY ROLLUP (bdate)
Output:
bdate Total ACCESSORIES NBB UNDERWARE
13/04/2016 7000 7000 NULL NULL
14/04/2016 3000 NULL NULL 3000
15/04/2016 3000 NULL NULL 3000
16/04/2016 3000 NULL 3000 NULL
17/04/2016 23000 14000 6000 3000
TOTAL 39000 21000 9000 9000
EDIT#1
Based on sample you provided. You need to add variable with column names with SUM function:
DECLARE #sumcols nvarchar(max)
SET #sumcols = STUFF(( SELECT DISTINCT ', SUM(' + QUOTENAME( bmarke)+') as ' + QUOTENAME(bmarke)
FROM subbuyer FOR XML PATH( '' ) , TYPE ).value( '.' , 'NVARCHAR(MAX)') , 1 , 1 , '');
And change your dynamic query, so your previous query will be in sub-query:
--Forgot about two quotes around TOTAL
SET #query = 'SELECT ISNULL(bdate,''TOTAL'') bdate, '+#sumcols + ' FROM (
SELECT bdate, ' + #cols + ' from ( select bdate, bprice as q , bmarke from subbuyer ) x
pivot ( SUM(q)for bmarke in (' + #cols + ') ) p
) t GROUP BY ROLLUP (bdate)';
Hope this helps.
EDIT#2
To add TOTAL column use:
DECLARE #pluscols nvarchar(max)
SET #pluscols = STUFF(( SELECT DISTINCT '+' + QUOTENAME( bmarke)
FROM subbuyer FOR XML PATH( '' ) , TYPE ).value( '.' , 'NVARCHAR(MAX)') , 1 , 1 , '') + ' as [TOTAL]';
And change your dynamic query, so your previous query will be in sub-query:
--Forgot about two quotes around TOTAL
SET #query = 'SELECT ISNULL(bdate,''TOTAL'') bdate, '+#sumcols + ', SUM([TOTAL]) as [TOTAL] FROM (
SELECT bdate, ' + #cols + ', ' + #pluscols + ' from ( select bdate, bprice as q , bmarke from subbuyer ) x
pivot ( SUM(q)for bmarke in (' + #cols + ') ) p
) t GROUP BY ROLLUP (bdate)';
and this is my producer
use baxe
DECLARE #cols AS nvarchar( max) ,
#query AS nvarchar( max);
SET #cols = STUFF(( SELECT DISTINCT ',' + QUOTENAME( bmarke)
FROM subbuyer FOR XML PATH( '' ) , TYPE ).value( '.' , 'NVARCHAR(MAX)') , 1 , 1 , '');
SET #query = 'SELECT ISNULL(bdate,''TOTAL'') bdate, '+#cols + ' FROM (SELECT bdate, ' + #cols + ' from ( select bdate, bprice as q , bmarke from subbuyer ) x
pivot ( SUM(q)for bmarke in (' + #cols + ') ) p;
) GROUP BY ROLLUP (bdate)';
PRINT (#query )
PRINT (#cols)
EXEC (#query)
I have data in the following format:
I need to pivot this to get the data as follows.
Please help!!!
Something like this. In this case you need to have a fixed list of names.
SELECT
SUM(CASE WHEN Student='Mike' THEN [English Mark] ELSE 0 END) as [Mike English Mark],
SUM(CASE WHEN Student='Mike' THEN [Maths Mark] ELSE 0 END) as [Mike Maths Mark],
SUM(CASE WHEN Student='Fisher' THEN [English Mark] ELSE 0 END) as [Fisher English Mark],
SUM(CASE WHEN Student='Fisher' THEN [Maths Mark] ELSE 0 END) as [Fisher Maths Mark],
SUM(CASE WHEN Student='John' THEN [English Mark] ELSE 0 END) as [John English Mark],
SUM(CASE WHEN Student='John' THEN [Maths Mark] ELSE 0 END) as [John Maths Mark],
[TestName]
FROM Table1
GROUP BY [Test Name]
The solution I got is a bit tricky but very dynamic.
You should first unpivot your table, and put the data in a temp table, after that I get the columns name for the pivoting and put the result in the #cols variable. At the end I create a dynamic sql string to pivot the the temp table that contains my data, so even if a new student gets added to the table his 2 columns will be generated in the end result.
select test, col + ' '+ Student stu_col , value
INTO
#temp
from Marks
unpivot(value for col in (english, maths)) unpiv
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(stu_col)
from #temp order by 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT test, ' + #cols + ' from
(
select test, Value, stu_col
from #temp
) x
pivot
(
SUM(Value)
for stu_col in (' + #cols + ')
) p '
exec(#query)
DROP TABLE #temp
You can write a dynamic sql query using Pivot operator as:
DECLARE #columns NVARCHAR(MAX)
,#columnsEnglish_Mark NVARCHAR(MAX)
,#columnsMath_Mark NVARCHAR(MAX)
,#columnsFNL NVARCHAR(MAX)
,#sql NVARCHAR(MAX);
SET #columns = N'';
--Get column names for entire pivoting
SELECT #columns += N', ' + QUOTENAME(SpreadCol)
FROM (select distinct student as SpreadCol
from tblstudent
) AS T;
PRINT #columns;
--Get column names for Pivot1
SET #columnsEnglish_Mark = N'';
SELECT #columnsEnglish_Mark += N', ISNULL(' + QUOTENAME(SpreadCol) + ',0) AS [' + SpreadCol + '_English_Mark]'
FROM (select distinct student as SpreadCol
from tblstudent
) AS T
;
PRINT #columnsEnglish_Mark;
--Get column names for Pivot2
SET #columnsMath_Mark = N'';
SELECT #columnsMath_Mark += N', ISNULL(' + QUOTENAME(SpreadCol) + ',0) AS [' + SpreadCol + '_Math_Mark]'
FROM (select distinct student as SpreadCol
from tblstudent
) AS T
;
PRINT #columnsMath_Mark;
--Get final list of columns:
SET #columnsFNL = N'';
SELECT #columnsFNL += N', [' + SpreadCol + '_English_Mark], [' + SpreadCol + '_Math_Mark] '
FROM (select distinct student as SpreadCol
from tblstudent
) AS T
order by T.SpreadCol asc; -- change ordering of columns here
PRINT #columnsFNL;
SET #sql = N'
select tblEnglish_Mark.Test_Name , ' + STUFF(#columnsFNL, 1, 2, '') + ' from
'
+
'
( SELECT Test_Name, ' + STUFF(#columnsEnglish_Mark, 1, 2, '') + '
FROM
(select student as SpreadCol , English_Mark, Test_Name
from tblstudent ) as D
PIVOT
(
sum(English_Mark) FOR SpreadCol IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) AS Pivot1 ) tblEnglish_Mark
inner join
'
+
'
( SELECT Test_Name, ' + STUFF(#columnsMath_Mark, 1, 2, '') + '
FROM
(select student as SpreadCol , Test_Name,Math_Mark
from tblstudent ) as D
PIVOT
(
MAx(Math_Mark) FOR SpreadCol IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) as Pivot2 ) tblMath_Mark
on tblEnglish_Mark.Test_Name = tblMath_Mark.Test_Name ;
'
;
PRINT #sql;
EXEC sp_executesql #sql;
Hope this helps!!!
Please try:
DECLARE #pivv NVARCHAR(MAX),#Query NVARCHAR(MAX)
SELECT #pivv=COALESCE(#pivv+',','')+ QUOTENAME(Student+'_English_Mark')+','+QUOTENAME(Student+'_Maths_Mark')
FROM YourTable GROUP BY Student
IF ISNULL(#pivv, '')<>''
SET #Query='SELECT* FROM(
select English_Mark Marks, Student+''_English_Mark'' Col, Test_Name From YourTable
union all
select Maths_Mark Marks, Student+''_Maths_Mark'' Col, Test_Name From YourTable
)x pivot (sum(Marks) for Col in ('+#pivv+')) as xx'
IF ISNULL(#Query, '')<>''
EXEC (#Query)
SQL Fiddle Demo
Let's jump straight into it. Here's the code
SELECT [prov], [201304], [201305], [201306], [201307]
FROM (
SELECT [prov], [arrival], [Amount]
FROM [tblSource]) up
PIVOT (SUM([Amount]) FOR [arrival] IN ([201304], [201305], [201306], [201307])) AS pvt
GO
It brings me back an ever so lovely table. I was wondering how I would get the totals for each "date" column to show in an appended last row?
In addition, the underlying table will have more data added, specifically more dates. This means that 201308 will be added next, then 201309 etc
This will mean that currently I will have to amend the code above each month to reflect the addition. Is there anyway around this?
You can dynamically create the columns using dynamic SQL, however, I would really recommend handling dynamic pivots in a layer designed for it, such as SSRS or excel.
DECLARE #SQL NVARCHAR(MAX) = '',
#SQL2 NVARCHAR(MAX) = '',
#SQL3 NVARCHAR(MAX) = '';
-- COMPILE THE UNIQUE VALUES FOR ARRIVAL THAT NEED TO BE PIVOTED
SELECT #SQL = #SQL + ',' + QUOTENAME(Arrival),
#SQL2 = #SQL2 + '+ISNULL(' + QUOTENAME(Arrival) + ', 0)',
#SQL3 = #SQL3 + ',' + QUOTENAME(Arrival) + ' = ISNULL(' + QUOTENAME(Arrival) + ', 0)'
FROM (SELECT DISTINCT Arrival FROM tblSource) s;
-- COMBINE THEM INTO A SINGLE QUERY
SET #SQL = 'SELECT [Prov]' + #SQL3 + ', [Total] = ' + STUFF(#SQL2, 1, 1, '') + '
FROM ( SELECT Arrival, Prov, Amount
FROM [tblSource]
UNION ALL
SELECT Arrival, ''Total'', SUM(Amount)
FROM [tblSource]
GROUP BY Arrival
) up
PIVOT
( SUM(Amount)
FOR Arrival IN (' + STUFF(#SQL, 1, 1, '') + ')
) pvt;';
-- EXECUTE THE QUERY
EXECUTE SP_EXECUTESQL #SQL;
This creates and executes the following SQL:
SELECT [Prov],
[2013-01-01] = ISNULL([2013-01-01], 0),
[2013-02-01] = ISNULL([2013-02-01], 0),
[Total] = ISNULL([2013-01-01], 0) + ISNULL([2013-02-01], 0)
FROM ( SELECT Arrival, Prov, Amount
FROM [tblSource]
UNION ALL
SELECT Arrival, 'Total', SUM(Amount)
FROM [tblSource]
GROUP BY Arrival
) up
PIVOT
( SUM(Amount)
FOR Arrival IN ([2013-01-01],[2013-02-01])
) pvt;
It is the query below union in the subquery up that adds the total row at the bottom, and the row total is simply created by adding all the columns in the row.
Example on SQL Fiddle
I will stress again though, I really recommend handling manipulation of data like this outside of SQL.
EDIT
An alternative to using the UNION to get the the total row is to use GROUPING SETS as follows:
DECLARE #SQL NVARCHAR(MAX) = '',
#SQL2 NVARCHAR(MAX) = '',
#SQL3 NVARCHAR(MAX) = '';
-- COMPILE THE UNIQUE VALUES FOR ARRIVAL THAT NEED TO BE PIVOTED
SELECT #SQL = #SQL + ',' + QUOTENAME(Arrival),
#SQL2 = #SQL2 + '+ISNULL(' + QUOTENAME(Arrival) + ', 0)',
#SQL3 = #SQL3 + ',' + QUOTENAME(Arrival) + ' = ISNULL(' + QUOTENAME(Arrival) + ', 0)'
FROM (SELECT DISTINCT Arrival FROM tblSource) s;
-- COMBINE THEM INTO A SINGLE QUERY
SET #SQL = 'SELECT [Prov]' + #SQL3 + ', [Total] = ' + STUFF(#SQL2, 1, 1, '') + '
FROM ( SELECT Arrival, Prov = ISNULL(Prov, 'Total'), Amount = SUM(Amount)
FROM [tblSource]
GROUP BY GROUPING SETS((Prov, arrival), (arrival))
) up
PIVOT
( SUM(Amount)
FOR Arrival IN (' + STUFF(#SQL, 1, 1, '') + ')
) pvt;';
-- EXECUTE THE QUERY
EXECUTE SP_EXECUTESQL #SQL;
SAMPLE TABLE
CREATE TABLE #TEMP([prov] VARCHAR(100),[arrival] INT, AMOUNT NUMERIC(12,2))
INSERT INTO #TEMP
SELECT 'A' [prov],'201304' [arrival],100 AMOUNT
UNION ALL
SELECT 'A' ,'201305' ,124
UNION ALL
SELECT 'A' ,'201306' ,156
UNION ALL
SELECT 'B' ,'201304' ,67
UNION ALL
SELECT 'B' ,'201305' ,211
UNION ALL
SELECT 'B' ,'201306' ,176
UNION ALL
SELECT 'C' ,'201304' ,43
UNION ALL
SELECT 'C' ,'201305' ,56
UNION ALL
SELECT 'C' ,'201306' ,158
QUERY
You can use ROLLUP to get the row total. More about ROLLUP here
-- Get the columns for dynamic pivot
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + CAST([arrival] AS VARCHAR(50)) + ']',
'[' + CAST([arrival] AS VARCHAR(50)) + ']')
FROM (SELECT DISTINCT [arrival] FROM #TEMP) PV
ORDER BY [arrival]
-- Replace NULL value with zero
DECLARE #NulltoZeroCols NVARCHAR (MAX)
SELECT #NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+[arrival]+'],0) AS ['+[arrival]+']'
FROM (SELECT DISTINCT CAST([arrival] AS VARCHAR(50)) [arrival] FROM #TEMP)TAB
ORDER BY CAST([arrival]AS INT) FOR XML PATH('')),2,8000)
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT [prov],' + #NullToZeroCols + ' FROM
(
SELECT
ISNULL([prov],''Total'')[prov],
SUM(AMOUNT)AMOUNT ,
ISNULL(CAST([arrival] AS VARCHAR(50)),''Total'')[arrival]
FROM #TEMP
GROUP BY [arrival],[prov]
WITH ROLLUP
) x
PIVOT
(
MIN(AMOUNT)
FOR [arrival] IN (' + #cols + ')
) p
ORDER BY CASE WHEN ([prov]=''Total'') THEN 1 ELSE 0 END,[prov]'
EXEC SP_EXECUTESQL #query
Note : If you do not want to replace NULL with zero, just replace #NullToZeroCols with #cols in outer query of dynamic pivot