具有列标题和计数的列名/基于其他表中列标签的数据透视

Posted

技术标签:

【中文标题】具有列标题和计数的列名/基于其他表中列标签的数据透视【英文标题】:Column name with column caption and count / Pivot based on column label in other table 【发布时间】:2014-01-24 03:06:33 【问题描述】:

我有两张表如下:

TABLE 标记列表:

student_id  class_id    subject_1   subject_2   subject_3   subject_4   subject_5
----------- ----------- ----------- ----------- ----------- ----------- ----------
1           9           78          87                                  95
2           9           67          95                                    87
3           9           85          84                                    85
4           10          70                      65          78    
5           10          75                      80          81    
6           10          80                      75          82    

表 subject_names

column_name     subject_name
--------------- -------------
subject_1       English
subject_2       Chemistry
subject_3       Economics
subject_4       Accounts
subject_5       Biology

现在,我需要为 class_id = 9 生成这样的报告

column_name     subject_name  no_of_students
--------------- ------------- --------------
subject_1       English       3
subject_2       Chemistry     3
subject_3       Economics     0
subject_4       Accounts      0
subject_5       Biology       3

简而言之,我必须生成一份报告,其中包含 column_names、subject_name 和 class_id = 9(或 10,随便)的学生数量,这些学生已经出现在该主题中。

我所做的只是

1.

    SELECT sn.column_name, sn.subject_name FROM subject_names sn;

2.

    SELECT ml.class_id,
           count(ml.subject_1) AS s1,
           count(ml.subject_2) AS s1,
           count(ml.subject_3) AS s1,
           count(ml.subject_4) AS s1,
           count(ml.subject_5) AS s1,
      FROM marklist ml
     WHERE ml.class_id = 9;

我不明白如何继续使用查询 1 旋转查询 2 的结果。我可能走错了方向,但我不知道。

【问题讨论】:

从长远来看,进一步规范化数据可能会为您提供更好的服务;重复的列通常是设计缺陷的标志。 @Clockwork-Muse- 有时我们都有义务接受事物的本来面目而不改变它们,不是吗?这对我来说就是其中之一。 【参考方案1】:

你可以unpivot你的marklist表和外连接它与subject_names表。

with unpivot_x(student_id,class_id,subject_code,marks) as (
    select * from marklist
    unpivot (marks for subject_code in (  subject_1 as 'subject_1',
                                          subject_2 as 'subject_2',
                                          subject_3 as 'subject_3',
                                          subject_4 as 'subject_4',
                                          subject_5 as 'subject_5'
                                      )
                                      ))
select a.column_name,a.subject_name, count(b.student_id)
  from subject_names a left outer join unpivot_x b
    on a.column_name = b.subject_code and b.class_id = 9
 group by a.column_name,a.subject_name
 order by 1;

sqlfiddle 上的演示。

【讨论】:

您的回答绝对有用,但在您发布之前,我自己已经找到了解决方案。无论如何,谢谢。【参考方案2】:

试试这个

SELECT a.column_name, a.subject_name, COUNT( subject_1 ) 
FROM subject_names a
JOIN mark_list b ON b.class_id =9
AND a.subject_name =  'English'
GROUP BY a.subject_name
UNION ALL SELECT a.column_name columnname, a.subject_name, COUNT( subject_3 ) 
FROM subject_names a
JOIN mark_list b ON b.class_id =9
AND a.subject_name =  'Chemistry'
GROUP BY a.subject_name
UNION ALL SELECT a.column_name columnname, a.subject_name, COUNT( subject_4 ) 
FROM subject_names a
JOIN mark_list b ON b.class_id =9
AND a.subject_name =  'Economics'
GROUP BY a.subject_name UNION ALL 
SELECT a.column_name columnname, a.subject_name, COUNT( subject_2 ) 
FROM subject_names a
JOIN mark_list b ON b.class_id =9
AND a.subject_name =  'Accounts'
GROUP BY a.subject_name
UNION ALL 
SELECT a.column_name columnname, a.subject_name, COUNT( subject_1 ) 
FROM subject_names a
JOIN mark_list b ON b.class_id =9
AND a.subject_name =  'Biology'
GROUP BY a.subject_name

【讨论】:

怎么样?你这么说的依据是什么? 使用join来检索结果。【参考方案3】:

我找到了答案。您可以跳过 CTE 并检查以下主要查询:

/* -- This WITH clause is just for your reference.
WITH marklist AS (
SELECT 1 student_id, 9 class_id, 78 subject_1,87 subject_2,
       null subject_3, null subject_4, 95 subject_5 FROM dual
UNION ALL SELECT 2, 9, 67,95, null, null, 87 FROM dual
UNION ALL SELECT 3, 9, 85,84, null, null, 85 FROM dual
UNION ALL SELECT 4, 10,70, null, 65,78, null FROM dual
UNION ALL SELECT 5, 10,75, null, 80,81, null FROM dual
UNION ALL SELECT 6, 10,80, null, 75,82, null FROM dual
)
, subject_names AS (
SELECT 'subject_1' column_name, 'English' subject_name FROM dual
UNION ALL SELECT 'subject_2', 'Chemistry' FROM dual
UNION ALL SELECT 'subject_3', 'Economics' FROM dual
UNION ALL SELECT 'subject_4', 'Accounts' FROM dual
UNION ALL SELECT 'subject_5', 'Biology' FROM dual
) -- */
SELECT sn.column_name, sn.subject_name,
       (SELECT COUNT(CASE sn.column_name
                        WHEN 'subject_1' THEN ml.subject_1
                        WHEN 'subject_2' THEN ml.subject_2
                        WHEN 'subject_3' THEN ml.subject_3
                        WHEN 'subject_4' THEN ml.subject_4
                        WHEN 'subject_5' THEN ml.subject_5
                      END)
           FROM marklist ml
          WHERE ml.class_id = 9) AS no_of_students
  FROM subject_names sn;

输出:

column_name    subject_name    no_of_students
-------------- --------------- --------------
subject_1      English         3
subject_2      Chemistry       3
subject_3      Economics       0
subject_4      Accounts        0
subject_5      Biology         3

【讨论】:

以上是关于具有列标题和计数的列名/基于其他表中列标签的数据透视的主要内容,如果未能解决你的问题,请参考以下文章

2020年2月22日-日报

修改表中列

oracle中列中的数据求和

更改列名的几种方法在数据库中

雪花数据库:想要使用表中列的值作为另一个表的选择语句中的列名

Big Query Tables 中列的默认值