PIVOT JA UNPIVOT

Pivot tekitab tavalisest tabelist kahemõõtmelise risttabeli. Unpivot teeb täpselt vastupidist.

Püüame tekitada risttabeli, milles oleks ridades laste sünnilinn ning veergudes sünniaastad ning andmetena laste keskmised pikkused:

SELECT *
FROM
	( SELECT SynniAasta, SynniLinn, Pikkus 
	  FROM dbo.Laps_tbl ) AS data
PIVOT (
	AVG (Pikkus)
	FOR Synniaasta IN ([1995], [1996], [1997])
) AS piv

Vastupidise teisenduse saame korraldada UNPIVOT käsuga. Selleks salvestan eelnevalt eelmise pärinu tulemuse ajutisse tabelisse kasutades SELECT … INTO #ristt … konstruktsiooni, ehk siis

SELECT * INTO #ristt
FROM
	( SELECT SynniAasta, SynniLinn, Pikkus 
	  FROM dbo.Laps_tbl ) AS data
PIVOT (
	AVG (Pikkus)
	FOR Synniaasta IN ([1995], [1996], [1997])
) AS piv

Iseenesest õnnestus ka varem moodustada analoogseid konstruktsioone, kasutades CASE valikuid SELECT loetelus. PIVOT on muutnud selle protsessi oluliselt lihtsamaks kuid risttabelisse minevad väljanimed (veerud) tuleb endiselt sisse trükkida ning neid pole võimalik tekitada dünaamiliselt.

Lahenduseks on sellele dünaamiline SQLi koostamine ning käivitamine EXEC abil.

Selleks tuleb luua skript, mis tekitab komadega eraldatud loetelu kõigist risttabelisse minevatest väljadest ning kleepida see SQLis õige koha peale.

Kuna kasutame SQL 2005 siis teeksin selle tegevuse kasutades CTE abi:

DECLARE @aastad AS VARCHAR(MAX);
WITH AastaCTE
AS 
(
	SELECT DISTINCT SynniAasta AS Aasta FROM dbo.Laps_tbl
)
SELECT @aastad = ISNULL(@aastad + ',[', '[') + 
CAST(Aasta AS CHAR(4)) + ']'
FROM AastaCTE
ORDER BY Aasta
DECLARE @sql NVARCHAR(max)
SET @sql = N'SELECT * 
	FROM ( SELECT Pikkus, SynniAasta, SynniLinn 
		 FROM dbo.Laps_tbl ) AS Lapsed
	PIVOT ( AVG(Pikkus) FOR SynniAasta IN(' + @aastad + N')) AS Piv'
EXEC (@sql)