我有一个动态Pivot
查询,如下所示:
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
DECLARE @start AS DateTime
DECLARE @end AS DateTime
DECLARE @business AS VARCHAR(50)
SET @start = '2015-01-01';
SET @end = '2015-12-01';
SET @business = 'EUR';
--Get distinct values of the PIVOT Column
SELECT @ColumnName= ISNULL(@ColumnName + ',','')
+ QUOTENAME(date1)
FROM (
SELECT m.date1, m.date2 FROM(
SELECT DISTINCT CONVERT(nvarchar(50), DATENAME(m, date)
+ ', '
+ DATENAME(yyyy,date)) as date1, date as date2
FROM bus_best where date between @start and @end
)m
)tab order by tab.date2
SET @DynamicPivotQuery =
'select * from (
select sum(bb.value) as value, bb.date as date, c.name as Name from bus_best bb
join pro p on p.id = bb.id
join con c on c.id = p.id
join bus_t bu on bu.id = c.id
where bb.date between '''+ cast (@start as VARCHAR(50))+''' and '''+ cast (@end as VARCHAR(50))+'''
and bu.name = '''+ cast (@business as VARCHAR(50))+'''
group by bb.date, c.name
) as t
PIVOT(SUM(t.value)
FOR date IN (' + @ColumnName + ')) AS PVTTable'
EXEC sp_executesql @DynamicPivotQuery
,输出类似于:
Name Jan Feb March April May June July ....
----------------------------------------------------------
Name1 32 654 1 42 342 4 4543
Name2 54 3 234 43 453 432 22
Name3 55 12 56 1234 43 643 12
Name4 77 235 3566 35635 23 2 3462
我想要的只是在最后一行添加所有行的总和,如:
Name Jan Feb March April May June July ....
----------------------------------------------------------
Name1 32 654 1 42 342 4 4543
Name2 54 3 234 43 453 432 22
Name3 55 12 56 1234 43 643 12
Name4 77 235 3566 35635 23 2 3462
Total ... .... .... .... .... .... .....
答案 0 :(得分:1)
使用GROUPING SETS
,您可以将总行数添加到子查询中,如果您有查询,则可以作为一个简单示例:
SELECT A, B, SUM(C) AS C
FROM T
GROUP BY A, B;
这会给你:
A B C
-------------------
1 1 5
1 2 3
2 1 8
2 2 1
如果您使用分组集如下
SELECT A, B, SUM(C) AS C
FROM T
GROUP BY GROUPING SETS ((A, B), (A));
你得到了
A B C
-------------------
1 1 5
1 2 3
1 NULL 8 -- Total for A = 1
2 1 8
2 2 1
2 NULL 9 -- Total for A = 2
这相当于:
SELECT A, B, SUM(C) AS C
FROM T
GROUP BY A, B
UNION ALL
SELECT A, NULL, SUM(C) AS C
FROM T
GROUP BY A;
因此,每个分组集基本上代表了另一个查询,但内部SQL Server能够重用聚合,因此更有效。您需要做的只是替换NULL
的{{1}}值,并且您有总行数。
我也会advise against variable concatenation(Total
)因为结果不能保证是正确的。而是使用XML extensions to concatenate your rows to columns。
另外,我会使用参数化查询,而不是:
SELECT @Columnname = @ColumnName + SomeField FROM SomeTable
改为使用:
DECLARE @Variable VARCHAR(10) = 'TEST';
SET @DynamicPivotQuery = 'SELECT * FROM T WHERE Column = ''' + @Variable + '''';
EXECUTE sp_executesql @DynamicPivotQuery;
这为您提供了正确的类型化参数,因此无需将日期转换为varchars以将其添加到查询中,只是为了使查询在执行时必须将它们转换回日期。
最后,我还没有纠正这个问题,但是在处理日期时我会建议使用DECLARE @Variable VARCHAR(10) = 'TEST';
SET @DynamicPivotQuery = 'SELECT * FROM T WHERE Column = @Param';
EXECUTE sp_executesql @DynamicPivotQuery, N'@Param VARCHAR(10)', @Param = @Variable;
,在下面的文章中可以很好地总结出这个原因:
最后查询:'
BETWEEN
N.B。我还没有完全测试过,因为它需要创建4个表,我只能猜测数据,但是如果有一些小的语法错误,答案和链接中有足够的信息可以让你走上正确的轨道
完整的工作示例
DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)
DECLARE @start AS DATETIME
DECLARE @end AS DATETIME
DECLARE @business AS VARCHAR(50)
SET @start = '2015-01-01';
SET @end = '2015-12-01';
SET @business = 'EUR';
--Get distinct values of the PIVOT Column
-- Uses "DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)" to get the first of each
-- month then converts this to the format "yyyymmdd" (this is culture insensitive)
SET @ColumnName =
STUFF(( SELECT ',' + QUOTENAME(CONVERT(VARCHAR(10), D.[Date], 112))
FROM ( SELECT [Date] = DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)
FROM bus_best
WHERE [Date] BETWEEN @start AND @end
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)
) AS d
ORDER BY d.[Date]
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '');
SET @DynamicPivotQuery =
'SELECT Name, ' + @ColumnName + '
FROM ( SELECT SUM(bb.value) AS Value,
Date = DATEADD(MONTH, DATEDIFF(MONTH, 0, bb.date), 0),
ISNULL(c.name, ''Total'') AS Name
FROM bus_best bb
INNER JOIN pro AS p ON p.id = bb.id
INNER JOIN con AS c ON c.id = p.id
INNER JOIN bus_t AS bu ON bu.id = c.id
WHERE bb.date BETWEEN @StartParam AND @EndParam
AND bu.name = @BusinessParam
GROUP BY GROUPING SETS
( (DATEADD(MONTH, DATEDIFF(MONTH, 0, bb.date), 0), c.name),
(DATEADD(MONTH, DATEDIFF(MONTH, 0, bb.date), 0))
)
) AS t
PIVOT
( SUM(t.value)
FOR date IN (' + @ColumnName + ')
) AS PVTTable;';
EXECUTE sp_executesql
@DynamicPivotQuery,
N'@StartParam DATETIME, @EndParam DATETIME, @BusinessParam VARCHAR(50)',
@StartParam = @Start,
@EndParam = @End,
@BusinessParam = @Business;