মাইএসকিউএল - কলামগুলিতে সারি


185

আমি পোস্টগুলি অনুসন্ধান করার চেষ্টা করেছি, তবে আমি কেবল এসকিউএল সার্ভার / অ্যাক্সেসের সমাধান পেয়েছি। আমার মাইএসকিউএল (5. এক্স) এর সমাধান দরকার।

আমার কাছে 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 |
   +--------+------+-----+-----+

@ রব, সঠিক প্রশ্নটি অন্তর্ভুক্ত করতে দয়া করে প্রশ্নটি সম্পাদনা করতে পারেন?
জোহান

উত্তর:


274

আমি এই সমস্যাটি সমাধানে নেওয়া পদক্ষেপগুলির কিছুটা দীর্ঘ এবং আরও বিশদ ব্যাখ্যা যুক্ত করতে যাচ্ছি। আমি দীর্ঘ ক্ষণ চাইলে ক্ষমা চাই।


আপনার দেওয়া বেসটি দিয়ে শুরু করব এবং কয়েকটি পোস্টের সংজ্ঞা দিতে এটি ব্যবহার করব যা আমি এই পোস্টের বাকী অংশের জন্য ব্যবহার করব। এটি বেস টেবিল হবে :

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কলামের মানগুলি এক্স-মানগুলিতে পরিণত হবে (স্পষ্ট কারণে)।


যখন আমাকে একটি পাইভট টেবিল তৈরির সমস্যার সমাধান করতে হবে, আমি তিন-পদক্ষেপ প্রক্রিয়া (fourthচ্ছিক চতুর্থ ধাপ সহ) ব্যবহার করে এটি মোকাবিলা করি:

  1. আগ্রহের কলামগুলি নির্বাচন করুন, যেমন y- মান এবং এক্স-মান
  2. অতিরিক্ত কলাম সহ বেস টেবিল প্রসারিত করুন - প্রতিটি এক্স-মানের জন্য একটি
  3. গ্রুপ এবং প্রসারিত টেবিলকে একত্রিত করুন - প্রতিটি y- মানের জন্য একটি গ্রুপ
  4. (alচ্ছিক) সম্মিলিত টেবিল প্রাকৃত

আসুন আপনার সমস্যায় এই পদক্ষেপগুলি প্রয়োগ করুন এবং দেখুন আমরা কী পাই:

পদক্ষেপ 1: আগ্রহের কলামগুলি নির্বাচন করুন । কাঙ্ক্ষিত ফলাফল সালে hostidউপলব্ধ Y-মান এবং itemnameউপলব্ধ এক্স-মান

পদক্ষেপ 2: অতিরিক্ত কলাম সহ বেস টেবিল প্রসারিত করুন । আমাদের সাধারণত এক্স-ভ্যালুতে একটি কলামের প্রয়োজন। আমাদের এক্স-মান কলামটি মনে করুন 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 |
+--------+------+------+------+

(দ্রষ্টব্য যে এখন আমাদের প্রতি ওয়াই-ভ্যালুতে একটি সারি রয়েছে)) ঠিক আছে, আমরা প্রায় রয়েছি! আমাদের কেবল সেই কুৎসিতদের হাত থেকে মুক্তি দেওয়া দরকার 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 |
+--------+------+------+------+

এবং আমরা সম্পন্ন করেছি - আমরা মাইএসকিউএল ব্যবহার করে একটি দুর্দান্ত, সুন্দর পিভট টেবিল তৈরি করেছি।


