ฉันจะคืนค่าตารางสาระสำคัญใน MySQL ได้อย่างไร


312

หากฉันมีตาราง MySQL ที่มีลักษณะเช่นนี้:

ชื่อการกระทำของ company_name
-------------------------------
บริษัท พริ้นท์ 3
บริษัท A พริ้นท์ 2
บริษัท พริ้นท์ 3
บริษัท B EMAIL   
บริษัท B PRINT 2
บริษัท B PRINT 2
บริษัท B พิมพ์ 1
บริษัท พริ้นท์ 3

เป็นไปได้ไหมที่จะรันคำสั่ง MySQL เพื่อให้ได้ผลลัพธ์เช่นนี้:

company_name EMAIL PRINT 1 หน้าพิมพ์ 2 หน้าพิมพ์ 3 หน้า
-------------------------------------------------- -----------
บริษัท 0 0 1 3
บริษัท B 1 1 2 0

คิดคือการที่pagecountสามารถแตกต่างกันเพื่อให้จำนวนคอลัมน์ที่ส่งออกควรจะสะท้อนให้เห็นว่าหนึ่งคอลัมน์สำหรับแต่ละaction/ คู่แล้วจำนวนครั้งต่อpagecount company_nameฉันไม่แน่ใจว่าสิ่งนี้เรียกว่าตารางสาระสำคัญ แต่มีคนแนะนำว่า


3
มันเรียกว่า pivoting และเร็วกว่ามากในการแปลงนอก SQL
NB

1
Excel ดึงสิ่งต่าง ๆ ออกมาเช่นนี้มันเป็นเรื่องยากมากใน MySQL เนื่องจากไม่มีตัวดำเนินการ "CROSSTAB" :(
Dave Rix

ใช่ปัจจุบันทำด้วยมือใน Excel และเราพยายามทำให้เป็นอัตโนมัติ
peku

3
ที่นี่ผมพบว่าขั้นตอนโดยขั้นตอนตัวอย่าง: วิธีการทำให้ตารางเดือย และนี่
Devid G

1
@giannischristofakis - ขึ้นอยู่กับสิ่งที่คุณและเพื่อนร่วมงานของคุณเห็นว่าง่ายขึ้น เทคโนโลยีจมลงเล็กน้อยตั้งแต่ฉันโพสต์ความคิดเห็น (4 ปี) ดังนั้นมันขึ้นอยู่กับสิ่งที่คุณรู้สึกดีกว่า - ไม่ว่าจะเป็นในแอปพลิเคชันหรือ SQL ตัวอย่างเช่นที่ทำงานของฉันเราจัดการกับปัญหาที่คล้ายกัน แต่เรารวมทั้งวิธีการ SQL และในแอป โดยทั่วไปผมไม่สามารถช่วยคุณอื่น ๆ กว่าให้คำตอบที่ดื้อดึงและนั่นไม่ใช่สิ่งที่คุณต้องการ :)
NB

คำตอบ:


236

นี่คือตารางสาระสำคัญ

บทแนะนำที่ดีเกี่ยวกับวิธีการบรรลุเป้าหมายสามารถพบได้ที่นี่: http://www.artfulsoftware.com/infotree/qrytip.php?id=78

ผมแนะนำให้อ่านโพสต์นี้และปรับแก้ปัญหานี้ให้เหมาะกับความต้องการของคุณ

ปรับปรุง

หลังจากลิงค์ด้านบนไม่สามารถใช้งานได้อีกต่อไปฉันรู้สึกว่าจำเป็นต้องให้ข้อมูลเพิ่มเติมบางอย่างสำหรับคุณทุกคนที่ค้นหาคำตอบของ mysql pivot ในที่นี่ มีข้อมูลจำนวนมากจริง ๆ และฉันจะไม่ใส่ทุกอย่างจากที่นี่ (ยิ่งกว่านั้นเพราะฉันไม่ต้องการคัดลอกความรู้มากมาย) แต่ฉันจะให้คำแนะนำเกี่ยวกับวิธีจัดการกับเดือย ตารางวิธี sql โดยทั่วไปพร้อมตัวอย่างจาก peku ที่ถามคำถามในสถานที่แรก

บางทีลิงก์จะกลับมาเร็ว ๆ นี้ฉันจะจับตาดูมัน

วิธีสเปรดชีต ...

หลายคนใช้เครื่องมือเช่น MSExcel, OpenOffice หรือเครื่องมือสเปรดชีตอื่น ๆ เพื่อจุดประสงค์นี้ นี่เป็นทางออกที่ถูกต้องเพียงคัดลอกข้อมูลตรงนั้นและใช้เครื่องมือที่ GUI เสนอเพื่อแก้ไขปัญหานี้

