2012-08-31 14 views
7

मुझे यकीन है कि मुझे यहां कुछ याद आ रहा है।मैं पंक्ति डेटा को कॉलम के रूप में कैसे क्वेरी कर सकता हूं?

मैं इस तरह एक डाटासेट है:

 
FK RowNumber Value Type Status 
1  1   aaaaa A  New 
1  2   bbbbb B  Good 
1  3   ccccc A  Bad 
1  4   ddddd C  Good 
1  5   eeeee B  Good 
2  1   fffff C  Bad 
2  2   ggggg A  New 
2  3   hhhhh C  Bad 
3  1   iiiii A  Good 
3  2   jjjjj A  Good 

मैं शीर्ष 3 परिणामों क्वेरी और उन्हें स्तंभों के रूप में पिवट करने के लिए चाहते हैं, इसलिए अंतिम परिणाम सेट इस तरह दिखता है:

 
FK Value1 Type1 Status1 Value2 Type2 Status2 Value3 Type3 Status3 
1  aaaaa  A  New  bbbbb  B  Good  ccccc  A  Bad 
2  fffff  C  Bad  ggggg  A  New  hhhhh  C  Bad 
3  iiiii  A  Good  jjjjj  A  Good 

मैं SQL सर्वर 2005 में इसे कैसे पूरा कर सकता हूं?

मैं PIVOT का उपयोग करके इसका प्रयास कर रहा हूं, लेकिन मैं अभी भी उस कीवर्ड से बहुत अपरिचित हूं और इसे जिस तरह से चाहता हूं उसे काम नहीं कर सकता।

SELECT * --Id, [1], [2], [3] 
FROM 
(
    SELECT Id, Value, Type, Status 
    , ROW_NUMBER() OVER (PARTITION BY Id ORDER Status, Type) as [RowNumber] 
    FROM MyTable 
) as T 
PIVOT 
(
    -- I know this section doesn't work. I'm still trying to figure out PIVOT 
    MAX(T.Value) FOR RowNumber IN ([1], [2], [3]), 
    MAX(T.Type) FOR RowNumber IN ([1], [2], [3]), 
    MAX(T.Status) FOR RowNumber IN ([1], [2], [3]) 
) AS PivotTable; 

मेरे वास्तविक डेटा सेट में थोड़ा और अधिक इस से जटिल है, और मैं शीर्ष 10 रिकॉर्ड, नहीं शीर्ष 3 की जरूरत है, तो मैं बस हर एक के लिए CASE WHEN RowNumber = X THEN... करने के लिए नहीं करना चाहती।

अद्यतन

मैं सभी प्रश्नों के उत्तर नीचे परीक्षण किया है, और पाया उनमें से ज्यादातर छोटे डेटा सेट में कोई स्पष्ट प्रदर्शन अंतर (3k रिकॉर्ड के आसपास) के साथ एक ही के बारे में लग रहे हैं, लेकिन वहाँ कुछ अंतर जब चल रहा था बड़े डेटा सेट के खिलाफ प्रश्न।

शीर्ष 10 पंक्तियों में 80,000 रिकॉर्ड और 5 कॉलम के लिए पूछताछ के माध्यम से मेरे परीक्षणों के परिणाम यहां दिए गए हैं, इसलिए मेरा अंतिम परिणाम सेट 50 कॉलम + Id कॉलम था। मेरा सुझाव है कि आप यह तय करने के लिए स्वयं का परीक्षण करें कि कौन सा आपके और आपके पर्यावरण के लिए सबसे अच्छा काम करता है।

  • unpivoting और डेटा फिर से पिवट की bluefoot's answer के बारे में 12 सेकंड में सबसे तेजी से औसत है। मुझे यह जवाब भी पसंद आया क्योंकि मुझे इसे पढ़ने और बनाए रखने में सबसे आसान लगता है।

  • Aaron's answer और koderoid's answer दोनों MAX(CASE WHEN RowNumber = X THEN ...) का उपयोग करने का सुझाव देते हैं, और लगभग 13 सेकंड में औसत के पीछे थे।

  • कई PIVOT बयानों का उपयोग करने का Rodney's answer लगभग 16 सेकंड औसतन, हालांकि यह तेजी से कम धुरी बयान (मेरे परीक्षण था 5) के साथ हो सकता है।

  • और Aaron's answer की पहली छमाही है कि एक CTE का उपयोग कर सुझाव और OUTER APPLY धीमी थी। मुझे नहीं पता कि यह कितना समय लगेगा क्योंकि मैंने इसे 2 मिनट के बाद रद्द कर दिया था, और यह लगभग 3k रिकॉर्ड, 3 पंक्तियों और 3 कॉलम के साथ 80k रिकॉर्ड, 10 पंक्तियों और 5 कॉलम के बजाय था।

