MySQL에서 피벗 테이블 출력을 어떻게 반환합니까?


312

다음과 같은 MySQL 테이블이있는 경우 :

company_name 작업 페이지 수
-------------------------------
회사 A 인쇄 3
회사 A 인쇄 2
회사 A 인쇄 3
회사 B 이메일   
회사 B 인쇄 2
회사 B 인쇄 2
회사 B 인쇄 1
회사 A 인쇄 3

MySQL 쿼리를 실행하여 다음과 같은 출력을 얻을 수 있습니까?

company_name 이메일 인쇄 1 페이지 인쇄 2 페이지 인쇄 3 페이지
-------------------------------------------------- -----------
회사 A 0 1 3
회사 B 1 1 0

아이디어 즉 pagecount출력 열의 양이 그 하나의 각 열에 반영해야하므로 달라질 수 action/에 pagecount따라 적중 한 후 한쌍 참조 company_name. 이것이 피벗 테이블인지 확실하지 않지만 누군가가 제안 했습니까?


3
피벗이라고하며 SQL 외부에서이 변환을 수행하는 것이 훨씬 더 빠릅니다.
NB

1
엑셀에는 "CROSSTAB"연산자 :( 없기 때문에 그것은 MySQL은 정말 어려운 일이 같은 것들을 통해 입술
데이브 릭스

예, 현재 Excel에서 직접 작성했으며 자동화하려고합니다.
peku

3
여기서는 단계별 예제를 발견했습니다 . 피벗 테이블을 자동화하는 방법 . 그리고 이것
Devid G

1
@giannischristofakis-그것은 당신과 당신의 동료가 더 단순하다고 생각하는 것에 달려 있습니다. 주석 (4 년)을 게시 한 이후 기술이 상당히 많이 사용되었으므로 응용 프로그램이나 SQL에서 의견이 더 좋습니다. 예를 들어, 우리는 비슷한 문제를 다루지 만 SQL과 인앱 접근법을 결합하고 있습니다. 기본적으로, 나는 의견을 제시하는 것 외에는 당신을 도울 수 없으며 그것은 당신이 필요로하지 않습니다 :)
NB

답변:


236

이것은 기본적 이다 피벗 테이블.

이것을 달성하는 방법에 대한 좋은 튜토리얼은 여기에서 찾을 수 있습니다 : http://www.artfulsoftware.com/infotree/qrytip.php?id=78

이 게시물을 읽고이 솔루션을 필요에 맞게 조정하는 것이 좋습니다.

최신 정보

위의 링크를 더 이상 사용할 수 없으면 여기에서 mysql 피벗 답변을 검색하는 모든 사용자에게 추가 정보를 제공해야한다고 생각합니다. 그것은 실제로 방대한 양의 정보를 가지고 있었고, 여기에 모든 것을 넣지 않을 것입니다 (심지어 방대한 지식을 복사하고 싶지 않기 때문에). 그러나 피벗을 다루는 방법에 대한 조언을 줄 것입니다. 처음에는 질문을 한 peku의 예제와 함께 일반적으로 SQL 방식을 표로 표시합니다.

어쩌면 링크가 곧 다시 올 수 있습니다. 계속 주시하겠습니다.

스프레드 시트 방식 ...

많은 사람들이이 목적으로 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은 다음과 같습니다.

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
그것은 다시 다운되면 링크가 지금 작동하는 것 같다 ... 이런 시도 : 구글의 캐시 webcache.googleusercontent.com/... 또는 인터넷 뒤로 머신 ( web.archive.org/web/20070303120558 * / artfulsoftware.com/을 infotree / queries.php )
Lykegenes

링크는이 URL에서 액세스 할 수 있습니다 artfulsoftware.com/infotree/qrytip.php?id=78
MrPandav

1
"if", "case"또는 "GROUP_CONCAT"를 사용하지 않고 피벗 테이블을 생성하는 다른 방법이 있습니다. en.wikibooks.org/wiki/MySQL/Pivot_table
user2513149

모자가 기본 동작이므로 조건부 집계가 충분하므로 CASE에서 ELSE NULL을 제거 할 수 있습니다.
Caius Jard

86

