Tổng hợp hàng MySQL thành số cột động


81

Giả sử tôi có ba bảng MySQL khác nhau:

Bảng products:

id | name
 1   Product A
 2   Product B

Bảng partners:

id | name
 1   Partner A
 2   Partner B

Bảng sales:

partners_id | products_id
          1             2
          2             5
          1             5
          1             3
          1             4
          1             5
          2             2
          2             4
          2             3
          1             1

Tôi muốn có một bảng với các đối tác trong các hàng và sản phẩm dưới dạng cột. Cho đến nay tôi đã có thể nhận được đầu ra như thế này:

name      | name      | COUNT( * )
Partner A   Product A          1
Partner A   Product B          1
Partner A   Product C          1
Partner A   Product D          1
Partner A   Product E          2
Partner B   Product B          1
Partner B   Product C          1
Partner B   Product D          1
Partner B   Product E          1

Sử dụng truy vấn này:

SELECT partners.name, products.name, COUNT( * ) 
FROM sales
JOIN products ON sales.products_id = products.id
JOIN partners ON sales.partners_id = partners.id
GROUP BY sales.partners_id, sales.products_id
LIMIT 0 , 30

nhưng thay vào đó tôi muốn có một cái gì đó như:

partner_name | Product A | Product B | Product C | Product D | Product E
Partner A              1           1           1           1           2
Partner B              0           1           1           1           1

Vấn đề là tôi không thể biết tôi sẽ có bao nhiêu sản phẩm nên số cột cần thay đổi động tùy thuộc vào các hàng trong bảng sản phẩm.

Câu trả lời rất hay này dường như không hoạt động với mysql: T-SQL Pivot? Khả năng tạo cột bảng từ các giá trị hàng


Tham khảo liên kết Hàng đến Cột để có nhiều đề xuất.
Bhavin Pokiya


@BhavinPokiya là liên kết MS SQL-Server mà bạn đã cung cấp, trong khi liên kết này được gắn thẻ là MySQL.
MattSom

Câu trả lời:


107

Thật không may, MySQL không có một PIVOTchức năng về cơ bản là những gì bạn đang cố gắng thực hiện. Vì vậy, bạn sẽ cần sử dụng một hàm tổng hợp với một CASEcâu lệnh:

select pt.partner_name,
  count(case when pd.product_name = 'Product A' THEN 1 END) ProductA,
  count(case when pd.product_name = 'Product B' THEN 1 END) ProductB,
  count(case when pd.product_name = 'Product C' THEN 1 END) ProductC,
  count(case when pd.product_name = 'Product D' THEN 1 END) ProductD,
  count(case when pd.product_name = 'Product E' THEN 1 END) ProductE
from partners pt
left join sales s
  on pt.part_id = s.partner_id
left join products pd
  on s.product_id = pd.prod_id
group by pt.partner_name

Xem SQL Demo

Vì bạn không biết Sản phẩm nên có thể bạn sẽ muốn thực hiện việc này một cách linh hoạt. Điều này có thể được thực hiện bằng cách sử dụng các câu lệnh chuẩn bị sẵn.

Với bảng tổng hợp động (chuyển đổi hàng thành cột), mã của bạn sẽ giống như sau:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'count(case when Product_Name = ''',
      Product_Name,
      ''' then 1 end) AS ',
      replace(Product_Name, ' ', '')
    )
  ) INTO @sql
from products;

SET @sql = CONCAT('SELECT pt.partner_name, ', @sql, ' from partners pt
left join sales s
  on pt.part_id = s.partner_id
left join products pd
  on s.product_id = pd.prod_id
group by pt.partner_name');

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

Xem SQL Demo

Có lẽ điều đáng chú ý GROUP_CONCATlà theo mặc định bị giới hạn ở 1024 byte. Bạn có thể giải quyết vấn đề này bằng cách đặt nó cao hơn trong suốt thời gian quy trình của bạn, tức là.SET @@group_concat_max_len = 32000;


2
Bình luận ở cuối về "max_len" là một cứu cánh! Cảm ơn vì tiền hỗ trợ.
Edward

1
nếu bạn đang tìm kiếm năng động hơn các truy vấn trục lòng kiểm tra này: boynux.com/creating-pivot-reports-in-mysql
Boynux

Điều gì xảy ra nếu tên sản phẩm làProductA') from partners pt; truncate partners;
avatarofhope2

@ avatarofhope2 Đây là một câu hỏi hay một hàm ý? Nếu điều này cho một góc phun, cách thích hợp để xử lý nó là gì?
MattSom
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.