برنامه نویسی

نحوه چرخش داده ها با استفاده از Dynamic SQL در SQL Server

SQL Server PIVOT عملگر زمانی مفید است که همه مقادیری را که باید به ستون تبدیل شوند را بدانید. اما اگر نمی دانید دقیقاً در جدول چیست. چگونه سطرها را به ستون تبدیل کنیم؟

SQL پویا می تواند به آن کمک کند. بیایید آن را در مثال ساده بررسی کنیم. یک میز وجود دارد Goods. تعداد مواد غذایی و فروشگاه ها می تواند نامحدود باشد. اگر همیشه فقط 3 فروشگاه و 3 ماده غذایی داشت، می توانستیم از استاندارد استفاده کنیم PIVOT.

فروشگاه غذا میزان
فروشگاه 1 سیب زمینی 50
فروشگاه 5 سیب زمینی 150
فروشگاه 12 سیب زمینی 300
فروشگاه 1 گوجه فرنگی 220
فروشگاه 5 گوجه فرنگی 180
فروشگاه 12 گوجه فرنگی 60
فروشگاه 1 خیار 500
فروشگاه 5 خیار 10
فروشگاه 12 خیار 90

بنابراین باید مواد غذایی را به ستون تبدیل کنیم. نتیجه باید به این صورت باشد:

فروشگاه سیب زمینی گوجه فرنگی خیار
فروشگاه 1 50 220 500
فروشگاه 5 150 180 10
فروشگاه 12 30 60 90

بیایید یک جدول ایجاد کنیم و داده های خود را وارد کنیم:

CREATE TABLE Goods([Store] VARCHAR(255), [Food] VARCHAR(255), [Amount] INT);

INSERT INTO Goods(Store, Food, Amount)
VALUES
('Store 1', 'potato', 50),
('Store 5', 'potato', 150),
('Store 12', 'potato', 300),
('Store 1', 'tomato', 220),
('Store 5', 'tomato', 180),
('Store 12', 'tomato', 60),
('Store 1', 'cucumber', 500),
('Store 5', 'cucumber', 10),
('Store 12', 'cucumber', 90);

GO
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای محاسبات به دو جدول موقت نیاز داریم:

/*for turning rows into columns*/
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
    DROP TABLE #tmp 
CREATE TABLE #tmp(Store VARCHAR(255), Food VARCHAR(255))
GO
/*for final result*/
IF OBJECT_ID('tempdb..#result') IS NOT NULL
    DROP TABLE #result
GO
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سه متغیر:

DECLARE @sql NVARCHAR(MAX) = '' /*dynamic string*/
        , @columns NVARCHAR(MAX) = STUFF(ISNULL((SELECT DISTINCT ', ['+ Food +'] INT'
                                                FROM Goods
                                                FOR XML PATH('')),''),1,2,'') /*column names for the final result table*/
        , @summary NVARCHAR(MAX) = STUFF(ISNULL((SELECT DISTINCT ', SUM(['+ Food +']) AS ['+ Food +']'
                                                FROM Goods
                                                FOR XML PATH('')),''),1,2,'') /*summing amount*/

SELECT @columns AS [columns], @summary AS [summary];
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

محتوای متغیرها

حالا بیایید اقلام غذایی را به ستون تبدیل کنیم و آن را ایمن کنیم #tmp جدول

INSERT INTO #tmp 
SELECT DISTINCT Store, 
REPLACE(STUFF(ISNULL((SELECT DISTINCT ', 0 AS ['+ Food +']'
            FROM Goods rw
            FOR XML PATH('')),''),1,2,''),'0 AS ['+ Food +']', CAST(org.Amount AS VARCHAR) + ' AS ['+org.Food+']')
FROM Goods org;

SELECT * FROM #tmp;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

#tmp

و اکنون باید از ستون Food خود ستون هایی ایجاد کنیم. برای این منظور از SQL پویا استفاده خواهیم کرد.

--create final table according to number of columns from @columns and insert data from #tmp
SET @sql = N'create table #result(food varchar(255),'+@columns+'); '+CHAR(10)+
            'insert into #result '+CHAR(10);

SELECT @sql = @sql + N'select '''+Store+''' as Store, '+Food+' union all '+CHAR(10) FROM #tmp;

--remove last 'union all'
SET @sql = REVERSE(STUFF(REVERSE(@sql),1,11,''));

SET @sql = @sql + N'select food, '+@summary+' from #result group by food';

EXEC sp_executesql @sql;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه ی sp_executesql رویه خواهد بود

نتیجه نهایی

در صورت نیاز به حفظ آن، می توانید یک جدول اضافی ایجاد کنید و داده ها را در آن وارد کنید. مثلا:

SET @sql = @sql + N'create table final_result(food varchar(255),'+@columns+');'+CHAR(10)+
                    'insert into final_result'+CHAR(10)+
                    'select food, '+@summary+' from #result group by food';

EXEC sp_executesql @sql;

SELECT* FROM final_result;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه نهایی در جدول

همچنین می‌توانید هنگام چرخش داده‌ها، ستون‌های اضافی مانند مقدار کل، تعداد کل در ستون‌ها یا ردیف‌ها اضافه کنید. این یک رویکرد کاملا انعطاف پذیر است.

توجه داشته باشید: اگر نسخه SQL شما بالاتر از 2017 باشد، امکان استفاده وجود دارد STRING_AGG() تابع برای ساده کردن STUFF/XML بیانیه.

لطفاً اگر از روش دیگری استفاده می کنید، در نظرات زیر به من اطلاع دهید. جالب است که چیز جدیدی را امتحان کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا