SQL 服务器中 PIVOT table 中动态列的总和
SUM of dynamic Columns in PIVOT table in SQL Server
我有一个动态 PIVOT 查询,其中的列是动态生成的。
我的table:ATTENDANCE_MASTER
包含:ID、Stud_id、ATT_DATE、PRESENT
其中存储的数据如下:
ID Stud_id ATT_DATE PRESENT
1 1 2015-08-1 1
2 2 2015-08-1 0
3 3 2015-08-1 1
4 1 2015-08-2 0
5 2 2015-08-2 1
6 3 2015-08-2 1
我已经创建了 PIVOT 查询
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME(ATT_DATE)
FROM (SELECT p.ATT_DATE FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE) AS x;
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT FROM dbo.ATTENDANCE_MASTER AS p
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;
我需要像
这样的列总和
Stud_ID 2015-08-01 2015-08-2 2015-08-3 Total
1 1 0 1 2
2 1 1 1 3
3 1 1 0 2
4 0 0 1 1
请给我建议解决方案。
提前致谢。
您可以添加 GROUP BY WITH CUBE
以获得以下总计:
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME(ATT_DATE)
FROM (SELECT p.ATT_DATE FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE) AS x;
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT
FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE, p.Stud_id, p.PRESENT
WITH CUBE
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;
首先我建议不要使用变量串联来创建列列表。 It's behaviour is undefined and can be unexpected。而是使用 SQL 服务器的 XML 扩展:
SET @Columns = (SELECT N', p.' + QUOTENAME(p.Att_Date)
FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE
ORDER BY p.ATT_DATE
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
然后您可以简单地使用 @Columns
为总数创建一个表达式,因此使用:
', Total = ' + STUFF(REPLACE(@columns, ', p.[', ' + p.['), 1, 3, '')
你会得到类似的东西:
, Total = p.[2015-08-01] + p.[2015-08-02]
您可以将其添加到您的动态 SQL,因此对于完整的工作示例:
IF OBJECT_ID(N'tempdb..#T', 'U') IS NOT NULL DROP TABLE #T;
CREATE TABLE #T ([ID] int, [Stud_id] int, [ATT_DATE] datetime, [PRESENT] int);
INSERT INTO #T ([ID], [Stud_id], [ATT_DATE], [PRESENT])
VALUES
(1, 1, '2015-08-01 00:00:00', 1),
(2, 2, '2015-08-01 00:00:00', 0),
(3, 3, '2015-08-01 00:00:00', 1),
(4, 1, '2015-08-02 00:00:00', 0),
(5, 2, '2015-08-02 00:00:00', 1),
(6, 3, '2015-08-02 00:00:00', 1);
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @Columns = (SELECT N', p.' + QUOTENAME(REPLACE(CONVERT(VARCHAR(10), p.Att_Date, 111), '/', '-'))
FROM #T AS p
GROUP BY p.ATT_DATE
ORDER BY p.ATT_DATE
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + ', Total = ' + STUFF(REPLACE(@columns, ', p.[', ' + p.['), 1, 3, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT FROM #T AS p
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;
我有一个动态 PIVOT 查询,其中的列是动态生成的。
我的table:ATTENDANCE_MASTER 包含:ID、Stud_id、ATT_DATE、PRESENT
其中存储的数据如下:
ID Stud_id ATT_DATE PRESENT
1 1 2015-08-1 1
2 2 2015-08-1 0
3 3 2015-08-1 1
4 1 2015-08-2 0
5 2 2015-08-2 1
6 3 2015-08-2 1
我已经创建了 PIVOT 查询
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME(ATT_DATE)
FROM (SELECT p.ATT_DATE FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE) AS x;
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT FROM dbo.ATTENDANCE_MASTER AS p
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;
我需要像
这样的列总和Stud_ID 2015-08-01 2015-08-2 2015-08-3 Total
1 1 0 1 2
2 1 1 1 3
3 1 1 0 2
4 0 0 1 1
请给我建议解决方案。
提前致谢。
您可以添加 GROUP BY WITH CUBE
以获得以下总计:
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @columns = N'';
SELECT @columns += N', p.' + QUOTENAME(ATT_DATE)
FROM (SELECT p.ATT_DATE FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE) AS x;
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT
FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE, p.Stud_id, p.PRESENT
WITH CUBE
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;
首先我建议不要使用变量串联来创建列列表。 It's behaviour is undefined and can be unexpected。而是使用 SQL 服务器的 XML 扩展:
SET @Columns = (SELECT N', p.' + QUOTENAME(p.Att_Date)
FROM dbo.ATTENDANCE_MASTER AS p
GROUP BY p.ATT_DATE
ORDER BY p.ATT_DATE
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
然后您可以简单地使用 @Columns
为总数创建一个表达式,因此使用:
', Total = ' + STUFF(REPLACE(@columns, ', p.[', ' + p.['), 1, 3, '')
你会得到类似的东西:
, Total = p.[2015-08-01] + p.[2015-08-02]
您可以将其添加到您的动态 SQL,因此对于完整的工作示例:
IF OBJECT_ID(N'tempdb..#T', 'U') IS NOT NULL DROP TABLE #T;
CREATE TABLE #T ([ID] int, [Stud_id] int, [ATT_DATE] datetime, [PRESENT] int);
INSERT INTO #T ([ID], [Stud_id], [ATT_DATE], [PRESENT])
VALUES
(1, 1, '2015-08-01 00:00:00', 1),
(2, 2, '2015-08-01 00:00:00', 0),
(3, 3, '2015-08-01 00:00:00', 1),
(4, 1, '2015-08-02 00:00:00', 0),
(5, 2, '2015-08-02 00:00:00', 1),
(6, 3, '2015-08-02 00:00:00', 1);
DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX);
SET @Columns = (SELECT N', p.' + QUOTENAME(REPLACE(CONVERT(VARCHAR(10), p.Att_Date, 111), '/', '-'))
FROM #T AS p
GROUP BY p.ATT_DATE
ORDER BY p.ATT_DATE
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
SET @sql = N'SELECT Stud_id, ' + STUFF(@columns, 1, 2, '') + ', Total = ' + STUFF(REPLACE(@columns, ', p.[', ' + p.['), 1, 3, '') + '
FROM
(
SELECT p.ATT_DATE, p.Stud_id, p.PRESENT FROM #T AS p
) AS j
PIVOT
(
SUM(PRESENT) FOR ATT_DATE IN ('+ STUFF(REPLACE(@columns, ', p.[', ',['), 1, 1, '') + ')
) AS p;';
PRINT @sql;
EXEC sp_executesql @sql;