如何在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中动态地将行旋转到列的主要内容,如果未能解决你的问题,请参考以下文章

如何将行旋转到列(自定义旋转)

SQL - 将行旋转到列并采用笛卡尔积

动态地将行旋转到红移中的列

AJAX如何动态地将行添加到表中

当我单击添加行按钮时,如何在 html 中动态地将行添加到表单中?

MySQL 动态地将行转为列