Wie kann ich die Pivot-Tabellenausgabe in MySQL zurückgeben?

312

Wenn ich eine MySQL-Tabelle habe, die ungefähr so ​​aussieht:

firmenname aktionsseitenanzahl
-------------------------------
Firma A DRUCK 3
Firma A DRUCK 2
Firma A DRUCK 3
Firma B E-MAIL   
Firma B DRUCKEN 2
Firma B DRUCKEN 2
Firma B DRUCKEN 1
Firma A DRUCK 3

Ist es möglich, eine MySQL-Abfrage auszuführen, um eine Ausgabe wie folgt zu erhalten:

Firmenname E-MAIL DRUCKEN 1 Seiten DRUCKEN 2 Seiten DRUCKEN 3 Seiten
-------------------------------------------------- -----------
FirmaA 0 0 1 3
FirmaB 1 1 2 0

Die Idee ist, dass pagecountdies variieren kann, sodass die Anzahl der Ausgabespalten dies widerspiegeln sollte, eine Spalte für jedes action/ pagecountPaar und dann die Anzahl der Treffer pro company_name. Ich bin nicht sicher, ob dies eine Pivot-Tabelle genannt wird, aber jemand hat das vorgeschlagen?

Peku
quelle
3
Es heißt Pivoting und es ist viel, viel schneller, diese Transformation außerhalb von SQL durchzuführen.
NB
1
Excel durchläuft solche Dinge, es ist wirklich schwierig in MySQL, da es keinen "CROSSTAB" -Operator gibt :(
Dave Rix
Ja, es wird derzeit von Hand in Excel ausgeführt und wir versuchen, es zu automatisieren.
Peku
3
Hier habe ich Schritt für Schritt ein Beispiel gefunden: wie man Pivot-Tabellen automatisiert . und das
Devid G
1
@giannischristofakis - es kommt wirklich darauf an, was Sie und Ihre Mitarbeiter für einfacher halten. Die Technologie hat ziemlich viel aufgeholt, seit ich den Kommentar gepostet habe (4 Jahre), also liegt es ganz bei dem, was Sie für besser halten - sei es in der Anwendung oder in SQL. Bei meiner Arbeit beschäftigen wir uns beispielsweise mit ähnlichen Problemen, kombinieren jedoch sowohl den SQL- als auch den In-App-Ansatz. Grundsätzlich kann ich Ihnen nur helfen, wenn Sie eine meinungsgebundene Antwort geben, und das brauchen Sie nicht :)
NB

Antworten:

236

Diese im Grunde ist eine Pivot - Tabelle.

Ein nettes Tutorial dazu finden Sie hier: http://www.artfulsoftware.com/infotree/qrytip.php?id=78

Ich empfehle, diesen Beitrag zu lesen und diese Lösung an Ihre Bedürfnisse anzupassen.

Aktualisieren

Nachdem der obige Link derzeit nicht mehr verfügbar ist, fühle ich mich verpflichtet, einige zusätzliche Informationen für alle bereitzustellen, die hier nach MySQL-Pivot-Antworten suchen. Es gab wirklich eine Menge Informationen, und ich werde hier nicht alles von hier einfügen (noch mehr, da ich ihr umfangreiches Wissen einfach nicht kopieren möchte), aber ich werde einige Ratschläge geben, wie man mit Pivot umgeht Tabellen die SQL-Art im Allgemeinen mit dem Beispiel von Peku, der die Frage an erster Stelle gestellt hat.

Vielleicht kommt der Link bald zurück, ich werde ein Auge darauf haben.

Die Tabellenkalkulation ...

Viele Leute verwenden zu diesem Zweck nur ein Tool wie MSExcel, OpenOffice oder andere Tabellenkalkulations-Tools. Dies ist eine gültige Lösung. Kopieren Sie einfach die Daten dort und verwenden Sie die von der GUI angebotenen Tools, um dies zu lösen.