+1

'ddddd' और' eeeee' साथ पंक्ति का क्या हुआ? – Kermit

+0

वे अंतिम सेट के बाद से मैं केवल शीर्ष एक्स रिकॉर्ड प्राप्त करने में रुचि है परिणाम में शामिल @njk नहीं कर रहे हैं (मेरे उदाहरण में मैं 3 उपयोग कर रहा हूँ, लेकिन मेरी वास्तविक क्वेरी में मैं शीर्ष 10 रिकॉर्ड की जरूरत है) – Rachel

+0

क्या है "शीर्ष 10" चुनने के मानदंड? – Kermit

उत्तर

7

आप एक UNPIVOT और फिर डेटा की एक PIVOT कर सकते हैं। यह या तो स्थिर या गतिशील किया जा सकता है:

स्टेटिक संस्करण:

select * 
from 
(
    select fk, col + cast(rownumber as varchar(1)) new_col, 
    val 
    from 
    (
    select fk, rownumber, value, cast(type as varchar(10)) type, 
     status 
    from yourtable 
) x 
    unpivot 
    (
    val 
    for col in (value, type, status) 
) u 
) x1 
pivot 
(
    max(val) 
    for new_col in 
    ([value1], [type1], [status1], 
    [value2], [type2], [status2], 
    [value3], [type3]) 
) p 

देख SQL Fiddle with demo

गतिशील संस्करण, इस कॉलम की सूची unpivot को pivot को रन-टाइम में मिल जाएगा और उसके बाद:

DECLARE @colsUnpivot AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX), 
    @colsPivot as NVARCHAR(MAX) 

select @colsUnpivot = stuff((select ','+quotename(C.name) 
     from sys.columns as C 
     where C.object_id = object_id('yourtable') and 
       C.name not in ('fk', 'rownumber') 
     for xml path('')), 1, 1, '') 

select @colsPivot = STUFF((SELECT ',' 
         + quotename(c.name 
         + cast(t.rownumber as varchar(10))) 
        from yourtable t 
        cross apply 
         sys.columns as C 
        where C.object_id = object_id('yourtable') and 
         C.name not in ('fk', 'rownumber') 
        group by c.name, t.rownumber 
        order by t.rownumber 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 


set @query 
    = 'select * 
     from 
     (
     select fk, col + cast(rownumber as varchar(10)) new_col, 
      val 
     from 
     (
      select fk, rownumber, value, cast(type as varchar(10)) type, 
      status 
      from yourtable 
     ) x 
     unpivot 
     (
      val 
      for col in ('+ @colsunpivot +') 
     ) u 
    ) x1 
     pivot 
     (
     max(val) 
     for new_col in 
      ('+ @colspivot +') 
    ) p' 

exec(@query) 

SQL Fiddle with Demo

को देखने के

दोनों एक ही परिणाम उत्पन्न करेंगे, हालांकि गतिशील महान है यदि आप समय से पहले कॉलम की संख्या नहीं जानते हैं।

गतिशील संस्करण धारणा है कि पहले से ही rownumber डाटासेट का एक हिस्सा है के तहत काम कर रहा है।

+0

+1 लेकिन 'VARCHAR (1)' 'मूल्य टूट जाएगा 10' रहे मैं अपने परीक्षणों के परिणामों के साथ मेरे सवाल का अद्यतन किया गया। इसके अलावा मुझे टाइप टकराव के बारे में एक त्रुटि मिल रही है (डेमो जिसे आपने टेबल में कॉलम के रूप में देखा है; इसे मुझे लगता है कि रनटाइम पर निर्मित किया जाना चाहिए)। तो मुझे आपके डेमो के बाहर एक कठिन समय परीक्षण हो रहा है। –

+0

@AaronBertrand मैं इस्तेमाल किया 'varchar (1)' एक उदाहरण के बाद से वहाँ केवल 1-5 पंक्ति वर्तमान संख्या थे के रूप में, यह अब मूल्यों के लिए बढ़ाया जा करने की आवश्यकता होगी। मैंने प्रदान किए गए आंकड़ों से मेरा डेमो आधारित किया है, यदि 'राउनम्बर' मौजूद नहीं है तो हां इसे उपयोग से पहले मूल्यांकन करने की आवश्यकता होगी। मैंने यह दिखाया कि डेटासेट को 'unpivot' और फिर' pivot' के माध्यम से दिखाया गया है। – Taryn

+0

यहां और ढेर पर उसने समझाया कि उसे 10 सेट की जरूरत है (उसने नमूना में केवल 3 का उपयोग किया था)। –

7

आप तीन अलग-अलग धुरी बयान में धुरी करने की कोशिश कर सकते हैं। इस आजमाइए करें:

SELECT Id 
    ,MAX(S1) [Status 1] 
    ,MAX(T1) [Type1] 
    ,MAX(V1) [Value1] 
    --, Add other columns 
FROM 
(
    SELECT Id, Value , Type, Status 
    , 'S' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Status_RowNumber] 
    , 'T' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Type_RowNumber] 
    , 'V' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Value_RowNumber] 
    FROM MyTable 
) as T 
PIVOT 
( 
    MAX(Status) FOR Status_RowNumber IN ([S1], [S2], [S3],[S4],[S5],[S6],[S7],[S8],[S9],[S10]) 
)AS StatusPivot 
PIVOT(
    MAX(Type) FOR Type_RowNumber IN ([T1], [T2], [T3],[T4],[T5],[T6],[T7],[T8],[T9],[T10]) 
)AS Type_Pivot 
PIVOT(
    MAX(Value) FOR Value_RowNumber IN ([V1], [V2], [V3],[V4],[V5],[V6],[V7],[V8],[V9],[V10]) 
)AS Value_Pivot 
GROUP BY Id 

