MySQL - कॉलम के लिए पंक्तियाँ


187

मैंने पोस्ट खोजने की कोशिश की, लेकिन मुझे केवल SQL सर्वर / एक्सेस के लिए समाधान मिला। मुझे MySQL (5.X) में एक समाधान की आवश्यकता है।

मेरे पास 3 कॉलम के साथ एक टेबल (जिसे इतिहास कहा जाता है) है: होस्टिड, आइटमनाम, आइटमवॉल।
यदि मैं एक चयन ( select * from history) करता हूं , तो यह वापस आ जाएगा

   +--------+----------+-----------+
   | hostid | itemname | itemvalue |
   +--------+----------+-----------+
   |   1    |    A     |    10     |
   +--------+----------+-----------+
   |   1    |    B     |     3     |
   +--------+----------+-----------+
   |   2    |    A     |     9     |
   +--------+----------+-----------+
   |   2    |    c     |    40     |
   +--------+----------+-----------+

मैं डेटाबेस को कैसे क्वेरी करूँ जैसे कुछ वापस करने के लिए

   +--------+------+-----+-----+
   | hostid |   A  |  B  |  C  |
   +--------+------+-----+-----+
   |   1    |  10  |  3  |  0  |
   +--------+------+-----+-----+
   |   2    |   9  |  0  |  40 |
   +--------+------+-----+-----+

@ रोब, क्या आप सटीक क्वेरी को शामिल करने के लिए प्रश्न को संपादित कर सकते हैं?
जोहान


नोट: @ako की लिंक केवल MariaDB के लिए प्रासंगिक है।
टूलमेकर

जवाबों:


275

मैं इस समस्या को हल करने के लिए कुछ और अधिक विस्तृत कदम उठाने जा रहा हूँ। मैं माफी माँगता हूँ अगर यह बहुत लंबा है।


मैं आपके द्वारा दिए गए आधार के साथ शुरुआत करूँगा और इसका इस्तेमाल कुछ शब्दों को परिभाषित करने के लिए करूँगा, जिनका उपयोग मैं इस पोस्ट के बाकी हिस्सों के लिए करूँगा। यह आधार तालिका होगी :

select * from history;

+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
|      1 | A        |        10 |
|      1 | B        |         3 |
|      2 | A        |         9 |
|      2 | C        |        40 |
+--------+----------+-----------+

यह हमारा लक्ष्य होगा, सुंदर धुरी तालिका :

select * from history_itemvalue_pivot;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 |    0 |
|      2 |    9 |    0 |   40 |
+--------+------+------+------+

में मान history.hostidस्तंभ बन जाएगा y- मानों पिवट तालिका में। history.itemnameकॉलम में मान x-मान (स्पष्ट कारणों के लिए) बन जाएंगे ।


जब मुझे पिवट टेबल बनाने की समस्या को हल करना होगा, तो मैं इसे तीन-चरणीय प्रक्रिया (वैकल्पिक चौथे चरण के साथ) का उपयोग करके निपटाता हूं:

  1. ब्याज के कॉलम का चयन करें, यानी y-मान और x-मान
  2. अतिरिक्त स्तंभों के साथ आधार तालिका का विस्तार करें - प्रत्येक एक्स-मूल्य के लिए एक
  3. समूह और विस्तारित तालिका को एकत्रित करें - प्रत्येक y- मूल्य के लिए एक समूह
  4. (वैकल्पिक) कुल तालिका को संक्षिप्त करें

आइए इन चरणों को अपनी समस्या पर लागू करें और देखें कि हमें क्या मिलता है:

चरण 1: ब्याज के कॉलम चुनें । वांछित परिणाम में, hostidप्रदान करता है y- मानों और itemnameप्रदान करता है एक्स-मूल्यों

चरण 2: अतिरिक्त स्तंभों के साथ आधार तालिका का विस्तार करें । हमें आमतौर पर प्रति-मूल्य एक कॉलम की आवश्यकता होती है। याद रखें कि हमारा x- मान स्तंभ है itemname:

create view history_extended as (
  select
    history.*,
    case when itemname = "A" then itemvalue end as A,
    case when itemname = "B" then itemvalue end as B,
    case when itemname = "C" then itemvalue end as C
  from history
);

select * from history_extended;

+--------+----------+-----------+------+------+------+
| hostid | itemname | itemvalue | A    | B    | C    |
+--------+----------+-----------+------+------+------+
|      1 | A        |        10 |   10 | NULL | NULL |
|      1 | B        |         3 | NULL |    3 | NULL |
|      2 | A        |         9 |    9 | NULL | NULL |
|      2 | C        |        40 | NULL | NULL |   40 |
+--------+----------+-----------+------+------+------+

