এসকিউএল সার্ভারে 'পিভট' ব্যবহার করে সারিগুলিকে কলামগুলিতে রূপান্তর করুন


279

আমি এমএস পাইভট টেবিলগুলিতে স্টাফটি পড়েছি এবং এখনও এই সঠিক হতে আমার সমস্যা হচ্ছে।

আমার তৈরি একটি টেম্প টেবিল রয়েছে যা আমরা তৈরি করব, আমরা বলব যে কলাম 1 একটি স্টোর নম্বর, এবং কলাম 2 একটি সপ্তাহের সংখ্যা এবং সর্বশেষে কলাম 3 কোনও এক ধরণের মোট। এছাড়াও সপ্তাহের সংখ্যাগুলি গতিশীল, স্টোর নম্বরগুলি স্থির।

Store      Week     xCount
-------    ----     ------
102        1        96
101        1        138
105        1        37
109        1        59
101        2        282
102        2        212
105        2        78
109        2        97
105        3        60
102        3        123
101        3        220
109        3        87

আমি চাই এটি একটি পিভট টেবিল হিসাবে এটি প্রকাশিত হবে:

Store        1          2          3        4        5        6....
----- 
101        138        282        220
102         96        212        123
105         37        
109

শীর্ষে নম্বর এবং পাশের নীচে স্টোর করুন।


উত্তর:


356

আপনি যদি এসকিউএল সার্ভার 2005+ ব্যবহার করে থাকেন তবে PIVOTসারিগুলি থেকে কলামগুলিতে ডেটা রূপান্তর করতে আপনি ফাংশনটি ব্যবহার করতে পারেন ।

দেখে মনে হচ্ছে সপ্তাহগুলি অজানা থাকলে আপনার ডায়নামিক স্কয়ার ব্যবহার করা দরকার তবে প্রাথমিকভাবে হার্ড-কোডেড সংস্করণ ব্যবহার করে সঠিক কোডটি দেখা সহজ।

প্রথমত, ব্যবহারের জন্য এখানে কয়েকটি দ্রুত সারণী সংজ্ঞা এবং ডেটা রয়েছে:

CREATE TABLE #yt 
(
  [Store] int, 
  [Week] int, 
  [xCount] int
);

INSERT INTO #yt
(
  [Store], 
  [Week], [xCount]
)
VALUES
    (102, 1, 96),
    (101, 1, 138),
    (105, 1, 37),
    (109, 1, 59),
    (101, 2, 282),
    (102, 2, 212),
    (105, 2, 78),
    (109, 2, 97),
    (105, 3, 60),
    (102, 3, 123),
    (101, 3, 220),
    (109, 3, 87);

যদি আপনার মানগুলি জানা থাকে তবে আপনি কোয়েরিটিকে কঠোর কোড করবেন:

select *
from 
(
  select store, week, xCount
  from yt
) src
pivot
(
  sum(xcount)
  for week in ([1], [2], [3])
) piv;

এসকিউএল ডেমো দেখুন

তারপরে আপনার যদি গতিশীলভাবে সপ্তাহের নম্বর উত্পন্ন করার দরকার হয় তবে আপনার কোডটি হ'ল:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(Week) 
                    from yt
                    group by Week
                    order by Week
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT store,' + @cols + ' from 
             (
                select store, week, xCount
                from yt
            ) x
            pivot 
            (
                sum(xCount)
                for week in (' + @cols + ')
            ) p '

execute(@query);

এসকিউএল ডেমো দেখুন ।

গতিশীল সংস্করণ, weekসংখ্যার তালিকা তৈরি করে যেগুলি কলামে রূপান্তর করা উচিত। উভয়ই একই ফলাফল দেয়:

| STORE |   1 |   2 |   3 |
---------------------------
|   101 | 138 | 282 | 220 |
|   102 |  96 | 212 | 123 |
|   105 |  37 |  78 |  60 |
|   109 |  59 |  97 |  87 |

4
খুব সুন্দর! কিন্তু কীভাবে কলামটি মুছে ফেলবেন যখন column কলামটির সমস্ত মানগুলি নল হয়?
চিড়িয়াখানা

1
@ZZ নীচের উত্তর দেখুন । ভারব্যাটিম চেষ্টা করে দেখেনি, তবে ধারণাটি দুর্দান্ত।
রাফিন