मैं शीर्ष दस रिकॉर्ड चयन के लिए मानदंड का पूर्ण क्षेत्र पता नहीं है, लेकिन यह पैदा करता है और उत्पादन है कि आप अपने जवाब के करीब हो सकता है।

SQL Fiddle Example

+3

+1, बहुत चालाक। लेकिन कृपया लंबाई के बिना 'वचरर' का प्रयोग न करें। http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad-habits-to-kick-declaring-varchar-without-length.aspx –

+0

मैं अपने बयान varchar लंबाई शामिल करने के लिए नवीनीकृत किया है। वह एक बहुत उपयोगी लेख था। –

+0

आप row_number प्राप्त करने के लिए एक दूसरी सबक्वायरी का उपयोग करके इसे भी कठिन बना सकते हैं। किसी भी मामले में केवल एक बार मूल्यांकन किया जाना चाहिए, लेकिन यह सुंदर दिखेंगे। :-) –

2

रॉडने की मूली धुरी चालाक है, कि पक्का है।यहां दो अन्य विकल्प दिए गए हैं जो निश्चित रूप से कम आकर्षक होते हैं जब आप 10 एक्स बनाम 3 एक्स क्षेत्र में जाते हैं।

;WITH a AS 
(
    SELECT Id, Value, Type, Status, 
     n = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY [Status], [Type]) 
    FROM dbo.MyTable 
) 
SELECT a.Id, 
Value1 = a.Value, Type1 = a.[Type], Status1 = a.[Status], 
Value2 = b.Value, Type2 = b.[Type], Status2 = b.[Status], 
Value3 = c.Value, Type3 = c.[Type], Status3 = c.[Status] 
FROM a 
OUTER APPLY (SELECT * FROM a AS T2 WHERE n = a.n + 1 AND id = a.id) AS b 
OUTER APPLY (SELECT * FROM a AS T2 WHERE n = b.n + 1 AND id = b.id) AS c 
WHERE a.n = 1 
ORDER BY a.Id; 

- या -

;WITH a AS 
(
    SELECT Id, Value, [Type], [Status], 
     n = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY [Status], [Type]) 
    FROM dbo.MyTable 
) 
SELECT Id, 
    Value1 = MAX(CASE WHEN n = 1 THEN Value END), 
    Type1 = MAX(CASE WHEN n = 1 THEN [Type] END), 
    Status1 = MAX(CASE WHEN n = 1 THEN [Status] END), 
    Value2 = MAX(CASE WHEN n = 2 THEN Value END), 
    Type2 = MAX(CASE WHEN n = 2 THEN [Type] END), 
    Status2 = MAX(CASE WHEN n = 2 THEN [Status] END), 
    Value3 = MAX(CASE WHEN n = 3 THEN Value END), 
    Type3 = MAX(CASE WHEN n = 3 THEN [Type] END), 
    Status3 = MAX(CASE WHEN n = 3 THEN [Status] END) 
FROM a 
GROUP BY Id 
ORDER BY a.Id; 
+0

