Вы можете сделать это без поворота (синтаксис, который я нахожу пугающим также).Поскольку вы заранее не знаете фактическое расположение столбцов, я думаю, что это проще всего с динамическим SQL.Для следующей таблицы / примера данных:
USE tempdb;
GO
CREATE TABLE dbo.foo
(
ItemID INT,
MonthAsInt INT,
[Month] VARCHAR(12),
[Year] INT,
InvType VARCHAR(12),
Quantity INT
);
INSERT dbo.foo SELECT 4643,4 ,'April ',2011,'Shipment',10
UNION ALL SELECT 4643,5 ,'May ',2011,'Shipment',10
UNION ALL SELECT 4643,7 ,'July ',2011,'Shipment',10
UNION ALL SELECT 4643,8 ,'August ',2011,'Destroy ',10
UNION ALL SELECT 4643,11,'November',2011,'Shipment',25
UNION ALL SELECT 4643,12,'December',2011,'Picking ',1;
Вы можете сгенерировать список месяцев, используя гораздо более простой CTE, и построить на его основе динамический оператор SQL:
DECLARE @sql NVARCHAR(MAX) = N'';
;WITH n AS
(
SELECT TOP (12) d = DATEADD
(
MONTH,
-(ROW_NUMBER() OVER (ORDER BY [object_id]) - 1),
GETDATE()
)
FROM sys.objects
ORDER BY d DESC
)
SELECT @sql = @sql + N',' + CHAR(13) + CHAR(10) + DATENAME(MONTH, d)
+ ' = SUM(CASE WHEN [Year] = ' + CONVERT(VARCHAR(4), DATEPART(YEAR, d))
+ ' AND MonthAsInt = ' + CONVERT(VARCHAR(2), DATEPART(MONTH, d))
+ ' THEN Quantity ELSE 0 END)'
FROM n
ORDER BY d;
SELECT @sql = N'SELECT InvType' + @sql + '
FROM dbo.foo
GROUP BY InvType';
PRINT @sql;
-- EXEC sp_executesql @sql;
Я положил PRINT
, чтобы вы могли проверить его перед запуском.Я не был уверен, что вам нужно 12 месяцев или 13 месяцев, вы можете просто изменить TOP (12)
на TOP (13)
, если хотите 13 месяцев, или удалить -1
, если вы не хотите, чтобы текущий месяц был включен.