используя 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
для Total
, и у вас есть общая строка (ы).
Я бы также advise against variable concatenation (SELECT @Columnname = @ColumnName + SomeField FROM SomeTable
) так как результаты не гарантируются. Вместо этого используйте XML extensions to concatenate your rows to columns.
Кроме того, я хотел бы использовать параметризованный запрос, так что вместо:
DECLARE @Variable VARCHAR(10) = 'TEST';
SET @DynamicPivotQuery = 'SELECT * FROM T WHERE Column = ''' + @Variable + '''';
EXECUTE sp_executesql @DynamicPivotQuery;
Вместо этого используйте:
DECLARE @Variable VARCHAR(10) = 'TEST';
SET @DynamicPivotQuery = 'SELECT * FROM T WHERE Column = @Param';
EXECUTE sp_executesql @DynamicPivotQuery, N'@Param VARCHAR(10)', @Param = @Variable;
Это дает вам правильно типизированные параметры, поэтому нет необходимости конвертировать ваши дат в varchars, чтобы добавить их в ваш запрос, только для вашего запроса, чтобы преобразовать их обратно в даты, когда он выполняется.
Наконец, я не исправили, но я бы рекомендовал agaainst с помощью BETWEEN
при работе с датами, причины этого суммируются красиво в следующих статьях:
Который дает окончательный запрос о: '
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;
N.B.Я не тестировал это полностью, так как для этого потребовалось бы создать 4 таблицы, о которых я могу только догадываться в данных, но есть надежда, что в ответе и ссылках будет достаточно информации, чтобы получить вас на правильном пути, если есть некоторые незначительные синтаксические ошибки
ПОЛНЫЙ РАБОЧИЙ ПРИМЕР
IF OBJECT_ID(N'tempdb..#T', 'U') IS NOT NULL DROP TABLE #T;
CREATE TABLE #T
(
[Date] DATE,
Business VARCHAR(50),
Value INT,
Name VARCHAR(50)
);
INSERT #T (Date, Business, Value, Name)
VALUES
('20150601', 'EUR', 1, 'Group 1'),
('20150605', 'EUR', 12, 'Group 2'),
('20150605', 'EUR', 3, 'Group 3'),
('20150701', 'EUR', 2, 'Group 1'),
('20150708', 'EUR', 2, 'Group 2'),
('20150702', 'EUR', 7, 'Group 3'),
('20150703', 'AAA', 2, 'Group 1');
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
SET @ColumnName =
STUFF((SELECT ',' + QUOTENAME(CONVERT(VARCHAR(10), D.[Date], 120))
FROM ( SELECT [Date] = DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0)
FROM #T
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(bb.name, ''Total'') AS Name
FROM #T AS bb
WHERE bb.date BETWEEN @StartParam AND @EndParam
AND bb.Business = @BusinessParam
GROUP BY GROUPING SETS ((bb.date, bb.name), (bb.Date))
) 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;
Союз новое имя столбца с суммы каждого столбца. вам нужно использовать временную таблицу для этого – bmsqldev
Получить динамический запрос для записи в временную таблицу. Выберите из таблицы temp, объедините другой запрос, который выполняет суммирование. Конечно, это было бы намного проще (чище и эффективнее) в коде приложения. – user5151179
Это должно быть сделано инструментом отчетности, а не SQL. Все инструменты отчетности позволяют добавлять заголовки/нижние колонтитулы групп –