आपके पहले परिदृश्य में, क्या आप जानते हैं कि प्रत्येक शामिल होने के लिए सीटीई का मूल्यांकन किया जाता है या नहीं? मतलब है कि अगर मैं शीर्ष 10 रिकॉर्ड प्राप्त करने के लिए 10 जोड़ता हूं, तो सीटीई का मूल्यांकन 10 गुना होगा? – Rachel

+0

@ राहेल परीक्षण के बिना जानना असंभव है, क्षमा करें। बहुत सारे चर यह निर्धारित कर सकते हैं कि सीटीई का मूल्यांकन एक से अधिक बार किया जाएगा या नहीं। –

+0

प्रदर्शन के कारण सीटीई के साथ पहली क्वेरी निश्चित रूप से मेरे लिए काम नहीं करने जा रही है, लेकिन दूसरे के पास एक सभ्य रन टाइम है। यदि आप रुचि रखते :) – Rachel

1

यह आप के लिए काम कर सकते हैं, हालांकि यह सुरुचिपूर्ण नहीं है।

इस तरह
select aa.FK_Id 
    , isnull(max(aa.Value1), '') as Value1 
    , isnull(max(aa.Type1), '') as Type1 
    , isnull(max(aa.Status1), '') as Status1 
    , isnull(max(aa.Value2), '') as Value2 
    , isnull(max(aa.Type2), '') as Type2 
    , isnull(max(aa.Status2), '') as Status2 
    , isnull(max(aa.Value3), '') as Value3 
    , isnull(max(aa.Type3), '') as Type3 
    , isnull(max(aa.Status3), '') as Status3 
from 
(  
    select FK_Id 
      , case when RowNumber = 1 then Value else null end as Value1 
      , case when RowNumber = 1 then [Type] else null end as Type1 
      , case when RowNumber = 1 then [Status] else null end as Status1 
      , case when RowNumber = 2 then Value else null end as Value2 
      , case when RowNumber = 2 then [Type] else null end as Type2 
      , case when RowNumber = 2 then [Status] else null end as Status2 
      , case when RowNumber = 3 then Value else null end as Value3 
      , case when RowNumber = 3 then [Type] else null end as Type3 
      , case when RowNumber = 3 then [Status] else null end as Status3 
    from Table1 
) aa 
group by aa.FK_Id 
+0

हाँ यह मेरी बैकअप योजना थी। मुझे शीर्ष 10 रिकॉर्ड्स से 5 कॉलम चुनने की ज़रूरत है, जिसके परिणामस्वरूप 50 केस स्टेटमेंट – Rachel

+0

होते हैं जब आपके पास दोनों समाधान होते हैं, तो कृपया हमें प्रदर्शन के लिए पोस्ट रखें। धन्यवाद :) –

+0

मैंने अपने प्रश्नों के परिणामों के साथ अपना प्रश्न अपडेट किया :) – Rachel

1

कोशिश कुछ:

declare @rowCount int 
set @rowCount = 10 

declare @isNullClause varchar(4024) 
set @isnullClause = '' 
declare @caseClause varchar(4024) 
set @caseClause = '' 

declare @i int 
set @i = 1 

while(@i <= @rowCount) begin 
    set @isnullClause = @isNullClause + 
         ' , max(aa.Value' + CAST(@i as varchar(3)) + ') as Value' + CAST(@i as varchar(3)) + 
         ' , max(aa.Type' + CAST(@i as varchar(3)) + ') as Type' + CAST(@i as varchar(3)) + 
         ' , max(aa.Status' + CAST(@i as varchar(3)) + ') as Status' + CAST(@i as varchar(3)) + ' '; 
    set @caseClause = @caseClause + 
     ' , case when RowNumber = ' + CAST(@i as varchar(3)) + ' then Value else null end as Value' + CAST(@i as varchar(3)) + 
     ' , case when RowNumber = ' + CAST(@i as varchar(3)) + ' then Type else null end as Type' + CAST(@i as varchar(3)) + 
     ' , case when RowNumber = ' + CAST(@i as varchar(3)) + ' then Status else null end as Status' + CAST(@i as varchar(3)) + ' ' 


    set @i = @i + 1; 
end 

declare @sql nvarchar(4000) 
set @sql = 'select aa.FK_Id ' + @isnullClause + ' from (select FK_Id ' 
      + @caseClause + ' from Table1) aa group by aa.FK_Id ' 

exec SP_EXECUTESQL @sql 
+0

+1 केस के निर्माण के गतिशील तरीके प्रदान करने के लिए जब क्वेरी का संस्करण :) – Rachel

संबंधित मुद्दे

 संबंधित मुद्दे