แต่ ... นี่ไม่ใช่คำถามและอาจนำไปสู่ข้อเสียบางประการเช่นวิธีนำข้อมูลลงในสเปรดชีตการปรับขนาดที่มีปัญหาและอื่น ๆ

วิธี SQL ...

ให้ตารางของเขามีลักษณะดังนี้:

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;

ตอนนี้ดูที่ตารางที่ต้องการของเขา / เธอ:

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

แถว ( EMAIL, PRINT x pages) คล้ายกับเงื่อนไข company_nameการจัดกลุ่มโดยหลักคือ

เพื่อที่จะตั้งค่าเงื่อนไขนี้ค่อนข้างตะโกนสำหรับการใช้CASE-statement ในการสั่งซื้อเพื่อจัดกลุ่มตามสิ่งที่ดีใช้ GROUP BY...

SQL พื้นฐานที่ให้ pivot นี้สามารถมีลักษณะดังนี้:

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

ควรให้ผลลัพธ์ที่ต้องการอย่างรวดเร็ว ข้อเสียที่สำคัญสำหรับวิธีการนี้ยิ่งคุณต้องการแถวในตารางเดือยมากเท่าไหร่คุณก็จะต้องกำหนดเงื่อนไขเพิ่มเติมในคำสั่ง SQL ของคุณ

สิ่งนี้สามารถแก้ไขได้เช่นกันดังนั้นผู้คนมักจะใช้คำสั่งที่เตรียมไว้, กิจวัตร, ตัวนับและสิ่งที่เตรียมไว้

ลิงก์เพิ่มเติมบางส่วนเกี่ยวกับหัวข้อนี้:


4
ลิงค์ดูเหมือนจะใช้งานได้ในตอนนี้ ... ถ้ามันลงมาอีกครั้งลองเหล่านี้: แคชของ Google webcache.googleusercontent.com/หรือเครื่องอินเทอร์เน็ต Wayback ( web.archive.org/web/20070303120558 * / artfulsoftware.com/ infotree / query.php )
Lykegenes

ลิงค์นี้สามารถเข้าถึงได้ที่ url artfulsoftware.com/infotree/qrytip.php?id=78
MrPandav

1
มีอีกวิธีในการสร้างตาราง
สาระสำคัญ

คุณสามารถลบ ELSE NULL ออกจาก CASE ของคุณได้เนื่องจากหมวกเป็นพฤติกรรมเริ่มต้น (และการรวมตามเงื่อนไขเป็นคำที่เพียงพอ)
Caius Jard

86

โซลูชันของฉันอยู่ใน T-SQL โดยไม่มี pivots ใด ๆ :

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
สิ่งนี้ใช้ได้กับฉันแม้กระทั่งบน PostgreSQL ฉันชอบวิธีนี้มากกว่าการใช้ส่วนขยายอ้างอิงไขว้บน Postgres เพราะนี่สะอาดกว่า
itsols

2
"โซลูชันของฉันอยู่ใน T-SQL ที่ไม่มี pivots:"ไม่เพียง แต่ SQL Server เท่านั้นที่ควรทำงานกับผู้จำหน่ายฐานข้อมูลส่วนใหญ่ซึ่งเป็นไปตามมาตรฐาน ANSI SQL โปรดทราบว่าSUM()สามารถใช้ได้กับข้อมูลตัวเลขเท่านั้นหากคุณจำเป็นต้องใช้สตริงเดือยที่คุณจะต้องใช้MAX()
Raymond Nijland

1
ฉันคิดว่าCASEนั้นไม่จำเป็นSUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END)คุณสามารถทำได้SUM(action='PRINT' AND pagecount=1)เนื่องจากเงื่อนไขจะถูกแปลง1เป็นจริงและ0เมื่อเท็จ
kajacx

1
@kajacx ใช่ แต่จำเป็นสำหรับฐานข้อมูลที่ไม่มีการจัดการแบบบูลนั้น ได้รับตัวเลือกระหว่าง "ไวยากรณ์อีกต่อไปที่ใช้งานได้กับ dB ทั้งหมด" และ "ไวยากรณ์ที่สั้นกว่าซึ่งใช้ได้กับ ... " ฉันจะเลือกอดีต
Caius Jard

66

สำหรับ MySQL คุณสามารถใส่เงื่อนไขในการSUM()ทำงานโดยตรงและจะถูกประเมินเป็นบูลีน0หรือ1และทำให้คุณสามารถนับจำนวนตามเกณฑ์โดยไม่ต้องใช้IF/CASEคำสั่ง

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
นั่นเป็นสิ่งที่เนี้ยบจริงๆ คุณรู้หรือไม่ว่าสิ่งนี้เป็นมาตรฐานที่สอดคล้องกับแพลตฟอร์มอื่น ๆ (เช่น Postgres)
itsols