ध्यान दें कि हमने पंक्तियों की संख्या नहीं बदली है - हमने सिर्फ अतिरिक्त कॉलम जोड़े हैं। NULLएस के पैटर्न पर भी ध्यान दें - एक पंक्ति जिसमें itemname = "A"नए कॉलम के लिए एक गैर-शून्य मान है A, और अन्य नए कॉलम के लिए शून्य मान हैं।

चरण 3: समूह और विस्तारित तालिका एकत्र करें । हमें इसकी आवश्यकता है group by hostid, क्योंकि यह y-मान प्रदान करता है:

create view history_itemvalue_pivot as (
  select
    hostid,
    sum(A) as A,
    sum(B) as B,
    sum(C) as C
  from history_extended
  group by hostid
);

select * from history_itemvalue_pivot;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 | NULL |
|      2 |    9 | NULL |   40 |
+--------+------+------+------+

(ध्यान दें कि अब हमारे पास एक पंक्ति प्रति y-value है।) ठीक है, हम लगभग वहाँ हैं! हमें बस उन कुरूप NULLएस से छुटकारा पाने की आवश्यकता है ।

चरण 4: पहले से बताएं । हम सिर्फ शून्य मानों को शून्य से प्रतिस्थापित करने जा रहे हैं, इसलिए परिणाम सेट देखने के लिए अच्छा है:

create view history_itemvalue_pivot_pretty as (
  select 
    hostid, 
    coalesce(A, 0) as A, 
    coalesce(B, 0) as B, 
    coalesce(C, 0) as C 
  from history_itemvalue_pivot 
);

select * from history_itemvalue_pivot_pretty;

+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 |    0 |
|      2 |    9 |    0 |   40 |
+--------+------+------+------+

और हम कर रहे हैं - हमने MySQL का उपयोग करके एक अच्छी, सुंदर धुरी तालिका बनाई है।


इस प्रक्रिया को लागू करते समय विचार:

  • अतिरिक्त कॉलम में किस मूल्य का उपयोग करना है। मैंने itemvalueइस उदाहरण में इस्तेमाल किया
  • अतिरिक्त कॉलम में उपयोग करने के लिए "तटस्थ" मान क्या है। मैंने उपयोग किया NULL, लेकिन यह आपकी सटीक स्थिति के आधार पर भी हो सकता है 0या हो सकता ""है
  • समूहीकरण के समय कौन से कार्य का उपयोग करना है। मैं प्रयोग किया जाता sumहै, लेकिन countऔर maxभी अक्सर इस्तेमाल किया जाता है ( maxअक्सर जब एक-पंक्ति "वस्तुओं" है कि कई पंक्तियों में फैल गया था के निर्माण में किया जाता है)
  • y-मानों के लिए कई स्तंभों का उपयोग करना। यह समाधान केवल y- मानों के लिए एक कॉलम का उपयोग करने तक सीमित नहीं है - बस अतिरिक्त कॉलम को group byक्लॉज में प्लग करें (और उन्हें मत भूलना select)

ज्ञात सीमाएँ:

  • यह समाधान पिवट टेबल में एन कॉलम की अनुमति नहीं देता है - बेस टेबल को बढ़ाते समय प्रत्येक पिवट कॉलम को मैन्युअल रूप से जोड़ा जाना चाहिए। तो 5 या 10 x-मानों के लिए, यह समाधान अच्छा है। 100 के लिए, इतना अच्छा नहीं है। संग्रहीत प्रक्रियाओं के साथ कुछ समाधान हैं जो एक क्वेरी उत्पन्न करते हैं, लेकिन वे सही होने के लिए बदसूरत और मुश्किल हैं। मुझे वर्तमान में इस समस्या को हल करने के लिए एक अच्छा तरीका नहीं पता है जब धुरी तालिका में बहुत सारे कॉलम होने चाहिए।

25
+1 यह अब तक MySQL में मैंने देखी गई पिवट टेबल / क्रॉस टैब का सबसे अच्छा / सबसे स्पष्ट विवरण है
कैमरून.ब्रैकन

6
बहुत बढ़िया स्पष्टीकरण, धन्यवाद। चरण 4 को IFNULL (राशि (A), 0) AS A के उपयोग से चरण 3 में विलय किया जा सकता है, जो आपको एक ही परिणाम देगा लेकिन एक और तालिका बनाने की आवश्यकता के बिना
nealio82