내 솔루션은 피벗없이 T-SQL에 있습니다.

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에서도 작동합니다. 이 같이 내가 포스트 그레스에 크로스 탭 확장자를 사용하는 것보다이 방법을 선호하는 청소기
itsols

2
"제 솔루션은 피벗없이 T-SQL에 있습니다." SQL Server뿐만 아니라 ANSI SQL 표준을 따르는 대부분의 데이터베이스 공급 업체에서도 작동해야합니다. 참고 SUM()이 피벗 문자열로 네드 경우 숫자 데이터 만 일을 당신이 할 수있는 사용하기MAX()
레이몬드 Nijland

1
나는 CASE 가 불필요 하다고 생각합니다 . 조건이 참일 때 와 거짓 SUM(CASE WHEN (action='PRINT' AND pagecount=1) THEN 1 ELSE 0 END)SUM(action='PRINT' AND pagecount=1)10
때로

1
@kajacx 예, 그런 종류의 부울 조작이없는 데이터베이스에서는 필요합니다. 그리고 "만에 ... 작동 짧은 구문"나는 이전 선택할 것 "모든 dB의 작품이 그 이상 구문"사이에서 선택을 감안할 때
카이 우스 JARD

66

MySQL을위한 직접에 조건을 넣을 수 있습니다 SUM()기능과이를됩니다 부울로 평가 01 때문에 당신은 사용하지 않고 카운트가 당신의 기준에 따라 할 수 있습니다 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 칼리드 Junaid

@itsols : 다른 표준 SQL 버전을 추가했습니다 . Postgres에는 전용 crosstab()기능도 있습니다.
Erwin Brandstetter

2
SQLite에도 작동
SBF

37

동적 피벗의 경우 GROUP_CONCAT와 함께 사용하십시오 CONCAT. GROUP_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 굽타

2
"조치"열에 많은 값이 있거나 시간이 지남에 따라 목록이 커질 것으로 예상되는 경우 각 값에 대한 사례 설명을 작성하는 데 시간이 오래 걸리고 최신 상태를 유지하기가 어려울 수 있습니다.
패트릭 머피

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;

SQL 바이올린.

어떻게?

TRUE OR NULL 수율 TRUE.
FALSE OR NULL수율 NULL.
NULL OR NULL수율 NULL.
그리고 COUNT단지 null 이외의 값을 계산합니다. 보일라


@ Erwin, 그러나 세 개의 열이 있다는 것을 어떻게 알 수 있습니까? 5가 있다면? 10? 20?
Pacerier

@Pacerier : 질문의 예가 ​​그것을 제안하는 것 같습니다. 어느 쪽이든, SQL이 요구 반환 형식을 알 수 있습니다. 완전히 동적 쿼리 할 수 없습니다. 출력 열의 수가 달라질 수있는 경우 두 번째 단계가 필요합니다. 첫 번째는 쿼리를 빌드하고 두 번째는 실행합니다.
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테이블 의 구조는 무엇입니까 ?
패트릭 머피

1
"정답은 다음과 같습니다."SET 1024 이후 GROUP_CONCAT에 대해 1024로 제한되는 기본 값을 증가시키는 쿼리 가 누락되지 않았기 때문에 GROUP_CONCAT은 단순히 오류없이 문자열을 자르고 예기치 않은 결과가 발생할 수 있음을 의미합니다.
Raymond Nijland

죄송합니다. 자세한 내용을 기억할 수 없습니다. 나는 재미를 위해 일을 한 다음 전체 프로젝트를 잊거나 파괴합니다. 그러나 도전에 걸려 넘어지면 어떻게 해결했는지에 대해 이야기합니다. 나는 나의 예가 매우 상세하지는 않다는 것을 알고 있지만 그것이 반대하는 것을 아는 사람들에게 방향을 제시 할 수있을 것 같다 :)
Talha

9

MySQL Pivot 테이블 생성기라는 도구가 있으며 나중에 원하는 경우 Excel로 내보낼 수있는 웹 기반 피벗 테이블을 만들 수 있습니다. 데이터가 단일 테이블 또는 여러 테이블에있는 경우 작동 할 수 있습니다.

열의 데이터 소스 (동적 열을 지원함), rows, 테이블 본문의 값 및 테이블 관계 (있는 경우)를 지정하기 만하면됩니다. MySQL 피벗 테이블

이 도구의 홈 페이지는 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.