कई पंक्तियों में धुरी पंक्तियाँ


21

मेरे पास एक SQL सर्वर इंस्टेंस है जिसमें एक Oracle सर्वर से जुड़ा सर्वर है। Oracle सर्वर पर एक तालिका होती है जिसे PersonOptionsनिम्नलिखित डेटा कहा जाता है :

╔══════════╦══════════╗
║ PersonID ║ OptionID ║
╠══════════╬══════════╣
║        1 ║ A        ║
║        1 ║ B        ║
║        2 ║ C        ║
║        3 ║ B        ║
║        4 ║ A        ║
║        4 ║ C        ║
╚══════════╩══════════╝

मुझे उस डेटा को पिवट करने की आवश्यकता है ताकि परिणाम हो:

╔══════════╦═════════╦══════════╦══════════╗
║ PersonID ║ OptionA ║ Option B ║ Option C ║
╠══════════╬═════════╬══════════╬══════════╣
║        1 ║       1 ║        1 ║          ║
║        2 ║         ║          ║        1 ║
║        3 ║         ║        1 ║          ║
║        4 ║       1 ║          ║        1 ║
╚══════════╩═════════╩══════════╩══════════╝

कोई सुझाव?

जवाबों:


20

कुछ तरीके हैं जिनसे आप इस डेटा परिवर्तन को कर सकते हैं। आपके पास PIVOTफ़ंक्शन तक पहुंच है, तो यह सबसे आसान होगा, लेकिन यदि नहीं तो आप एक कुल फ़ंक्शन और ए का उपयोग कर सकते हैं CASE

एग्रीगेट / केस संस्करण:

select personid,
  max(case when optionid = 'A' then 1 else 0 end) OptionA,
  max(case when optionid = 'B' then 1 else 0 end) OptionB,
  max(case when optionid = 'C' then 1 else 0 end) OptionC
from PersonOptions
group by personid
order by personid;

SQL फिडेल को डेमो के साथ देखें

स्थैतिक धुरी:

select *
from
(
  select personid, optionid
  from PersonOptions
) src
pivot
(
  count(optionid)
  for optionid in ('A' as OptionA, 'B' OptionB, 'C' OptionC)
) piv
order by personid

SQL फिडेल को डेमो के साथ देखें

गतिशील संस्करण:

उपरोक्त दो संस्करण बहुत काम करते हैं यदि आपके पास ज्ञात मूल्यों की संख्या है, लेकिन यदि आपके मूल्य अज्ञात हैं, तो आप गतिशील sql को लागू करना चाहेंगे और Oracle में आप एक प्रक्रिया का उपयोग कर सकते हैं:

CREATE OR REPLACE procedure dynamic_pivot_po(p_cursor in out sys_refcursor)
as
    sql_query varchar2(1000) := 'select personid ';

    begin
        for x in (select distinct OptionID from PersonOptions order by 1)
        loop
            sql_query := sql_query ||
                ' , min(case when OptionID = '''||x.OptionID||''' then 1 else null end) as Option_'||x.OptionID;

                dbms_output.put_line(sql_query);
        end loop;

        sql_query := sql_query || ' from PersonOptions group by personid order by personid';
        dbms_output.put_line(sql_query);

        open p_cursor for sql_query;
    end;
/

फिर आप परिणाम लौटाते हैं, आप उपयोग करेंगे:

variable x refcursor
exec dynamic_pivot_po(:x)
print x

परिणाम सभी संस्करणों के साथ समान हैं:

| PERSONID | OPTIONA | OPTIONB | OPTIONC |
------------------------------------------
|        1 |       1 |       1 |       0 |
|        2 |       0 |       0 |       1 |
|        3 |       0 |       1 |       0 |
|        4 |       1 |       0 |       1 |

हालाँकि स्टेटिक पिवट समाधान मानता है कि केवल तीन विकल्प हैं। यदि आपके पास संभावित असीमित संख्या में विकल्प हैं तो क्या होगा? उदाहरण के लिए ABCDEFGHIJK? क्या नियमित एसक्यूएल के साथ धुरी को गतिशील बनाने का कोई तरीका नहीं है? क्या कॉलम हेडर बनाने के बजाय, क्या हम उन्हें कॉलम में रख सकते हैं? तो यह इस तरह दिखेगा: | PERSONID | कॉलम 2 | कॉलम 3 | कॉलम 4 | ------------------------------------------ | 1 | ए | B | नल | | 2 | सी | नल | नल | | 3 | नल | सी | नल |
मैथ्यू

1
@ मैथ्यू आपको डायनामिक Sql का उपयोग करना होगा क्योंकि मैं उत्तर के अंतिम भाग में प्रदर्शित करता हूं।
टरिन

शीघ्र जवाब देने के लिए ध्न्यवाद! मैं वास्तव में एक नया कॉलम बनाकर करता हूं, और कॉमा द्वारा अलग किए गए सभी विकल्पों को भरता हूं। एक ही तालिकाओं से चयन करने वाले उपकुंजी से कॉल उत्पन्न होता है where a.personId = a2.personId order by a2.personId for xml path('')। a2 उप-तालिका में तालिका है। तब मैं एक्सेल में टेक्स्ट को कॉलम के साथ सीमांकक के रूप में सीमांकक के रूप में डेटा को अलग करता हूं। मैं एक प्रक्रिया लिखने के बिना नियमित एसक्यूएल में ऐसा करने का एक तरीका खोजने की उम्मीद कर रहा था, लेकिन शायद कोई रास्ता नहीं है। फिलहाल दौड़ना है लेकिन बेहतर तरीके से समझाने के लिए मैं इसका एक उदाहरण पोस्ट करने की कोशिश करूंगा।
मैथ्यू

9

यह SQL सर्वर सिंटैक्स में समतुल्य होगा। Oracle डॉक्स के मेरे पढ़ने के आधार पर, NULLIF और PIVOT को अपने SQL सर्वर परिजन के समान प्रारूप दिखाई देते हैं। चुनौती धुरी सूची होगी जिसे तब तक स्थिर रहने की आवश्यकता है जब तक आप क्वेरी को गतिशील नहीं बनाते हैं क्योंकि इट्ज़िक प्रदर्शित करता है लेकिन मुझे पता नहीं है कि क्या इसका अनुवाद पी / एसक्यूएल में किया जा सकता है।

WITH PersonOptions(PersonID, OptionId) AS
(
    SELECT 1, 'A'
    UNION ALL SELECT 1, 'B'
    UNION ALL SELECT 2, 'C'
    UNION ALL SELECT 3, 'B'
    UNION ALL SELECT 4, 'A'
    UNION ALL SELECT 4, 'C'
)
SELECT
    P.PersonId
,   NULLIF(P.A, 0) AS OptionA
,   NULLIF(P.B, 0) AS OptionB
,   NULLIF(P.C, 0) AS OptionC
FROM
    PersonOptions  PO
    PIVOT 
    (
        COUNT(PO.OptionId)
        FOR OPtionId IN (A, B, C)
    )  P;

5

मैं मैन्युअल रूप से क्वेरी को पिवट करना पसंद करता हूं, लेकिन आप इसका उपयोग भी कर सकते हैं PIVOT

SELECT PersonID,
MAX(CASE WHEN OptionId ='A' THEN 1 END) AS OptionA,
MAX(CASE WHEN OptionId ='B' THEN 1 END) AS OptionB, 
MAX(CASE WHEN OptionId ='C' THEN 1 END) AS OptionC
FROM PersonOptions
GROUP BY PersonID

1
बेझिझक इस एक को थोड़ा और समझाएं। धुरी क्या प्रदान करती है जो अन्य नहीं कर सकते हैं? और वह कब टूटता है? याद रखें कि आप पोस्टरिटी के लिए जवाब दे रहे हैं, न कि विशिष्ट डोमेन विशेषज्ञता वाले किसी व्यक्ति के लिए जो आप जानते हैं।
jcolebrand

2
@jcolebrand: यह व्यक्तिगत प्राथमिकता के बारे में अधिक है - मैं खुद सोचता हूं कि PIVOTमेरे द्वारा उपयोग किए जाने वाले दृष्टिकोण की तुलना में वाक्य रचना अधिक जटिल है। हालाँकि, मुझे पता है कि दोनों एक ही परिणाम देते हैं, और मैं मानता हूं कि अन्य लोग इसके विपरीत सोच सकते हैं।
a1ex07

1
संकेत: संपादन बटन का उपयोग करें ;-) ~ हम एक कोड-जवाब प्रतिक्रिया से अधिक प्रोत्साहित करना पसंद करते हैं ।
jcolebrand
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.