এই পদ্ধতি প্রয়োগ করার সময় বিবেচনাগুলি:

  • অতিরিক্ত কলামগুলিতে কী মান ব্যবহার করতে হবে। আমি itemvalueএই উদাহরণে ব্যবহার করেছি
  • অতিরিক্ত কলামগুলিতে কী "নিরপেক্ষ" মান ব্যবহার করতে হবে। আমি ব্যবহার করেছি NULL, তবে এটি আপনার সঠিক পরিস্থিতির উপর নির্ভর করেও হতে পারে 0বা হতে পারে""
  • গোষ্ঠীকরণের সময় কোন সমষ্টিগত ফাংশনটি ব্যবহার করতে হবে। আমি ব্যবহার করেছি sum, তবে countএবং maxপ্রায়শই ব্যবহৃত হয় ( maxপ্রায়শই এক সারি "অবজেক্টগুলি" তৈরি করার সময় ব্যবহৃত হয় যা বহু সারি জুড়ে ছড়িয়ে পড়েছিল)
  • y- মানগুলির জন্য একাধিক কলাম ব্যবহার করা। এই সমাধানটি y- মানগুলির জন্য একটি একক কলাম ব্যবহার করার মধ্যেই সীমাবদ্ধ নয় - কেবল অতিরিক্ত কলামগুলিকে ক্লজটিতে প্লাগ করুন group by(এবং selectতাদেরকে ভুলে যাবেন না )

জ্ঞাত সীমাবদ্ধতা:

  • এই সমাধানটি পিভট টেবিলের n কলামগুলিকে অনুমতি দেয় না - বেস টেবিলটি প্রসারিত করার সময় প্রতিটি পিভট কলামটি ম্যানুয়ালি যুক্ত করা দরকার। 5 বা 10 এক্স-মানগুলির জন্য, এই সমাধানটি দুর্দান্ত। 100 এর জন্য, এত সুন্দর নয়। স্বেচ্ছাসেবী পদ্ধতিতে একটি কোয়েরি উত্পন্ন করার কিছু সমাধান রয়েছে তবে সেগুলি কুশ্রী এবং সঠিক হওয়া শক্ত। যখন পাইভট টেবিলটিতে প্রচুর কলাম থাকা দরকার তখন আমি এই সমস্যাটি সমাধান করার ভাল উপায়টি জানি না।

25
+1 এটি মাইএসকিউএল
পাইভট

6
দুর্দান্ত ব্যাখ্যা, ধন্যবাদ। IFNULL (যোগফল (যোগ), 0) এএস এ ব্যবহার করে চতুর্থ পদক্ষেপটি 3 ধাপে একীভূত করা যেতে পারে, আপনাকে একই ফলস্বরূপ প্রদান করেছে তবে আরও একটি সারণী তৈরির প্রয়োজন ছাড়াই
neialio82

1
এটি পাইভোটের জন্য সবচেয়ে আশ্চর্যজনক সমাধান ছিল তবে আমি কৌতূহলবশত যদি কলাম আইটেমনেমে এক্স অক্ষের রূপ ধারণ করে একাধিক মান থাকে তবে এখানে আমাদের কেবল তিনটি মান থাকে যেমন এ, বি, সি। যদি এই মানগুলি A পর্যন্ত প্রসারিত হয়, বি, সি, ডি, ই, এবি, বিসি, এসি, এডি, এইচ ..... এন তাহলে এক্ষেত্রে সমাধান কী হবে।
দীপেশ

1
এটি সত্যই এখানে গ্রহণযোগ্য উত্তর হওয়া উচিত। এটি
উপায়টি

1
@ হোয়াইটবিগ দয়া করে তারিখগুলি একবার দেখুন - এই স্ট্যাকওভারফ্লো উত্তরটি ব্লগ পোস্টের 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;

'এ', 'বি', 'সি' এর জন্য তিনটি পৃথক সারি তৈরি করে
পালানি

@ পলানী: না, তা হয় না। দেখুন group by
রুখ

ধন্যবাদ, এটি আমার পক্ষে কাজ করেছে! তবে কয়েক বছর দেরিতে কেবল একটি এফওয়াইআই আমাকে তার MAXপরিবর্তে ব্যবহার করতে হয়েছিল SUMকারণ আমার itemValueস্ট্রিংগুলি হচ্ছে সংখ্যাসূচক মান।
মেরিক্যাট

31