1
+1 "দেখে মনে হচ্ছে সপ্তাহগুলি অজানা থাকলে আপনার গতিশীল এসকিএল ব্যবহার করা প্রয়োজন তবে প্রাথমিকভাবে হার্ড-সিডিড সংস্করণ ব্যবহার করে সঠিক কোডটি দেখা সহজ" " ক্লিকভিউ জেনেরিক ফাংশন ( সম্প্রদায়ের .qlik.com/blogs/qlikviewdesignblog/2014/03/31/generic ) এর বিপরীতে যা আপনাকে স্পষ্টভাবে আলাদা আলাদা "নাম ____ (())" নাম রাখার প্রয়োজন হয় না
রেড পিটর

1
আপনি যদি আগে সিটি দিয়ে একটি পিভট টেবিল তৈরি করে থাকেন। cte3 AS (select ... )তারপরে আপনার সাথে উপরোক্ত যুক্তি যুক্ত করা আছে @colsএবং @query... এর সাথে একটি ত্রুটি রয়েছে `অবৈধ অবজেক্টের নাম 'cte3' 'আপনি কীভাবে এটি ঠিক করেন। -
এলিজাবেথ

3
এটি দুর্দান্ত - আমি এর আগে কখনও STUFF(...)(বা XML PATHউভয়) ব্যবহার করতাম না । অন্যান্য পাঠকদের সুবিধার জন্য, কলামের নামগুলিতে যোগদান করা এবং শীর্ষস্থানীয় কমাটি কেটে ফেলা হচ্ছে all দ্রষ্টব্য আমি মনে করি যে নিম্নলিখিতগুলি কিছুটা সহজ: @ কলস = (নির্বাচন করুন নির্বাচন কোটইম (সপ্তাহ)) + 'নির্বাচন করুন, yt ক্রম থেকে 1 ফর এক্সএমএল পাঠ (' ')) @ @ কলস = সাবস্ক্রিং (@ কলস, 1, লেন) সেট করুন ( @cols) - 1) ... প্রতিস্থাপন group byদ্বারা distinctএবং order by 1এবং ম্যানুয়ালি একটি চপ suffixed কমা!
দার্থপ্যাবলো

26

এটি # সপ্তাহের গতিশীল জন্য।

এখানে সম্পূর্ণ উদাহরণ: এসকিউএল ডায়নামিক পিভট

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') + QUOTENAME(Week)
FROM (SELECT DISTINCT Week FROM #StoreSales) AS Weeks

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'SELECT Store, ' + @ColumnName + ' 
    FROM #StoreSales
    PIVOT(SUM(xCount) 
          FOR Week IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery

আরে আমার একটা ফ্রিডল রয়েছে যেখানে আমার গতিময় টেবিলগুলি পিভট করা দরকার আপনি কি মনে করেন আপনি এটিতে আমাকে সহায়তা করতে পারেন? dbfiddle.uk/…
সিলি ভলি

@ সিলিভোলি এখানে একটি, আপনি কী পাইভট করতে চান তা নির্দিষ্ট করেননি। এছাড়াও আমি জানি না আপনি পোস্টগ্রিসে
এনকোড

16

সাবকিউরি ব্যবহার করে আগেও আমি একই জিনিস অর্জন করেছি। সুতরাং যদি আপনার আসল টেবিলটিকে স্টোর অ্যাকাউন্টসবিউইক বলা হয়, এবং আপনার কাছে আলাদা আলাদা টেবিল রয়েছে যা স্টোর আইডি তালিকাভুক্ত করেছে, তবে এটি দেখতে এটির মতো হবে:

SELECT StoreID, 
    Week1=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=1),
    Week2=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=2),
    Week3=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=3)
FROM Store
ORDER BY StoreID

এই পদ্ধতির একটি সুবিধা হ'ল বাক্য গঠনটি আরও পরিষ্কার এবং ফলাফলগুলি অন্য ক্ষেত্রগুলিকেও টানতে অন্য টেবিলগুলিতে যোগদান করা সহজ করে তোলে।

আমার উপাখ্যানের ফলাফলগুলি হ'ল এই ক্যোয়ারীটি কয়েক হাজার সারিতে এক সেকেন্ডেরও কম সময়ে সম্পন্ন হয়েছে এবং আমার কাছে 7 টি সাবকিউরিয়াস রয়েছে। তবে মন্তব্যে উল্লিখিত হিসাবে, এটি এইভাবে করা আরও বেশি গণনামূলক ব্যয়বহুল, সুতরাং আপনি যদি বিপুল পরিমাণে ডেটা চালানোর আশা করেন তবে এই পদ্ধতিটি ব্যবহার সম্পর্কে সতর্কতা অবলম্বন করুন।


8
এটি সহজ, তবে এটি একটি খুব ব্যয়বহুল ক্রিয়াকলাপ, এই সারকোরিগুলি টেবিল থেকে ফিরে আসা প্রতিটি সারির জন্য একবার সম্পাদন করতে হবে।
গ্রেগ


5

আমি একটি এসপি লিখছি যা এই উদ্দেশ্যে কার্যকর হতে পারে, মূলত এই এসপিটি যেকোন টেবিলকে পাইভট করে এবং একটি নতুন টেবিলকে পাইভোটেড করে দেয় বা কেবল ডেটা সেট করে দেয়, এটি কার্যকর করার উপায়:

Exec dbo.rs_pivot_table @schema=dbo,@table=table_name,@column=column_to_pivot,@agg='sum([column_to_agg]),avg([another_column_to_agg]),',
        @sel_cols='column_to_select1,column_to_select2,column_to_select1',@new_table=returned_table_pivoted;

দয়া করে নোট করুন যে @agg পরামিতিতে কলামের নামগুলি অবশ্যই থাকা উচিত '['এবং প্যারামিটারটি একটি কমা দিয়ে শেষ হওয়া উচিত','

এসপি

Create Procedure [dbo].[rs_pivot_table]
    @schema sysname=dbo,
    @table sysname,
    @column sysname,
    @agg nvarchar(max),
    @sel_cols varchar(max),
    @new_table sysname,
    @add_to_col_name sysname=null
As
--Exec dbo.rs_pivot_table dbo,##TEMPORAL1,tip_liq,'sum([val_liq]),sum([can_liq]),','cod_emp,cod_con,tip_liq',##TEMPORAL1PVT,'hola';
Begin

    Declare @query varchar(max)='';
    Declare @aggDet varchar(100);
    Declare @opp_agg varchar(5);
    Declare @col_agg varchar(100);
    Declare @pivot_col sysname;
    Declare @query_col_pvt varchar(max)='';
    Declare @full_query_pivot varchar(max)='';
    Declare @ind_tmpTbl int; --Indicador de tabla temporal 1=tabla temporal global 0=Tabla fisica

    Create Table #pvt_column(
        pivot_col varchar(100)
    );

    Declare @column_agg table(
        opp_agg varchar(5),
        col_agg varchar(100)
    );

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@table) AND type in (N'U'))
        Set @ind_tmpTbl=0;
    ELSE IF OBJECT_ID('tempdb..'+ltrim(rtrim(@table))) IS NOT NULL
        Set @ind_tmpTbl=1;

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@new_table) AND type in (N'U')) OR 
        OBJECT_ID('tempdb..'+ltrim(rtrim(@new_table))) IS NOT NULL
    Begin
        Set @query='DROP TABLE '+@new_table+'';
        Exec (@query);
    End;

    Select @query='Select distinct '+@column+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)+@schema+'.'+@table+' where '+@column+' is not null;';
    Print @query;

    Insert into #pvt_column(pivot_col)
    Exec (@query)

    While charindex(',',@agg,1)>0
    Begin
        Select @aggDet=Substring(@agg,1,charindex(',',@agg,1)-1);

        Insert Into @column_agg(opp_agg,col_agg)
        Values(substring(@aggDet,1,charindex('(',@aggDet,1)-1),ltrim(rtrim(replace(substring(@aggDet,charindex('[',@aggDet,1),charindex(']',@aggDet,1)-4),')',''))));

        Set @agg=Substring(@agg,charindex(',',@agg,1)+1,len(@agg))

    End

    Declare cur_agg cursor read_only forward_only local static for
    Select 
        opp_agg,col_agg
    from @column_agg;

    Open cur_agg;

    Fetch Next From cur_agg
    Into @opp_agg,@col_agg;

    While @@fetch_status=0
    Begin

        Declare cur_col cursor read_only forward_only local static for
        Select 
            pivot_col 
        From #pvt_column;

        Open cur_col;

        Fetch Next From cur_col
        Into @pivot_col;

        While @@fetch_status=0
        Begin

            Select @query_col_pvt='isnull('+@opp_agg+'(case when '+@column+'='+quotename(@pivot_col,char(39))+' then '+@col_agg+
            ' else null end),0) as ['+lower(Replace(Replace(@opp_agg+'_'+convert(varchar(100),@pivot_col)+'_'+replace(replace(@col_agg,'[',''),']',''),' ',''),'&',''))+
                (case when @add_to_col_name is null then space(0) else '_'+isnull(ltrim(rtrim(@add_to_col_name)),'') end)+']'
            print @query_col_pvt
            Select @full_query_pivot=@full_query_pivot+@query_col_pvt+', '

            --print @full_query_pivot

            Fetch Next From cur_col
            Into @pivot_col;        

        End     

        Close cur_col;
        Deallocate cur_col;

        Fetch Next From cur_agg
        Into @opp_agg,@col_agg; 
    End

    Close cur_agg;
    Deallocate cur_agg;

    Select @full_query_pivot=substring(@full_query_pivot,1,len(@full_query_pivot)-1);

    Select @query='Select '+@sel_cols+','+@full_query_pivot+' into '+@new_table+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)+
    @schema+'.'+@table+' Group by '+@sel_cols+';';

    print @query;
    Exec (@query);

End;
GO

এটি কার্যকর করার উদাহরণ:

Exec dbo.rs_pivot_table @schema=dbo,@table=##TEMPORAL1,@column=tip_liq,@agg='sum([val_liq]),avg([can_liq]),',@sel_cols='cod_emp,cod_con,tip_liq',@new_table=##TEMPORAL1PVT;

তাহলে Select * From ##TEMPORAL1PVTফিরে আসবে:

এখানে চিত্র বর্ণনা লিখুন



2

উপরে @ টায়ার্ন উত্তরের একটি সংশোধনী এখানে দেওয়া হয়েছে যা আপনাকে পাইভোটিংটি আরও সহজ করে তুলতে সহায়তা করতে পারে:

এটি করার সর্বোত্তম উপায় এটি নাও হতে পারে তবে টেবিলগুলিকে পিভট করার পদ্ধতিতে এটি আমার মাথাটি জড়িয়ে রাখতে সহায়তা করে।

আইডি = সারি আপনি পিভট করতে চান

MY_KEY = আপনি যে কলামটি পিভট করতে চান সেই কলামের নামগুলি আপনার মূল সারণী থেকে নির্বাচন করছেন।

VAL = আপনি প্রতিটি কলামের আওতায় ফিরে আসতে চান এমন মান।

MAX (VAL) => অন্যান্য সমষ্টিগত ফাংশনগুলির সাথে প্রতিস্থাপন করা যেতে পারে। সুম (ভ্যাল), এমআইএন (ভ্যাল), ইত্যাদি ...

DECLARE @cols AS NVARCHAR(MAX),
@query  AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(MY_KEY) 
                from yt
                group by MY_KEY
                order by MY_KEY ASC
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')
set @query = 'SELECT ID,' + @cols + ' from 
         (
            select ID, MY_KEY, VAL 
            from yt
        ) x
        pivot 
        (
            sum(VAL)
            for MY_KEY in (' + @cols + ')
        ) p '

        execute(@query);

2

অন্যান্য ডাটাবেসগুলি কীভাবে এই সমস্যার সমাধান করে তা কেবল আপনাকে কিছু ধারণা দিন। DolphinDBপিভোটিংয়ের জন্য অন্তর্নির্মিত সমর্থনও রয়েছে এবং এসকিউএল দেখতে অনেক বেশি স্বজ্ঞাত এবং ঝরঝরে দেখাচ্ছে। এটি মূল কলাম ( Store), পিভোটিং কলাম ( Week) এবং গণনা করা মেট্রিক ( sum(xCount)) নির্দিষ্ট করার মতোই সহজ ।

//prepare a 10-million-row table
n=10000000
t=table(rand(100, n) + 1 as Store, rand(54, n) + 1 as Week, rand(100, n) + 1 as xCount)

//use pivot clause to generate a pivoted table pivot_t
pivot_t = select sum(xCount) from t pivot by Store, Week

ডলফিনডিবি একটি কলামার উচ্চ কার্যকারিতা ডাটাবেস। ডেমোতে গণনাটি একটি ডেল এক্সপিএস ল্যাপটপে (i7 সিপিইউ) কম 546 এমএসের মতো ব্যয় করে। আরও বিশদ পেতে, দয়া করে অনলাইন ডলফিনডিবি ম্যানুয়াল https://www.dolphindb.com/help/index.html?pivotby.html দেখুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.