게시물을 검색하려고했지만 SQL Server / Access에 대한 솔루션 만 찾았습니다. MySQL (5.X) 솔루션이 필요합니다.
hostid, itemname, itemvalue라는 3 개의 열이있는 테이블 (히스토리라고 함)이 있습니다.
선택 ( select * from history
)을하면 반환됩니다
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
+--------+----------+-----------+
| 1 | B | 3 |
+--------+----------+-----------+
| 2 | A | 9 |
+--------+----------+-----------+
| 2 | c | 40 |
+--------+----------+-----------+
데이터베이스를 쿼리하여 다음과 같은 것을 반환하는 방법
+--------+------+-----+-----+
| hostid | A | B | C |
+--------+------+-----+-----+
| 1 | 10 | 3 | 0 |
+--------+------+-----+-----+
| 2 | 9 | 0 | 40 |
+--------+------+-----+-----+
답변
이 문제를 해결하기 위해 취해야 할 단계에 대해 좀 더 길고 자세한 설명을 추가하겠습니다. 너무 길면 사과드립니다.
나는 당신이 제공 한 기초부터 시작하여이 포스트의 나머지 부분에 사용할 몇 가지 용어를 정의하는 데 사용할 것입니다. 이것은 기본 테이블입니다 .
select * from history;
+--------+----------+-----------+
| hostid | itemname | itemvalue |
+--------+----------+-----------+
| 1 | A | 10 |
| 1 | B | 3 |
| 2 | A | 9 |
| 2 | C | 40 |
+--------+----------+-----------+
이것이 우리의 목표, 예쁜 피벗 테이블입니다 .
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
의 값 history.hostid
열이 될 것이다 y 값 피벗 테이블이다. 의 값 history.itemname
열이 될 것입니다 x 값 (분명한 이유를).
피벗 테이블을 만드는 문제를 해결해야하는 경우 3 단계 프로세스 (선택적 4 단계)를 사용하여 문제를 해결합니다.
- 관심있는 열을 선택하십시오 (예 : y- 값 및 x- 값)
- 추가 열을 사용하여 기본 테이블을 확장-각 x 값 마다 하나씩
- 확장 테이블 그룹화 및 집계-각 y- 값 에 대해 하나의 그룹
- (선택 사항) 집계 된 테이블을 확인
이 단계를 문제에 적용하고 우리가 얻는 것을 보자.
1 단계 : 관심의 선택 열 . 원하는 결과 hostid
에서 y 값 을 itemname
제공하고 x 값 을 제공 합니다 .
2 단계 : 여분의 열이 기본 테이블을 확장 . 일반적으로 x- 값당 하나의 열이 필요합니다. x- 값 열은 itemname
다음과 같습니다.
create view history_extended as (
select
history.*,
case when itemname = "A" then itemvalue end as A,
case when itemname = "B" then itemvalue end as B,
case when itemname = "C" then itemvalue end as C
from history
);
select * from history_extended;
+--------+----------+-----------+------+------+------+
| hostid | itemname | itemvalue | A | B | C |
+--------+----------+-----------+------+------+------+
| 1 | A | 10 | 10 | NULL | NULL |
| 1 | B | 3 | NULL | 3 | NULL |
| 2 | A | 9 | 9 | NULL | NULL |
| 2 | C | 40 | NULL | NULL | 40 |
+--------+----------+-----------+------+------+------+
우리는 행 수를 변경하지 않았으며 추가 열을 추가했습니다. 또한 NULL
s 의 패턴 – itemname = "A"
새 열에 대해서는 널이 아닌 값을 가지며 A
다른 새 열에 대해서는 널값을 갖는 행에 유의하십시오 .
3 단계 : 확장 테이블을 그룹화하고 집계합니다 . group by hostid
y- 값을 제공하기 때문에을 수행 해야 합니다.
create view history_itemvalue_pivot as (
select
hostid,
sum(A) as A,
sum(B) as B,
sum(C) as C
from history_extended
group by hostid
);
select * from history_itemvalue_pivot;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | NULL |
| 2 | 9 | NULL | 40 |
+--------+------+------+------+
(y- 값당 하나의 행 이 생겼습니다 .) 이제 거의 다 왔습니다 ! 우리는 그 추악한 것들을 제거해야합니다 NULL
.
4 단계 : prettify . 우리는 null 값을 0으로 대체하여 결과 집합을 더 잘 볼 수 있습니다.
create view history_itemvalue_pivot_pretty as (
select
hostid,
coalesce(A, 0) as A,
coalesce(B, 0) as B,
coalesce(C, 0) as C
from history_itemvalue_pivot
);
select * from history_itemvalue_pivot_pretty;
+--------+------+------+------+
| hostid | A | B | C |
+--------+------+------+------+
| 1 | 10 | 3 | 0 |
| 2 | 9 | 0 | 40 |
+--------+------+------+------+
그리고 우리는 끝났습니다-우리는 MySQL을 사용하여 멋진 피벗 테이블을 만들었습니다.
이 절차를 적용 할 때 고려해야 할 사항 :
- 추가 열에 사용할 값
itemvalue
이 예제에서 사용 했습니다 - 추가 열에 사용할 “중립”값 나는 사용
NULL
했지만 정확한 상황에 따라0
또는""
일 수도 있습니다. - 그룹화 할 때 사용할 집계 함수 내가 사용
sum
하지만,count
그리고max
종종 사용된다 (max
여러 행에 걸쳐 확산 있었다 하나의 행 “객체”를 구축 할 때 자주 사용된다) - y- 값에 여러 열을 사용합니다. 이 솔루션은 y 값에 단일 열을 사용하는 것으로 제한되지 않습니다-여분의 열을
group by
절에 연결하십시오 (그리고 잊지 마십시오select
).
알려진 제한 사항 :
- 이 솔루션은 피벗 테이블에서 n 개의 열을 허용하지 않습니다. 기본 테이블을 확장 할 때 각 피벗 열을 수동으로 추가해야합니다. 따라서 5 또는 10 x 값의 경우이 솔루션이 좋습니다. 100에 대해서는 그렇게 좋지 않습니다. 쿼리를 생성하는 저장 프로 시저가있는 몇 가지 솔루션이 있지만 추악하고 제대로 이해하기가 어렵습니다. 현재 피벗 테이블에 많은 열이 필요할 때이 문제를 해결하는 좋은 방법을 모릅니다.
답변
SELECT
hostid,
sum( if( itemname = 'A', itemvalue, 0 ) ) AS A,
sum( if( itemname = 'B', itemvalue, 0 ) ) AS B,
sum( if( itemname = 'C', itemvalue, 0 ) ) AS C
FROM
bob
GROUP BY
hostid;
답변
피벗해야 할 항목이 많은 경우 특히 유용한 또 다른 옵션은 mysql이 쿼리를 작성하도록하는 것입니다.
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'ifnull(SUM(case when itemname = ''',
itemname,
''' then itemvalue end),0) AS `',
itemname, '`'
)
) INTO @sql
FROM
history;
SET @sql = CONCAT('SELECT hostid, ', @sql, '
FROM history
GROUP BY hostid');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
FIDDLE
작동하는지 확인하기 위해 추가 값을 추가했습니다
GROUP_CONCAT
기본값이 1000이므로 쿼리가 너무 큰 경우 실행하기 전에이 매개 변수를 변경하십시오.
SET SESSION group_concat_max_len = 1000000;
테스트:
DROP TABLE IF EXISTS history;
CREATE TABLE history
(hostid INT,
itemname VARCHAR(5),
itemvalue INT);
INSERT INTO history VALUES(1,'A',10),(1,'B',3),(2,'A',9),
(2,'C',40),(2,'D',5),
(3,'A',14),(3,'B',67),(3,'D',8);
hostid A B C D
1 10 3 0 0
2 9 0 40 5
3 14 67 0 8
답변
문제를 해결하는 데 도움이 된 Matt Fenwick의 아이디어를 활용하여 (고마워) 하나의 쿼리로만 줄 이겠습니다.
select
history.*,
coalesce(sum(case when itemname = "A" then itemvalue end), 0) as A,
coalesce(sum(case when itemname = "B" then itemvalue end), 0) as B,
coalesce(sum(case when itemname = "C" then itemvalue end), 0) as C
from history
group by hostid
답변
하위 쿼리에서 Agung Sagita 의 답변을 편집 하여 참여합니다. 이 두 가지 방법의 차이점이 확실하지 않지만 다른 참조 용입니다.
SELECT hostid, T2.VALUE AS A, T3.VALUE AS B, T4.VALUE AS C
FROM TableTest AS T1
LEFT JOIN TableTest T2 ON T2.hostid=T1.hostid AND T2.ITEMNAME='A'
LEFT JOIN TableTest T3 ON T3.hostid=T1.hostid AND T3.ITEMNAME='B'
LEFT JOIN TableTest T4 ON T4.hostid=T1.hostid AND T4.ITEMNAME='C'
답변
하위 쿼리 사용
SELECT hostid,
(SELECT VALUE FROM TableTest WHERE ITEMNAME='A' AND hostid = t1.hostid) AS A,
(SELECT VALUE FROM TableTest WHERE ITEMNAME='B' AND hostid = t1.hostid) AS B,
(SELECT VALUE FROM TableTest WHERE ITEMNAME='C' AND hostid = t1.hostid) AS C
FROM TableTest AS T1
GROUP BY hostid
그러나 하위 쿼리가 행보다 많은 결과를 얻는 경우 하위 쿼리에서 추가 집계 함수를 사용하면 문제가됩니다.
답변
내 해결책 :
select h.hostid, sum(ifnull(h.A,0)) as A, sum(ifnull(h.B,0)) as B, sum(ifnull(h.C,0)) as C from (
select
hostid,
case when itemName = 'A' then itemvalue end as A,
case when itemName = 'B' then itemvalue end as B,
case when itemName = 'C' then itemvalue end as C
from history
) h group by hostid
제출 된 사례에서 예상 결과를 생성합니다.