MySQL'de pivot tablo çıktısını nasıl döndürebilirim?


312

Böyle bir şey arayan bir MySQL tablo varsa:

şirket_adı eylem sayfa sayısı
-------------------------------
A PRINT 3 şirketi
A PRINT 2 şirketi
A PRINT 3 şirketi
B EMAIL şirketi   
B Şirketi BASKI 2
B Şirketi BASKI 2
B Şirketi BASKI 1
A PRINT 3 şirketi

Aşağıdaki gibi bir çıktı almak için bir MySQL sorgusu çalıştırmak mümkün mü:

company_name EMAIL PRINT 1 sayfa PRINT 2 sayfa PRINT 3 sayfa
-------------------------------------------------- -----------
ŞirketA 0 0 1 3
ŞirketB 1 1 2 0

Fikir, pagecountçıkış sütunu miktarının, her bir action/ pagecountçift için bir sütun ve daha sonra da isabet sayısı yansıtması gerektiği şekilde değişebileceğidir company_name. Buna pivot tablo denir mi emin değilim ama biri bunu önerdi?


3
Buna pivotlama denir ve bu dönüşümü SQL dışında yapmak çok, çok daha hızlıdır.
NB

1
Excel böyle şeyleri araştırıyor, "CROSSTAB" operatörü olmadığı için MySQL'de gerçekten zor :(
Dave Rix

Evet, şu anda Excel'de elle yapılır ve otomatikleştirmeye çalışıyoruz.
peku

3
Burada adım adım örnek bulundu: pivot tabloları otomatikleştirmek için nasıl . ve bu
Devid G

1
@giannischristofakis - bu gerçekten sizin ve iş arkadaşlarınızın daha basit gördüklerine bağlıdır. Yorum (4 yıl) yayınladığımdan beri teknoloji biraz yakalandı, bu yüzden uygulamada veya SQL'de olsun, daha iyi hissettiğiniz şeylere tamamen bağlı. Örneğin, çalışmamda benzer bir sorunla ilgileniyoruz, ancak hem SQL hem de uygulama içi yaklaşımı birleştiriyoruz. Temel olarak, görüşlü cevap vermek dışında size yardımcı olamıyorum ve ihtiyacınız olan şey bu değil :)
NB

Yanıtlar:


236

Bu temel olarak bir pivot tablodur.

Bunu başarmak için güzel bir öğretici burada bulunabilir: http://www.artfulsoftware.com/infotree/qrytip.php?id=78

Bu yazıyı okumanızı ve bu çözümü ihtiyaçlarınıza göre uyarlamanızı öneririm.

Güncelleme

Yukarıdaki bağlantı artık mevcut değil sonra ben burada mysql pivot cevapları arama hepiniz için bazı ek bilgi sağlamak zorunda hissediyorum. Gerçekten çok miktarda bilgi vardı ve oradan her şeyi buraya koymayacağım (daha da fazla bilgi kopyalamak istemediğimden daha fazla), ancak pivot ile nasıl başa çıkılacağı konusunda bazı tavsiyeler vereceğim Sql yolunu genellikle ilk etapta soruyu soran peku örneği ile tablolar.

Belki bağlantı kısa süre sonra tekrar gelir, buna dikkat edeceğim.

Elektronik tablo yolu ...

Birçok kişi bu amaçla MSExcel, OpenOffice veya diğer elektronik tablo araçları gibi bir araç kullanır. Bu geçerli bir çözüm, sadece verileri buraya kopyalayın ve GUI'nin bunu çözmek için sunduğu araçları kullanın.

Ancak ... bu soru değildi ve verilerin elektronik tabloya nasıl girileceği, sorunlu ölçekleme ve benzeri gibi bazı dezavantajlara bile yol açabilir.

SQL yolu ...

Masasına şöyle bir şey göz önüne alındığında:

CREATE TABLE `test_pivot` (
  `pid` bigint(20) NOT NULL AUTO_INCREMENT,
  `company_name` varchar(32) DEFAULT NULL,
  `action` varchar(16) DEFAULT NULL,
  `pagecount` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=MyISAM;

Şimdi istediğiniz masasına bakın:

company_name    EMAIL   PRINT 1 pages   PRINT 2 pages   PRINT 3 pages
-------------------------------------------------------------
CompanyA        0       0               1               3
CompanyB        1       1               2               0

Satırlar ( EMAIL, PRINT x pages) koşullara benzer. Ana gruplama şu şekildedir company_name.

Koşulları ayarlamak için CASE-statement'ı kullanmak için bağırır. Bir şey tarafından gruba amacıyla, iyi kullanın ... GROUP BY.

Bu pivotu sağlayan temel SQL şu şekilde görünebilir:

SELECT  P.`company_name`,
    COUNT(
        CASE 
            WHEN P.`action`='EMAIL' 
            THEN 1 
            ELSE NULL 
        END
    ) AS 'EMAIL',
    COUNT(
        CASE 
            WHEN P.`action`='PRINT' AND P.`pagecount` = '1' 
            THEN P.`pagecount` 
            ELSE NULL 
        END
    ) AS 'PRINT 1 pages',
    COUNT(
        CASE 
            WHEN P.`action`='PRINT' AND P.`pagecount` = '2' 
            THEN P.`pagecount` 
            ELSE NULL 
        END
    ) AS 'PRINT 2 pages',
    COUNT(
        CASE 
            WHEN P.`action`='PRINT' AND P.`pagecount` = '3' 
            THEN P.`pagecount` 
            ELSE NULL 
        END
    ) AS 'PRINT 3 pages'
FROM    test_pivot P
GROUP BY P.`company_name`;

Bu, istenen sonucu çok hızlı bir şekilde sağlamalıdır. Bu yaklaşımın en büyük dezavantajı, pivot tablonuzda ne kadar fazla satır olmasını istiyorsanız, SQL ifadenizde o kadar çok koşul tanımlamanız gerekir.

Bu da ele alınabilir, bu nedenle insanlar hazırlanan ifadeleri, rutinleri, sayaçları ve benzerlerini kullanma eğilimindedir.

Bu konuyla ilgili bazı ek bağlantılar:


4
bağlantı şu an için çalışıyor gibi görünüyor ... bir kez daha düşerse, şunu deneyin: Google'ın önbelleği webcache.googleusercontent.com/… veya İnternet Wayback Makinesi ( web.archive.org/web/20070303120558 * / artfulsoftware.com/ infotree / queries.php )
Lykegenes

bağlantıya şu url'den erişilebilir artfulsoftware.com/infotree/qrytip.php?id=78
MrPandav

1
"
İf

Şapka varsayılan davranış olduğundan (ve koşullu toplama yeterince pürüzlü olduğundan) ELSE NULL'ı CASE'inizden kaldırabilirsiniz
Caius Jard

86

Benim çözüm herhangi bir pivot olmadan T-SQL olduğunu:

SELECT
    CompanyName,  
    SUM(CASE WHEN (action='EMAIL') THEN 1 ELSE 0 END) AS Email,
    SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END) AS Print1Pages,
    SUM(CASE WHEN (action='PRINT' AND pagecount=2) THEN 1 ELSE 0 END) AS Print2Pages,
    SUM(CASE WHEN (action='PRINT' AND pagecount=3) THEN 1 ELSE 0 END) AS Print3Pages
FROM 
    Company
GROUP BY 
    CompanyName

2
Bu benim için PostgreSQL'de bile çalışıyor. Bu daha temiz
itsols

2
"Benim çözümüm herhangi bir pivot olmadan T-SQL'de:" Sadece SQL Server değil, ANSI SQL standartlarına uyan çoğu veritabanı satıcısı üzerinde çalışmalıdır. SUM()Sayısal verilerle çalışabileceğinizi unutmayın, eğer kullanmanız gerekecek olan MAX()
pivotları döndürürseniz

1
CASE unnesesary olduğunu düşünüyorum, SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END)sadece SUM(action='PRINT' AND pagecount=1)durum 1doğru ve 0yanlış olduğunda dönüştürülür beri yapabilirsiniz
kajacx

1
@kajacx evet, ancak bu tür bir Boolean manipülasyonu olmayan veritabanında gereklidir. "Tüm dB üzerinde çalışan daha uzun bir sözdizimi" ile "yalnızca üzerinde çalışan daha kısa bir sözdizimi" arasında bir seçim göz önüne alındığında, eski
Caius Jard

66

MySQL için koşulları doğrudan devreye sokabilirsiniz SUM()ve Boolean01 olarak değerlendirilir veya böylece IF/CASEifadeler kullanmadan ölçütlerinize göre sayım yapabilirsiniz.

SELECT
    company_name,  
    SUM(action = 'EMAIL')AS Email,
    SUM(action = 'PRINT' AND pagecount = 1)AS Print1Pages,
    SUM(action = 'PRINT' AND pagecount = 2)AS Print2Pages,
    SUM(action = 'PRINT' AND pagecount = 3)AS Print3Pages
FROM t
GROUP BY company_name

DEMO


1
Bu gerçekten düzenli. Bunun diğer platformlarda (Postgres gibi) standartlara uygun olup olmadığını biliyor musunuz?
itsols

3
@itsols Hayır sadece Mysql özgü
M Khalid Junaid


2
SQLite için de çalışır
SBF

37

Dinamik pivot için GROUP_CONCATile kullanın CONCAT. GROUP_CONCAT fonksiyonu çeşitli seçenekleri ile tek dizede bir gruptan dizeyi birleştirir.

SET @sql = NULL;
SELECT
    GROUP_CONCAT(DISTINCT
    CONCAT(
      'SUM(CASE WHEN action = "',
      action,'"  AND ', 
           (CASE WHEN pagecount IS NOT NULL 
           THEN CONCAT("pagecount = ",pagecount) 
           ELSE pagecount IS NULL END),
      ' THEN 1 ELSE 0 end) AS ',
      action, IFNULL(pagecount,'')

    )
  )
INTO @sql
FROM
  t;