আরেকটি বিকল্প, বিশেষত দরকারী যদি আপনার কাছে আইভ্যাট করা দরকার এমন অনেকগুলি আইটেম থাকে তবে মাইএসকিএলকে আপনার জন্য ক্যোয়ারী তৈরি করতে দেওয়া:

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/…
সাফল্য ম্যান

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

আমি সম্পাদনা আগুং Sagita subquery 's উত্তর যোগদানের জন্য। আমি এই 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

আমি তাই মনে করি না। বাম যোগদানের নিজস্ব বিলম্ব আছে!
আবাদিস

10

subquery ব্যবহার করুন

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

ব্যবহারের একটি বাস্তব উদাহরণের জন্য, এই প্রতিবেদনে কলামগুলিতে ভিজ্যু শিডিউল সহ নৌকো / বাসের আগমনগুলির সময়গুলি কলামগুলিতে শোনা যায়। আপনি ভিজ্যুয়ালাইজেশনকে বিভ্রান্ত না করে শেষ কর্নারে আরও একটি অতিরিক্ত কলাম ব্যবহার করবেন না: সিস্টেমে ভেন্ডা ডি প্যাসেজগুলি অনলাইন ই গ্রাহক এবং চূড়ান্ত ই কনট্রোল ডি ফ্রোটা - এক্সএসএল টেকনোলজিয়া - xsl.com.br ** টিকিট দেওয়ার টিকিট অনলাইনে এবং টিকিট বিক্রি করার জন্য


3

আপনি যদি মারিয়াডিবি ব্যবহার করতে পারতেন তবে খুব সহজ একটি সমাধান রয়েছে।

মারিয়াডিবি -১০.০২ থেকে সেখানে সংযোগ নামে একটি নতুন স্টোরেজ ইঞ্জিন যুক্ত করা হয়েছে যা আপনি যা চান ঠিক তার মতোই অন্য ক্যোয়ারী বা টেবিলের ফলাফলগুলিকে পিভট টেবিলে রূপান্তর করতে সহায়তা করতে পারে: আপনি ডক্সটিতে নজর রাখতে পারেন ।

সবার আগে সংযুক্ত স্টোরেজ ইঞ্জিনটি ইনস্টল করুন

এখন আমাদের টেবিলের পিভট কলামটি রয়েছে 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 সারি আইটেমের তালিকা করবে। গ্রুপ_কনক্যাট মাইএসকিউএলে এটি সম্ভব করে তোলে।

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

এই কবরস্থানের দুটি সাধারণ নাম রয়েছে তাই নামগুলি একটি পৃথক আইডির সাথে সংযুক্ত বিভিন্ন সারিতে তালিকাবদ্ধ করা হয়েছে তবে দুটি নাম আইডির এবং ক্যোয়ারিতে এমন কিছু তৈরি হয় যা

    কবরস্থান ID কবরস্থান_নাম অক্ষাংশ
    1 অ্যাপলটন, সলফার স্প্রিংস 35.4276242832293


-2

আমি এটি বলার জন্য দুঃখিত এবং সম্ভবত আমি আপনার সমস্যাটি ঠিক সমাধান করছি না তবে পোস্টগ্রিসকিউএল মাইএসকিউএল থেকে 10 বছর বড় এবং মাইএসকিউএলের তুলনায় অত্যন্ত উন্নত এবং এটি সহজেই অর্জন করার অনেক উপায় রয়েছে। PostgreSQL ইনস্টল করুন এবং এই কোয়েরিটি সম্পাদন করুন

CREATE EXTENSION tablefunc;

তাহলে ভয়েলা! এবং এখানে বিস্তৃত ডকুমেন্টেশন: পোস্টগ্রেএসকিউএল: ডকুমেন্টেশন: 9.1: টেবিলফঙ্ক বা এই কোয়েরি

CREATE EXTENSION hstore;

তারপরে আবার ভয়েলা! PostgreSQL: ডকুমেন্টেশন: 9.0: hstore

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