1
यह धुरी के लिए सबसे अद्भुत समाधान था, लेकिन मैं सिर्फ उत्सुक हूं अगर कॉलम आइटमनाम में जो एक्स-अक्ष बनाता है, जिसमें कई मान हैं, जैसे यहां हमारे पास केवल तीन मान हैं जैसे कि ए, बी, सी। यदि ये मान ए तक फैले हुए हैं, तो। बी, सी, डी, ई, एबी, बीसी, एसी, एडी, एच ..... एन। फिर इस मामले में क्या समाधान होगा।
दीपेश

1
यह वास्तव में यहाँ स्वीकृत उत्तर होना चाहिए। यह अधिक विस्तृत, उपयोगी है, और यह बताता है कि इसे कैसे समझा जाए बजाय इसके कि इसे किसी लेख से जोड़ा जाए जैसे वर्तमान में स्वीकृत एक है
एजकैसेर्ज

2
@WhiteBig कृपया तारीखों पर एक नज़र डालें - यह StackOverflow उत्तर उस ब्लॉग पोस्ट से 1.5 साल पहले लिखा गया था। शायद आपको इसके बजाय ब्लॉग को मुझसे श्रेय देने के लिए कहना चाहिए।
मैट फेनविक

55
SELECT 
    hostid, 
    sum( if( itemname = 'A', itemvalue, 0 ) ) AS A,  
    sum( if( itemname = 'B', itemvalue, 0 ) ) AS B, 
    sum( if( itemname = 'C', itemvalue, 0 ) ) AS C 
FROM 
    bob 
GROUP BY 
    hostid;

'ए', 'बी', 'सी' के लिए तीन अलग-अलग पंक्तियों को बनाता है
पलानी

1
@ पालनी: नहीं, यह नहीं है। देखते हैं group by

धन्यवाद, यह मेरे लिए काम किया! हालाँकि, सिर्फ एक FYI करें कुछ साल देर से, मुझे MAXइसके बजाय उपयोग करना था SUMक्योंकि मेरे itemValueतार, संख्यात्मक मान नहीं हैं।
मेरिकट

33

