0


SQL之行列转置以及非常规的行列转置

一、准备工作

  1. # 创建数据表
  2. CREATE TABLE ChengJi
  3. (
  4. Name varchar(32),
  5. Subject varchar(32),
  6. Result int(10)
  7. );
  8. # 插入数据
  9. insert into ChengJi
  10. values ('张三', '语文', 80),
  11. ('张三', '数学', 90),
  12. ('张三', '物理', 85),
  13. ('李四', '语文', 85),
  14. ('李四', '数学', 92),
  15. ('李四', '物理', 82);

二、行转列

整体分两步走

1、先预处理数据,将数据进行初步的行转列,便于后续的分组处理

  1. select Name,
  2. case
  3. when Subject = '语文' then Result else 0
  4. end as 'Chinese',
  5. case
  6. when Subject = '数学' then Result else 0
  7. end as 'Math',
  8. case
  9. when Subject = '物理' then Result else 0
  10. end as 'Pha'
  11. from ChengJi;

2、对预处理完毕的数据进行分组聚合,使多行数据汇聚到一个组内,达到数据集中的结果,这其中要注意的一点是:要明确按照哪个字段进行聚合操作。

  1. with t1 as(select Name,
  2. case
  3. when Subject = '语文' then Result else 0
  4. end as 'Chinese',
  5. case
  6. when Subject = '数学' then Result else 0
  7. end as 'Math',
  8. case
  9. when Subject = '物理' then Result else 0
  10. end as 'Pha'
  11. from ChengJi)
  12. select Name,
  13. sum(Chinese) as 'Chinese',
  14. sum(Math) as 'Math',
  15. sum(Pha) as 'Pha'
  16. from t1
  17. group by Name;

三、列转行

为便于理解,我们将刚才已经转置好的结果插入到一个结果表内

1、创建一个结果表

  1. create table ChengJi_2(
  2. Name varchar(255),
  3. Chinese int,
  4. Math int,
  5. Pha int
  6. );

2、将行转列结果插入到结果表

  1. insert into chengji_2
  2. with t1 as(select Name,
  3. case
  4. when Subject = '语文' then Result else 0
  5. end as 'Chinese',
  6. case
  7. when Subject = '数学' then Result else 0
  8. end as 'Math',
  9. case
  10. when Subject = '物理' then Result else 0
  11. end as 'Pha'
  12. from ChengJi)
  13. select Name,
  14. sum(Chinese) as 'Chinese',
  15. sum(Math) as 'Math',
  16. sum(Pha) as 'Pha'
  17. from t1
  18. group by Name
  19. ;

3、对结果表进行列转行的操作,列转行相对于行转列较为简单,可直接使用 union all 进行操作。

  1. select Name,Chinese from ChengJi_2
  2. union all
  3. select Name,Math from ChengJi_2
  4. union all
  5. select Name,Pha from ChengJi_2;

四、特殊的列转行/行转列

但是对于一些特殊的行列转置,以上方法就不再使用,通常情况下,我们的行列转置是有可以进行分组聚合操作可以完成的,而生产实践中也多数如此,但是有时有一些特殊的操作是以上方法无法完成的,这就需要一些特殊的行列转置来完成,对此,我给出了以下的方案。

1、准备工作,创建数据表并插入数据

  1. CREATE TABLE 2003a
  2. (
  3. seat varchar(255) ,
  4. status varchar(255) ,
  5. rowid varchar(255)
  6. )
  7. ;
  8. INSERT INTO 2003a
  9. VALUES ('2', '已预订', 'A');
  10. INSERT INTO 2003a
  11. VALUES ('3', '未预订', 'A');
  12. INSERT INTO 2003a
  13. VALUES ('4', '未预订', 'A');
  14. INSERT INTO 2003a
  15. VALUES ('5', '未预订', 'A');
  16. INSERT INTO 2003a
  17. VALUES ('6', '未预订', 'B');
  18. INSERT INTO 2003a
  19. VALUES ('7', '未预订', 'B');
  20. INSERT INTO 2003a
  21. VALUES ('8', '未预订', 'B');
  22. INSERT INTO 2003a
  23. VALUES ('9', '未预订', 'B');
  24. INSERT INTO 2003a
  25. VALUES ('10', '未预订', 'B');
  26. INSERT INTO 2003a
  27. VALUES ('11', '未预订', 'C');
  28. INSERT INTO 2003a
  29. VALUES ('12', '已预订', 'C');
  30. INSERT INTO 2003a
  31. VALUES ('13', '已预订', 'C');
  32. INSERT INTO 2003a
  33. VALUES ('14', '未预订', 'C');
  34. INSERT INTO 2003a
  35. VALUES ('15', '未预订', 'C');
  36. INSERT INTO 2003a
  37. VALUES ('16', '未预订', 'D');
  38. INSERT INTO 2003a
  39. VALUES ('17', '未预订', 'D');
  40. INSERT INTO 2003a
  41. VALUES ('18', '未预订', 'D');
  42. INSERT INTO 2003a
  43. VALUES ('19', '未预订', 'D');
  44. INSERT INTO 2003a
  45. VALUES ('20', '已预订', 'D');