Aber ... das war nicht die Frage, und es könnte sogar zu einigen Nachteilen führen, wie zum Beispiel, wie die Daten in die Tabelle aufgenommen werden, problematische Skalierung und so weiter.

Der SQL-Weg ...

Angesichts dessen sieht sein Tisch ungefähr so ​​aus:

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;

Schauen Sie nun in den gewünschten Tisch:

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

Die Zeilen ( EMAIL, PRINT x pages) ähneln den Bedingungen. Die Hauptgruppierung ist von company_name.

Um die Bedingungen einzurichten, ruft dies eher nach der Verwendung der CASEAnweisung. Um zu einer Gruppe von etwas, na ja, Gebrauch ... GROUP BY.

Das grundlegende SQL, das diesen Pivot bereitstellt, kann ungefähr so ​​aussehen:

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`;

Dies sollte sehr schnell das gewünschte Ergebnis liefern. Je größer der Nachteil dieses Ansatzes ist, desto mehr Zeilen müssen in Ihrer Pivot-Tabelle enthalten sein, desto mehr Bedingungen müssen Sie in Ihrer SQL-Anweisung definieren.

Dies kann auch behandelt werden, daher neigen die Leute dazu, vorbereitete Anweisungen, Routinen, Zähler und dergleichen zu verwenden.

Einige zusätzliche Links zu diesem Thema:

Björn
quelle
4
Der Link scheint vorerst zu funktionieren. Wenn er jemals wieder ausfällt , versuchen Sie Folgendes : Googles Cache webcache.googleusercontent.com/… oder die Internet Wayback Machine ( web.archive.org/web/20070303120558 * / artfulsoftware.com/) infotree / queries.php )
Lykegenes
Der Link ist unter dieser URL zugänglich. artfulsoftware.com/infotree/qrytip.php?id=78
MrPandav
1
Es gibt eine andere Möglichkeit, eine Pivot-Tabelle zu generieren, ohne "if", "case" oder "GROUP_CONCAT" zu verwenden: en.wikibooks.org/wiki/MySQL/Pivot_table
user2513149
Sie können den ELSE NULL aus Ihrem CASE entfernen, da dies das Standardverhalten ist (und die bedingte Aggregation wortreich genug ist)
Caius Jard
86

Meine Lösung ist in T-SQL ohne Drehpunkte:

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
RRM
quelle
2
Dies funktioniert bei mir sogar unter PostgreSQL. Ich bevorzuge diese Methode als die Kreuztabellenerweiterung auf Postgres zu verwenden, da dies sauberer ist
itsols
2
"Meine Lösung ist in T-SQL ohne Pivots:" Nicht nur SQL Server sollte auf den meisten Datenbankanbietern funktionieren, die den ANSI SQL-Standards entsprechen. Beachten Sie, dass SUM()nur mit numerischen Daten gearbeitet werden kann, wenn Sie Zeichenfolgen schwenken müssen, die Sie verwenden müssenMAX()
Raymond Nijland
1
Ich denke , die CASE unnesesary in sind SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END), können Sie einfach tun , SUM(action='PRINT' AND pagecount=1)da der Zustand konvertiert werden wird , 1wenn wahr und 0wenn falsch
kajacx
1
@kajacx ja, obwohl es für Datenbanken benötigt wird, die diese Art von Boolescher Manipulation nicht haben. Bei einer Wahl zwischen einer "längeren Syntax, die auf allen dB funktioniert" und einer "kürzeren Syntax, die nur auf ... funktioniert" würde ich die erstere auswählen
Caius Jard
66

Für MySQL können Sie Bedingungen direkt in SUM()Funktion setzen und es wird als Boolescher Wert ausgewertet 0oder1 Sie können Ihre Anzahl basierend auf Ihren Kriterien ohne Verwendung von IF/CASEAnweisungen festlegen

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

M Khalid Junaid
quelle
1
Das ist wirklich ordentlich. Wissen Sie, ob dies auf anderen Plattformen (wie Postgres) standardkonform ist?
Itsols
3
@itsols Nein, es ist nur für MySQL spezifisch
M Khalid Junaid
@itsols: Ich habe eine weitere Standard-SQL-Version hinzugefügt . Postgres hat auch eine spezielle crosstab()Funktion.
Erwin Brandstetter
2
Funktioniert auch für SQLite
SBF
37

Verwenden Sie für dynamischen Pivot GROUP_CONCATmit CONCAT. Die Funktion GROUP_CONCAT verkettet Zeichenfolgen aus einer Gruppe mit verschiedenen Optionen zu einer Zeichenfolge.

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;

DEMO HIER

Abhishek Gupta
quelle
2
Pacerier, wahrer Mann, aber für dynamisches Schwenken ist es einer der besten Ansätze
Abhishek Gupta
2
Dies funktioniert gut, wenn Sie viele Werte in der Spalte "Aktionen" haben oder erwarten, dass diese Liste im Laufe der Zeit wächst, da das Schreiben einer case-Anweisung für jeden Wert zeitaufwändig und schwierig auf dem neuesten Stand sein kann.
Patrick Murphy
23

Eine Stardard-SQL- Version mit boolescher Logik :

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.

Wie?

TRUE OR NULL ergibt TRUE.
FALSE OR NULLergibt NULL.
NULL OR NULLergibt NULL.
Und COUNTzählt nur Nicht-Null-Werte. Voilá.

Erwin Brandstetter
quelle
@Erwin, aber woher weißt du, dass es drei Spalten gibt? Was ist, wenn es 5 gibt? 10? 20?
Pacerier
@ Pacerier: Das Beispiel in der Frage scheint darauf hinzudeuten. So oder so, SQL fordert den Rückgabetyp zu kennen. Eine vollständig dynamische Abfrage ist nicht möglich. Wenn die Anzahl der Ausgabespalten variieren kann, benötigen Sie zwei Schritte: 1. Erstellen Sie die Abfrage, 2. Führen Sie sie aus.
Erwin Brandstetter
11

Die richtige Antwort lautet:

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
Talha
quelle
1
Ist dies nur ein Beispiel, das Sie zur Hand hatten? Wie ist die other_valueTabelle aufgebaut?
Patrick Murphy
1
"Die richtige Antwort lautet:" Höchstwahrscheinlich nicht, da die SETAbfrage zur Erhöhung des auf 1024 für GROUP_CONCAT auf 1024 begrenzten Defualt-Werts fehlt. GROUP_CONCAT schneidet die Zeichenfolge einfach ohne Fehler ab, was bedeutet, dass unerwartete Ergebnisse auftreten können.
Raymond Nijland
Entschuldigung, Jungs können sich nicht an weitere Details erinnern. Ich mache Sachen zum Spaß und vergesse oder zerstöre dann das gesamte Projekt. Aber wenn ich auf eine Herausforderung stoße, teile ich mit, wie ich sie behoben habe. Ich weiß, dass mein Beispiel nicht sehr detailliert ist, aber ich denke, es kann Anweisungen für diejenigen geben, die wissen, gegen was sie antreten :)
Talha
9

Es gibt ein Tool namens MySQL Pivot Table Generator, mit dem Sie webbasierte Pivot-Tabellen erstellen können, die Sie später in Excel exportieren können (wenn Sie möchten). Dies kann funktionieren, wenn sich Ihre Daten in einer einzelnen Tabelle oder in mehreren Tabellen befinden.

Sie müssen lediglich die Datenquelle der Spalten (sie unterstützt dynamische Spalten), Zeilen, die Werte im Hauptteil der Tabelle und die Tabellenbeziehung (falls vorhanden) angeben. MySQL Pivot-Tabelle

Die Homepage dieses Tools lautet http://mysqlpivottable.net

Peter Green
quelle
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 ;
irba
quelle