如何在mysql中动态地将行旋转到列
Posted
技术标签:
【中文标题】如何在mysql中动态地将行旋转到列【英文标题】:How to pivot rows to column dynamically in mysql 【发布时间】:2021-03-28 14:42:48 【问题描述】:我遇到了一个问题,我认为我必须使用 pivot 来解决我不熟悉的问题。 如果有人能为我提供帮助,我将非常感激。
以下查询产生以下输出。 这当然是正确的。
SELECT tm.team_id AS team, pp.user_name AS name, tm.rank AS rank
FROM teams_members AS tm
LEFT JOIN players_profiles AS pp
ON pp.uid=tm.user_id
WHERE tm.team_id = 1 OR tm.team_id = 2
ORDER BY tm.team_id, tm.rank
team | name | rank |
---|---|---|
1 | 1Player1 | 1 |
1 | 1Player2 | 2 |
1 | 1Player3 | 2 |
1 | 1Player4 | 2 |
1 | 1Player5 | 3 |
1 | 1Player6 | 4 |
1 | 1Player7 | 5 |
2 | 2Player1 | 1 |
2 | 2Player2 | 2 |
2 | 2Player3 | 2 |
2 | 2Player4 | 2 |
我希望桌子看起来像这样。我如何调整查询? 有可能,等级2可以容纳无限数量的玩家。等级 1、3、4 和 5 被设置为限制为 1。
team | 1 | 2 | 2 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
1 | 1Player1 | 1Player2 | 1Player3 | 1Player4 | 1Player5 | 1Player6 | 1Player7 |
2 | 2Player1 | 2Player2 | 2Player3 | 2Player4 | |||
3 | 3Player1 | 3Player2 | 3Player3 | 3Player4 | 3Player5 | ||
4 | 4Player1 | 4Player2 | 4Player3 | 3Player4 |
感谢您的帮助。非常感谢!
【问题讨论】:
您使用的是哪个 dbms? 我正在使用 mysql 你自己尝试了什么?文档中有一个很好的示例(如果您使用 MSSQL,请参阅:docs.microsoft.com/en-us/sql/t-sql/queries/… 对于 MySQL,示例在这里:***.com/questions/7674786/… 嗨 Luuk,感谢您提供的示例。我只是一个用户,我正在尝试通过 db 获取数据,这样我就不必从前端表中获取它们。我有超过 500 行,我手动复制粘贴和排序。这需要太多时间,而且我对枢轴不太熟悉,但会更深入地研究它。 【参考方案1】:再举一个例子: DBFIDDLE
DROP TABLE IF EXISTS testPivot ;
CREATE TABLE testPivot(i int, name varchar(20), k int);
INSERT INTO testPivot VALUES
(1,'1Player1',1),
(1,'1Player2',2),
(1,'1Player3',2),
(1,'1Player4',2),
(1,'1Player5',3),
(1,'1Player6',4),
(1,'1Player7',5),
(2,'2Player1',1),
(2,'2Player2',2),
(2,'2Player3',2),
(2,'2Player4',2);
SELECT
i as team,
max(case when right(name,1)='1' then name else '' end) as '1',
max(case when right(name,1)='2' then name else '' end) as '2',
max(case when right(name,1)='3' then name else '' end) as '3',
max(case when right(name,1)='4' then name else '' end) as '4',
max(case when right(name,1)='5' then name else '' end) as '5',
max(case when right(name,1)='6' then name else '' end) as '6',
max(case when right(name,1)='7' then name else '' end) as '7'
FROM testPivot
GROUP BY i;
输出:
team | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
1 | 1Player1 | 1Player2 | 1Player3 | 1Player4 | 1Player5 | 1Player6 | 1Player7 |
2 | 2Player1 | 2Player2 | 2Player3 | 2Player4 |
编辑:在 1 列中获取组 2(我只应用了 rank==2 的更改),使用:
SELECT
i as team,
max(case when right(name,1)='1' then name else '' end) as '1',
regexp_replace(regexp_replace(regexp_replace(group_concat(case when k=2 then name else '' end),'[,]+',','),'^,',''),',$','') as '2',
-- max(case when right(name,1)='2' then name else '' end) as '2',
max(case when right(name,1)='3' then name else '' end) as '3',
max(case when right(name,1)='4' then name else '' end) as '4',
max(case when right(name,1)='5' then name else '' end) as '5',
max(case when right(name,1)='6' then name else '' end) as '6',
max(case when right(name,1)='7' then name else '' end) as '7'
FROM testPivot
GROUP BY i;
team | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
1 | 1Player1 | 1Player2,1Player3,1Player4 | 1Player3 | 1Player4 | 1Player5 | 1Player6 | 1Player7 |
2 | 2Player1 | 2Player2,2Player3,2Player4 | 2Player3 | 2Player4 |
【讨论】:
嘿,谢谢。它有很大帮助。你知道当 3 名玩家排名 2 时我如何显示名字吗?目前它只显示排名第二的第一个玩家,而不是第二或第三。【参考方案2】:MySQL 不支持 PIVOT 关系运算符。但肯定有办法在 MySQL 中透视数据。您数据中的挑战是数据透视列的非唯一性。您的输出中会有多个名称为“2”的列。
所以我通过在名称字段的最后三个后面连接团队来创建唯一性。我在这里分享您的数据的静态和动态透视。在动态枢轴中,如果您有 3 名或 10 名玩家,它会以您需要的格式提供您的数据。但是如果你的球队名单和球员名单都是固定的,那么你可以选择静态支点,因为它会更快。
在动态数据透视表中,我已将您的数据创建为表 t
。您可以将整个选择查询替换为t
。
架构:
create table t (team int, name varchar(50) ,rank int);
insert into t values(1, '1Player1', 1);
insert into t values(1, '1Player2', 2);
insert into t values(1, '1Player3', 2);
insert into t values(1, '1Player4', 2);
insert into t values(1, '1Player5', 3);
insert into t values(1, '1Player6', 4);
insert into t values(1, '1Player7', 5);
insert into t values(2, '2Player1', 1);
insert into t values(2, '2Player2', 2);
insert into t values(2, '2Player3', 2);
insert into t values(2, '2Player4', 2);
查询#1(静态枢轴)
SELECT team, MAX(IF(concat(rank,right(name,3)) = '1er1', concat(rank,name), NULL)) AS "1",
MAX(IF(concat(rank,right(name,3)) = '2er2', concat(rank,name), NULL)) AS "2",
MAX(IF(concat(rank,right(name,3)) = '2er3', concat(rank,name), NULL)) AS "2",
MAX(IF(concat(rank,right(name,3)) = '2er4', concat(rank,name), NULL)) AS "2",
MAX(IF(concat(rank,right(name,3)) = '3er5', concat(rank,name), NULL)) AS "3",
MAX(IF(concat(rank,right(name,3)) = '4er6', concat(rank,name), NULL)) AS "4",
MAX(IF(concat(rank,right(name,3)) = '5er7', concat(rank,name), NULL)) AS "5"
FROM (SELECT tm.team_id AS team, pp.user_name AS name, tm.rank AS rank
FROM teams_members AS tm
LEFT JOIN players_profiles AS pp
ON pp.uid=tm.user_id
WHERE tm.team_id = 1 OR tm.team_id = 2
ORDER BY tm.team_id, tm.rank)t
GROUP BY team
查询#2(动态枢轴)
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(IF(concat(rank,right(name,3)) = ''',
concat(rank,right(name,3)),
''', concat(rank,name), NULL)) AS ',
concat('"',rank,'"')
)
) INTO @sql
FROM t;
SET @sql = CONCAT('SELECT team
, ', @sql, '
FROM t
GROUP BY team');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
输出:
team | 1 | 2 | 2 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|
1 | 11Player1 | 21Player2 | 21Player3 | 21Player4 | 31Player5 | 41Player6 | 51Player7 |
2 | 12Player1 | 22Player2 | 22Player3 | 22Player4 | null | null | null |
db小提琴here
【讨论】:
以上是关于如何在mysql中动态地将行旋转到列的主要内容,如果未能解决你的问题,请参考以下文章