एक अन्य विकल्प, विशेष रूप से उपयोगी है यदि आपके पास कई आइटम हैं जिनकी आपको धुरी की आवश्यकता है, तो mysql को आपके लिए क्वेरी बनाने दें:

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'ifnull(SUM(case when itemname = ''',
      itemname,
      ''' then itemvalue end),0) AS `',
      itemname, '`'
    )
  ) INTO @sql
FROM
  history;
SET @sql = CONCAT('SELECT hostid, ', @sql, ' 
                  FROM history 
                   GROUP BY hostid');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

FIDDLE ने इसे देखने के लिए कुछ अतिरिक्त मान जोड़े

GROUP_CONCAT अगर आपके पास चलाने से पहले इस पैरामीटर को वास्तव में बड़ा क्वेरी बदलना है तो 1000 का डिफ़ॉल्ट मान है

SET SESSION group_concat_max_len = 1000000;

परीक्षा:

DROP TABLE IF EXISTS history;
CREATE TABLE history
(hostid INT,
itemname VARCHAR(5),
itemvalue INT);

INSERT INTO history VALUES(1,'A',10),(1,'B',3),(2,'A',9),
(2,'C',40),(2,'D',5),
(3,'A',14),(3,'B',67),(3,'D',8);

  hostid    A     B     C      D
    1     10      3     0      0
    2     9       0    40      5
    3     14     67     0      8

@ मिहाई शायद आप मेरी मदद कर सकते हैं। इसे देखें: stackoverflow.com/questions/51832979/…
सक्सेस मैन

आसान बनाने में कर सकते हैं 'ifnull(SUM(case when itemname = ''',के साथ ''' then itemvalue end),0) AS करने के लिए, ' ` 'SUM(case when itemname = '''साथ ''' then itemvalue else 0 end) AS ',। यह आउटपुट की तरह है SUM(case when itemname = 'A' then itemvalue else 0 end) AS 'A'
टूलमेकर

24

मैट फेनविक के विचार का लाभ उठाते हुए मुझे समस्या को हल करने में मदद मिली (बहुत धन्यवाद), चलो इसे केवल एक क्वेरी तक कम करें:

select
    history.*,
    coalesce(sum(case when itemname = "A" then itemvalue end), 0) as A,
    coalesce(sum(case when itemname = "B" then itemvalue end), 0) as B,
    coalesce(sum(case when itemname = "C" then itemvalue end), 0) as C
from history
group by hostid

14

मैं शामिल होने के लिए उपकुंजी से Agung Sagita के उत्तर को संपादित करता हूं । मुझे यकीन नहीं है कि इस 2 तरीके के बीच कितना अंतर है, लेकिन सिर्फ एक और संदर्भ के लिए।

SELECT  hostid, T2.VALUE AS A, T3.VALUE AS B, T4.VALUE AS C
FROM TableTest AS T1
LEFT JOIN TableTest T2 ON T2.hostid=T1.hostid AND T2.ITEMNAME='A'
LEFT JOIN TableTest T3 ON T3.hostid=T1.hostid AND T3.ITEMNAME='B'
LEFT JOIN TableTest T4 ON T4.hostid=T1.hostid AND T4.ITEMNAME='C'

2
संभवतः, यह एक तेज़ समाधान हो सकता है।
jave.web 13

मुझे ऐसा नहीं लगता। क्योंकि लेफ्ट जॉइन की अपनी विलंबता है!
अबादिस

10

उपवर्ग का उपयोग करें

SELECT  hostid, 
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='A' AND hostid = t1.hostid) AS A,
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='B' AND hostid = t1.hostid) AS B,
    (SELECT VALUE FROM TableTest WHERE ITEMNAME='C' AND hostid = t1.hostid) AS C
FROM TableTest AS T1
GROUP BY hostid

लेकिन यह एक समस्या होगी यदि उप क्वेरी एक पंक्ति से अधिक होती है, तो उपक्वरी में आगे के कुल फ़ंक्शन का उपयोग करें


4

मेरा समाधान:

select h.hostid, sum(ifnull(h.A,0)) as A, sum(ifnull(h.B,0)) as B, sum(ifnull(h.C,0)) as  C from (
select
hostid,
case when itemName = 'A' then itemvalue end as A,
case when itemName = 'B' then itemvalue end as B,
case when itemName = 'C' then itemvalue end as C
  from history 
) h group by hostid

यह प्रस्तुत मामले में अपेक्षित परिणाम पैदा करता है।


3

मुझे लगता है कि Group By hostIdतब यह मूल्यों के साथ पहली पंक्ति दिखाएगा,
जैसे:

A   B  C
1  10
2      3

3

मैं अपनी रिपोर्टों को सरल क्वेरी का उपयोग करके लगभग स्तंभों को पंक्तियों में परिवर्तित करने के लिए एक तरीका बताता हूं। आप इसे यहाँ ऑनलाइन देख और परीक्षण कर सकते हैं

क्वेरी के स्तंभों की संख्या निश्चित है लेकिन मान गतिशील हैं और पंक्तियों के मूल्यों पर आधारित हैं। आप इसे बना सकते हैं, इसलिए, मैं तालिका शीर्ष लेख बनाने के लिए एक क्वेरी का उपयोग करता हूं और दूसरा मान देखने के लिए:

SELECT distinct concat('<th>',itemname,'</th>') as column_name_table_header FROM history order by 1;

SELECT
     hostid
    ,(case when itemname = (select distinct itemname from history a order by 1 limit 0,1) then itemvalue else '' end) as col1
    ,(case when itemname = (select distinct itemname from history a order by 1 limit 1,1) then itemvalue else '' end) as col2
    ,(case when itemname = (select distinct itemname from history a order by 1 limit 2,1) then itemvalue else '' end) as col3
    ,(case when itemname = (select distinct itemname from history a order by 1 limit 3,1) then itemvalue else '' end) as col4
FROM history order by 1;

आप इसे संक्षेप में भी बता सकते हैं:

SELECT
     hostid
    ,sum(case when itemname = (select distinct itemname from history a order by 1 limit 0,1) then itemvalue end) as A
    ,sum(case when itemname = (select distinct itemname from history a order by 1 limit 1,1) then itemvalue end) as B
    ,sum(case when itemname = (select distinct itemname from history a order by 1 limit 2,1) then itemvalue end) as C
FROM history group by hostid order by 1;
+--------+------+------+------+
| hostid | A    | B    | C    |
+--------+------+------+------+
|      1 |   10 |    3 | NULL |
|      2 |    9 | NULL |   40 |
+--------+------+------+------+

रेक्सटेस्टर के परिणाम :

रेक्सटेस्टर के परिणाम

http://rextester.com/ZSWKS28923

उपयोग के एक वास्तविक उदाहरण के लिए, यह रिपोर्ट एक दृश्य अनुसूची के साथ नाव / बस के प्रस्थान आगमन के घंटों के कॉलम में दिखाती है। आपको विज़ुअलाइज़ेशन को भ्रमित किए बिना अंतिम कॉल पर उपयोग नहीं किया गया एक अतिरिक्त कॉलम दिखाई देगा: sistema venda de passagens ऑनलाइन ई घाघ अंतिम ई कंट्रोले डे फ्रेटा - xsl tecnologia - xsl.com.br ** ऑनलाइन टिकट बेचने की प्रणाली


3

यदि आप MariaDB का उपयोग कर सकते हैं तो एक बहुत ही आसान उपाय है।

MariaDB-10.02 के बाद से CONNECT नामक एक नया स्टोरेज इंजन जोड़ा गया है जो हमें किसी अन्य क्वेरी या तालिका के परिणामों को एक पिवट टेबल में बदलने में मदद कर सकता है, जैसे आप चाहते हैं: आप डॉक्स पर एक नजर डाल सकते हैं ।

सबसे पहले कनेक्ट स्टोरेज इंजन को इंस्टॉल करें

अब हमारी तालिका का पिवट कॉलम है itemnameऔर प्रत्येक आइटम के लिए डेटा itemvalueकॉलम में स्थित है , इसलिए हमारे पास इस तालिका के लिए परिणाम धुरी तालिका हो सकती है:

create table pivot_table
engine=connect table_type=pivot tabname=history
option_list='PivotCol=itemname,FncCol=itemvalue';

अब हम चुन सकते हैं कि हम क्या चाहते हैं pivot_table:

select * from pivot_table

अधिक जानकारी यहाँ


1

यह सटीक उत्तर नहीं है, जिसकी आप तलाश कर रहे हैं, लेकिन यह एक ऐसा समाधान था जिसकी मुझे अपनी परियोजना पर जरूरत थी और आशा है कि यह किसी की मदद करेगा। यह अल्पविराम द्वारा अलग किए गए 1 से n पंक्ति वस्तुओं को सूचीबद्ध करेगा। Group_Concat MySQL में यह संभव बनाता है।

select
cemetery.cemetery_id as "Cemetery_ID",
GROUP_CONCAT(distinct(names.name)) as "Cemetery_Name",
cemetery.latitude as Latitude,
cemetery.longitude as Longitude,
c.Contact_Info,
d.Direction_Type,
d.Directions

    from cemetery
    left join cemetery_names on cemetery.cemetery_id = cemetery_names.cemetery_id 
    left join names on cemetery_names.name_id = names.name_id 
    left join cemetery_contact on cemetery.cemetery_id = cemetery_contact.cemetery_id 

    left join 
    (
        select 
            cemetery_contact.cemetery_id as cID,
            group_concat(contacts.name, char(32), phone.number) as Contact_Info

                from cemetery_contact
                left join contacts on cemetery_contact.contact_id = contacts.contact_id 
                left join phone on cemetery_contact.contact_id = phone.contact_id 

            group by cID
    )
    as c on c.cID = cemetery.cemetery_id


    left join
    (
        select 
            cemetery_id as dID, 
            group_concat(direction_type.direction_type) as Direction_Type,
            group_concat(directions.value , char(13), char(9)) as Directions

                from directions
                left join direction_type on directions.type = direction_type.direction_type_id

            group by dID


    )
    as d on d.dID  = cemetery.cemetery_id

group by Cemetery_ID

इस कब्रिस्तान के दो सामान्य नाम हैं, इसलिए नाम एक ही आईडी से जुड़े अलग-अलग पंक्तियों में सूचीबद्ध हैं, लेकिन दो नाम आईडी और क्वेरी कुछ इस तरह का उत्पादन करते हैं

    CemeteryID Cemetery_Name अक्षांश
    1 Appleton, Sulpher स्प्रिंग्स 35.46,6242832293


-2

मुझे यह कहने के लिए खेद है और हो सकता है कि मैं आपकी समस्या को बिल्कुल हल नहीं कर रहा हूं लेकिन PostgreSQL MySQL से 10 साल पुराना है और MySQL की तुलना में बेहद उन्नत है और इसे आसानी से प्राप्त करने के कई तरीके हैं। PostgreSQL स्थापित करें और इस क्वेरी को निष्पादित करें

CREATE EXTENSION tablefunc;

तब आवाज! और यहाँ व्यापक प्रलेखन: PostgreSQL: प्रलेखन: 9.1: tablefunc या यह क्वेरी

CREATE EXTENSION hstore;

फिर से आवाज! PostgreSQL: प्रलेखन: 9.0: hstore

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.