2、明确需求

原有表的结构:

  1. 2,已预订,A
  2. 3,未预订,A

需要完成的工作:

  1. 2,3
  2. 已预定,未预定
  3. A,A

在这里我们可以很明显的看出,我们需要做的就是如何进行 行转列/列转行 的操作,在这里的行列转置是整行/整列进行转置,不再是依靠某个字段进行分组处理或者使用 union all 进行整体操作,因此,我是用以下方案来完成。

1、对原表字段进行 group_concat,指定 “,”为字段值之间的分隔符

  1. SELECT
  2. GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
  3. GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
  4. GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
  5. FROM (
  6. SELECT rowid, status, seat from `2003a`
  7. ) AS subquery

2、将所有的字段按照值聚合到一个数据表格内之后,我们可以使用 union all 来进行字段拆分

  1. with t1 as (SELECT
  2. GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
  3. GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
  4. GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
  5. FROM (
  6. SELECT rowid, status, seat from `2003a`
  7. ) AS subquery)
  8. select seat from t1
  9. union all
  10. select status from t1
  11. union all
  12. select rowid from t1

3、使用 SUBSTRING_INDEX来进行拆分,将所有的字段值拆分成单独的值

  1. with t1 as (SELECT
  2. GROUP_CONCAT(rowid ORDER BY rowid ASC SEPARATOR ', ') AS rowid,
  3. GROUP_CONCAT(status ORDER BY rowid ASC SEPARATOR ', ') AS status,
  4. GROUP_CONCAT(seat ORDER BY rowid ASC SEPARATOR ', ') AS seat
  5. FROM (
  6. SELECT rowid, status, seat from `2003a`
  7. ) AS subquery)
  8. ,t2 as (select seat from t1
  9. union all
  10. select status from t1
  11. union all
  12. select rowid from t1)
  13. select SUBSTRING_INDEX(seat,',',1) as p1,
  14. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',2),',',-1) as p2,
  15. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',3),',',-1) as p3,
  16. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',4),',',-1) as p4,
  17. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',5),',',-1) as p5,
  18. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',6),',',-1) as p6,
  19. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',7),',',-1) as p7,
  20. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',8),',',-1) as p8,
  21. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',9),',',-1) as p9,
  22. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',10),',',-1) as p10,
  23. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',11),',',-1) as p11,
  24. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',12),',',-1) as p12,
  25. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',13),',',-1) as p13,
  26. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',14),',',-1) as p14,
  27. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',15),',',-1) as p15,
  28. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',16),',',-1) as p16,
  29. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',17),',',-1) as p17,
  30. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',18),',',-1) as p18,
  31. SUBSTRING_INDEX(SUBSTRING_INDEX(seat,',',19),',',-1) as p19
  32. from t2

在这里需要注意的是:第一个SUBSTRING_INDEX我们取的是源数据的第一个值,第二个SUBSTRING_INDEX以及之后的,我们取得是源数据的倒数第一个值,因此这里需要注意一下我们给到的是“-1”

至此,我们使用group_concat()以及SUBSTRING_INDEX()来达到了特殊的行列转置操作。

标签: sql 数据库

本文转载自: https://blog.csdn.net/zxcvbnm0207/article/details/139672962
版权归原作者 yangjiwei0207 所有, 如有侵权,请联系我们删除。

“SQL之行列转置以及非常规的行列转置”的评论:

还没有评论