Wiem, że to pytanie jest starsze, ale szukałem odpowiedzi i pomyślałem, że mogę rozwinąć „dynamiczną” część problemu i być może komuś pomóc.
Przede wszystkim zbudowałem to rozwiązanie, aby rozwiązać problem, który miał kilku współpracowników z niestabilnymi i dużymi zestawami danych, które należy szybko przestawić.
To rozwiązanie wymaga utworzenia procedury składowanej, więc jeśli nie ma takiej potrzeby, proszę przestań czytać.
Ta procedura będzie obejmować kluczowe zmienne instrukcji przestawnej, aby dynamicznie tworzyć instrukcje przestawne dla różnych tabel, nazw kolumn i agregatów. Kolumna statyczna jest używana jako kolumna grupowania według / tożsamości dla elementu przestawnego (można go usunąć z kodu, jeśli nie jest to konieczne, ale jest dość powszechne w instrukcjach przestawnych i było konieczne do rozwiązania pierwotnego problemu), kolumna przestawna to miejsce, w którym końcowe kolumny wynikowe zostaną wygenerowane, a kolumna wartości jest tym, do czego agregat zostanie zastosowany. Parametr Table to nazwa tabeli zawierającej schemat (schema.tablename), w tej części kodu można by użyć trochę miłości, ponieważ nie jest ona tak czysta, jak bym tego chciał. Działa to dla mnie, ponieważ moje użycie nie było publicznie dostępne, a zastrzyk SQL nie był problemem.
Zacznijmy od kodu, aby utworzyć procedurę składowaną. Ten kod powinien działać we wszystkich wersjach SSMS 2005 i nowszych, ale nie testowałem go w 2005 ani 2016 roku, ale nie rozumiem, dlaczego to nie działa.
create PROCEDURE [dbo].[USP_DYNAMIC_PIVOT]
(
@STATIC_COLUMN VARCHAR(255),
@PIVOT_COLUMN VARCHAR(255),
@VALUE_COLUMN VARCHAR(255),
@TABLE VARCHAR(255),
@AGGREGATE VARCHAR(20) = null
)
AS
BEGIN
SET NOCOUNT ON;
declare @AVAIABLE_TO_PIVOT NVARCHAR(MAX),
@SQLSTRING NVARCHAR(MAX),
@PIVOT_SQL_STRING NVARCHAR(MAX),
@TEMPVARCOLUMNS NVARCHAR(MAX),
@TABLESQL NVARCHAR(MAX)
if isnull(@AGGREGATE,'') = ''
begin
SET @AGGREGATE = 'MAX'
end
SET @PIVOT_SQL_STRING = 'SELECT top 1 STUFF((SELECT distinct '', '' + CAST(''[''+CONVERT(VARCHAR,'+ @PIVOT_COLUMN+')+'']'' AS VARCHAR(50)) [text()]
FROM '+@TABLE+'
WHERE ISNULL('+@PIVOT_COLUMN+','''') <> ''''
FOR XML PATH(''''), TYPE)
.value(''.'',''NVARCHAR(MAX)''),1,2,'' '') as PIVOT_VALUES
from '+@TABLE+' ma
ORDER BY ' + @PIVOT_COLUMN + ''
declare @TAB AS TABLE(COL NVARCHAR(MAX) )
INSERT INTO @TAB EXEC SP_EXECUTESQL @PIVOT_SQL_STRING, @AVAIABLE_TO_PIVOT
SET @AVAIABLE_TO_PIVOT = (SELECT * FROM @TAB)
SET @TEMPVARCOLUMNS = (SELECT replace(@AVAIABLE_TO_PIVOT,',',' nvarchar(255) null,') + ' nvarchar(255) null')
SET @SQLSTRING = 'DECLARE @RETURN_TABLE TABLE ('+@STATIC_COLUMN+' NVARCHAR(255) NULL,'+@TEMPVARCOLUMNS+')
INSERT INTO @RETURN_TABLE('+@STATIC_COLUMN+','+@AVAIABLE_TO_PIVOT+')
select * from (
SELECT ' + @STATIC_COLUMN + ' , ' + @PIVOT_COLUMN + ', ' + @VALUE_COLUMN + ' FROM '+@TABLE+' ) a
PIVOT
(
'+@AGGREGATE+'('+@VALUE_COLUMN+')
FOR '+@PIVOT_COLUMN+' IN ('+@AVAIABLE_TO_PIVOT+')
) piv
SELECT * FROM @RETURN_TABLE'
EXEC SP_EXECUTESQL @SQLSTRING
END
Następnie przygotujemy nasze dane do przykładu. Wziąłem przykład danych z zaakceptowanej odpowiedzi, dodając kilka elementów danych do wykorzystania w tym dowodzie koncepcji, aby pokazać różne wyniki łącznej zmiany.
create table temp
(
date datetime,
category varchar(3),
amount money
)
insert into temp values ('1/1/2012', 'ABC', 1000.00)
insert into temp values ('1/1/2012', 'ABC', 2000.00) -- added
insert into temp values ('2/1/2012', 'DEF', 500.00)
insert into temp values ('2/1/2012', 'DEF', 1500.00) -- added
insert into temp values ('2/1/2012', 'GHI', 800.00)
insert into temp values ('2/10/2012', 'DEF', 700.00)
insert into temp values ('2/10/2012', 'DEF', 800.00) -- addded
insert into temp values ('3/1/2012', 'ABC', 1100.00)
Poniższe przykłady pokazują zróżnicowane instrukcje wykonania, pokazujące różne agregaty jako prosty przykład. Nie zdecydowałem się zmienić kolumny statycznej, przestawnej i wartościowej, aby zachować prosty przykład. Powinieneś być w stanie po prostu skopiować i wkleić kod, aby samemu z nim zadzierać
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','sum'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','max'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','avg'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','min'
To wykonanie zwraca odpowiednio następujące zestawy danych.