3
@itsols ไม่มีเฉพาะ Mysql เท่านั้น
M Khalid Junaid

@itsols: ผมเพิ่มอีกรุ่นของ SQL มาตรฐาน Postgres ยังมีฟังก์ชั่นเฉพาะ crosstab()
Erwin Brandstetter

2
สามารถใช้งานได้กับ SQLite
SBF

37

สำหรับเดือยแบบไดนามิกที่ใช้กับGROUP_CONCAT group_concatฟังก์ชั่นเชื่อมสตริงจากกลุ่มเป็นสตริงหนึ่งกับตัวเลือกต่างๆCONCAT

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;

สาธิตที่นี่


2
Pacerier มนุษย์ที่แท้จริง แต่สำหรับพลวัตแบบไดนามิกมันเป็นหนึ่งในวิธีที่ดีที่สุด
Abhishek Gupta

2
วิธีนี้ใช้งานได้ดีหากคุณมีค่าจำนวนมากในคอลัมน์ "การกระทำ" หรือคาดว่ารายการจะเติบโตตลอดเวลาเนื่องจากการเขียนคำสั่งกรณีสำหรับแต่ละค่าอาจใช้เวลานานและยากที่จะรักษาให้ทันสมัย
Patrick Murphy

23

รุ่นstardard-SQLโดยใช้ตรรกะบูลีน :

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;

ซอ Fiddle

อย่างไร?

TRUE OR NULLTRUEอัตราผลตอบแทน อัตราผลตอบแทน
FALSE OR NULL อัตราผลตอบแทน และนับเฉพาะค่าที่ไม่เป็นนัล voilaNULL
NULL OR NULLNULL
COUNT


@ เออร์วิน แต่คุณจะรู้ได้อย่างไรว่ามีสามคอลัมน์ เกิดอะไรขึ้นถ้ามี 5 10? 20?
Pacerier

@Pacerier: ตัวอย่างในคำถามดูเหมือนจะแนะนำว่า ทั้งสองวิธี SQL ต้องการทราบชนิดการคืนสินค้า สมบูรณ์ค้นหาแบบไดนามิกเป็นไปไม่ได้ หากจำนวนคอลัมน์เอาท์พุทสามารถเปลี่ยนแปลงได้คุณต้องมีสองขั้นตอน: วันที่ 1 สร้างแบบสอบถามอันดับที่ 2: เรียกใช้งาน
Erwin Brandstetter

11

คำตอบที่ถูกต้องคือ:

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
นี่เป็นเพียงตัวอย่างที่คุณมี โครงสร้างของother_valueตารางคืออะไร?
Patrick Murphy

1
"คำตอบที่ถูกต้องคือ:"ไม่น่าเป็นไปได้เพราะไม่มีการSETค้นหาเพื่อเพิ่มค่าเริ่มต้นซึ่ง จำกัด ที่ 1024 สำหรับ GROUP_CONCAT หลังจาก 1024 GROUP_CONCAT เพียงตัดสตริงโดยไม่มีข้อผิดพลาดซึ่งหมายความว่าผลลัพธ์ที่ไม่คาดคิดเกิดขึ้น ..
Raymond Nijland

คนที่ขอโทษไม่สามารถจำรายละเอียดเพิ่มเติมได้ ฉันทำสิ่งต่าง ๆ เพื่อความสนุกแล้วลืมหรือทำลายโครงการทั้งหมด แต่เมื่อฉันสะดุดความท้าทายฉันแบ่งปันวิธีแก้ไข ฉันรู้ว่าตัวอย่างของฉันไม่มีรายละเอียดมากนัก แต่ฉันคิดว่ามันอาจจะเป็นแนวทางให้กับผู้ที่รู้ว่าพวกเขากำลังทำอะไรอยู่ :)
Talha

9

มีเครื่องมือที่เรียกว่าตัวสร้างตาราง MySQL Pivot มันสามารถช่วยคุณสร้างตารางสาระสำคัญบนเว็บที่คุณสามารถส่งออกไปยัง excel ได้ในภายหลัง (ถ้าคุณต้องการ) มันสามารถทำงานได้หากข้อมูลของคุณอยู่ในตารางเดียวหรือในหลายตาราง

สิ่งที่คุณต้องทำคือการระบุแหล่งข้อมูลของคอลัมน์ (รองรับคอลัมน์ไดนามิก), แถว, ค่าในเนื้อความของตารางและความสัมพันธ์ของตาราง (ถ้ามี) ตาราง MySQL Pivot

โฮมเพจของเครื่องมือนี้คือ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 ;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.