SET @sql = CONCAT('SELECT company_name, ', @sql, ' 
                  FROM t 
                   GROUP BY company_name');

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

BURADA DEMO


2
Pacerier, gerçek adam ama dinamik olarak en iyi yaklaşımlardan birini döndürüyor
Abhishek Gupta

2
"İşlemler" sütununda birçok değeriniz varsa veya her bir değer için bir vaka ifadesi yazmak zaman alıcı ve güncel tutulması zor olabileceğinden, listenin zaman içinde büyümesini beklerseniz bu işe yarar.
Patrick Murphy

23

Boole mantığı kullanan bir stardard-SQL sürümü :

SELECT company_name
     , COUNT(action = 'EMAIL' OR NULL) AS "Email"
     , COUNT(action = 'PRINT' AND pagecount = 1 OR NULL) AS "Print 1 pages"
     , COUNT(action = 'PRINT' AND pagecount = 2 OR NULL) AS "Print 2 pages"
     , COUNT(action = 'PRINT' AND pagecount = 3 OR NULL) AS "Print 3 pages"
FROM   tbl
GROUP  BY company_name;

SQL Fiddle.

Nasıl?

TRUE OR NULL verim TRUE.
FALSE OR NULLverim NULL.
NULL OR NULLverim NULL.
Ve COUNTyalnızca boş olmayan değerleri sayar. Voila.


@Erwin, Ama üç sütun olduğunu nereden bilebilirsin? Ya 5 varsa? 10? 20?
Pacerier

@Pacerier: Sorudaki örnek bunu gösteriyor gibi görünüyor. Her iki durumda da, SQL dönüş türünü bilmek ister . Bir tamamen dinamik sorgu mümkün değildir. Çıktı sütunlarının sayısı değişebiliyorsa iki adıma ihtiyacınız vardır: 1. sorguyu derleyin, 2.: yürütün.
Erwin Brandstetter

11

Doğru cevap:

select table_record_id,
group_concat(if(value_name='note', value_text, NULL)) as note
,group_concat(if(value_name='hire_date', value_text, NULL)) as hire_date
,group_concat(if(value_name='termination_date', value_text, NULL)) as termination_date
,group_concat(if(value_name='department', value_text, NULL)) as department
,group_concat(if(value_name='reporting_to', value_text, NULL)) as reporting_to
,group_concat(if(value_name='shift_start_time', value_text, NULL)) as shift_start_time
,group_concat(if(value_name='shift_end_time', value_text, NULL)) as shift_end_time
from other_value
where table_name = 'employee'
and is_active = 'y'
and is_deleted = 'n'
GROUP BY table_record_id

1
Bu sadece elinizde olan bir örnek mi? other_valueTablonun yapısı nedir ?
Patrick Murphy

1
"Doğru cevap:" Muhtemelen SET1024_ GROUP_CONCAT sonra GROUP_CONCAT için 1024 ile sınırlı olan defualt değerini artırmak için sorguyu eksik değil gibi basit bir hata olmadan dize keser anlamına gelir beklenmedik sonuçlar olabilir ..
Raymond Nijland

üzgünüm daha fazla ayrıntı hatırlayamıyorum. Eğlenmek için bir şeyler yaparım ve sonra tüm projeyi unutur veya yok ederim. Ama bir zorlukla karşılaştığımda bunu nasıl düzelttiğimi paylaşıyorum. Örneğimin çok ayrıntılı olmadığını biliyorum ama sanırım neye karşı olduklarını bilenlere yol
Talha

9

MySQL Pivot tablo üreteci adlı bir araç var, daha sonra excel'e (isterseniz) dışa aktarabileceğiniz web tabanlı pivot tablo oluşturmanıza yardımcı olabilir. verileriniz tek bir tabloda veya birkaç tabloda bulunuyorsa işe yarayabilir.

Tek yapmanız gereken sütunların veri kaynağını (dinamik sütunları destekler), satırları, tablonun gövdesindeki değerleri ve tablo ilişkisini (varsa) belirtmektir. MySQL Pivot Tablosu

Bu aracın ana sayfası http://mysqlpivottable.net


3
select t3.name, sum(t3.prod_A) as Prod_A, sum(t3.prod_B) as Prod_B, sum(t3.prod_C) as    Prod_C, sum(t3.prod_D) as Prod_D, sum(t3.prod_E) as Prod_E  
from
(select t2.name as name, 
case when t2.prodid = 1 then t2.counts
else 0 end  prod_A, 

case when t2.prodid = 2 then t2.counts
else 0 end prod_B,

case when t2.prodid = 3 then t2.counts
else 0 end prod_C,

case when t2.prodid = 4 then t2.counts
else 0 end prod_D, 

case when t2.prodid = "5" then t2.counts
else 0 end prod_E

from 
(SELECT partners.name as name, sales.products_id as prodid, count(products.name) as counts
FROM test.sales left outer join test.partners on sales.partners_id = partners.id
left outer join test.products on sales.products_id = products.id 
where sales.partners_id = partners.id and sales.products_id = products.id group by partners.name, prodid) t2) t3

group by t3.name ;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.