unpivoting data تکنیکی کاربردی و قابل استفاده برای نرمال سازی کردن (normalizing) جداول غیر نرمال (denormalized table) است.
هیچ چیزی بهتر از مثال نمی تواند مفاهیم را تفهیم کند. فرض کنید آمار تعداد پست های برخی از کاربران را در یک تالار گفتمان (forum) مشخص در سه ماه فروردین، اردیبهشت و خرداد سال 89 را می خواهیم در جدول ذخیره کنیم. داده ها به شکل before در جدول ذخیره شده اند و ما می خواهیم با query گرفتن از جدول before نتیجه ی after را بدست آوریم.
--============== before =====================
/*
user_name Farvardin Ordibehesht Khordad
--------------- --------- ----------- -------
user_1 50 150 250
user_2 200 300 1200
user_3 0 0 900
*/
--============== after =====================
/*
user_name Month posts
--------------- ----------- --------------
user_1 Farvardin 50
user_1 Ordibehesht 150
user_1 Khordad 250
user_2 Farvardin 200
user_2 Ordibehesht 300
user_2 Khordad 1200
user_3 Farvardin 0
user_3 Ordibehesht 0
user_3 Khordad 900
*/
برای بدست آوردن این نتیجه از روشهای استاندارد زبان SQL دو روش شناخته شده وجود دارند. یکی استفاده از چندین union all و دیگری استفاده از جدول اعداد یا کپی کردن داده ها به تعداد ستون هایی که باید به سطر چرخش پیدا کنند. اگر هم از SQL Server 2005 و بالاتر استفاده می کنید می توانید از UNPIVOT برای حل این مساله استفاده کنید.
روش های مذکور به قرار زیر هستند:
--Declare Sample Table
DECLARE @sample TABLE
([user_name] varchar(15) NOT NULL UNIQUE,
[Farvardin] tinyint NOT NULL DEFAULT(0),
[Ordibehesht] tinyint NOT NULL DEFAULT(0),
[Khordad] tinyint NOT NULL DEFAULT(0)) ;
--insert sample data
INSERT INTO @sample
VALUES ('user_1', 50, 150, 250),
('user_2', 200, 300, 1200),
('user_3', 0, 0, 900) ;
--using number table method
SELECT [user_name], D.i AS [Month],
CASE D.i WHEN 'Farvardin' THEN [Farvardin]
WHEN 'Ordibehesht' THEN [Ordibehesht]
WHEN 'Khordad' THEN [Khordad]
END AS posts
FROM @sample
CROSS JOIN
(SELECT 'Farvardin' UNION ALL
SELECT 'Ordibehesht' UNION ALL
SELECT 'Khordad') D(i)
--using union all
SELECT [user_name], 'Farvardin' AS [Month], [Farvardin] AS [posts]
FROM @sample
UNION ALL
SELECT [user_name], 'Ordibehesht', [Ordibehesht]
FROM @sample
UNION ALL
SELECT [USER_NAME], 'Khordad', [Khordad]
FROM @sample ;
--using UNPIVOT
SELECT *
FROM @sample
UNPIVOT ([post] FOR [Month]
IN (farvardin, ordibehesht, khordad)) AS U