将每个字段的行进行解构并对齐

huangapple go评论73阅读模式
英文:

Unpivot and align rows for each field

问题

如何将表中每个字段的行和属性对齐,使其在同一行中显示,以给定的表作为示例?请注意,此表中的所有字段均为varchar,以确保一致性。

STD SUBJECT MARKS COMMENT TDATE
ST1 MATH 25% POOR 1/02/2021
ST1 ENGLISH 88% DIST 2/02/2021
ST1 SCIENCE 56% PASS 4/02/2021

在将[Subject]中的内容解除枢轴操作后,表格应该如下所示:

STD MATH COMMENT TDATE ENGLISH COMMENT TDATE SCIENCE COMMENT TDATE
ST1 25% POOR 1/02/2021 88% DIST 2/02/2021 56% PASS 4/02/2021

我尝试了我的代码,并出现了许多错误,所以也许我可以得到一些帮助来实现所需的结果。

英文:

How can I align the rows and attributes of each field in a table to appear in the same line, using the given table as an example?. Mark this all fields in this table are varchar so as to enable uniformity.

STD SUBJECT MARKS COMMENT TDATE
ST1 MATH 25% POOR 1/02/2021
ST1 ENGLISH 88% DIST 2/02/2021
ST1 SCIENCE 56% PASS 4/02/2021

The table should appear like this after unpivoting the contents in [Subject]:

STD MATH COMMENT TDATE ENGLISH COMMENT TDATE SCIENCE COMMENT TDATE
ST1 25% POOR 1/02/2021 88% DIST 2/02/2021 56% PASS 4/02/2021

I tried with my code and got lots of errors, so maybe I could get some help to achieve the desired result.

         SELECT
             [MATH],
             [ENGLISH],
             [SCIENCE]
         FROM (
             SELECT
                 STD, stdn,
                 cont,
                 x,
                 SUBJECT
             FROM
                 [dbo].[Exam]
             UNPIVOT (
                 x
                 for cont in (COMMENT, TDATE)
             ) a
        ) a
        PIVOT (
           MAX(x) 
           FOR SUBJECT IN (
                [MATH],
                [ENGLISH],
                [SCIENCE],
            )
        ) p
        WHERE p.stdn IN (SELECT STD FROM [dbo].[exam])

答案1

得分: 1

我认为当我使用MAX(CASE)时解决了它

SELECT [STD], 
    MAX(CASE WHEN SUBJECT = 'MATH' THEN MARKS ELSE '' END) MATH,
    MAX(CASE WHEN SUBJECT = 'MATH' THEN COMMENT ELSE '' END) COMMENT,
    MAX(CASE WHEN SUBJECT = 'MATH' THEN TDATE ELSE '' END) TDATE ,
   
    MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN MARKS ELSE '' END) ENGLISH,
    MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN COMMENT ELSE '' END) COMMENT,
    MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN TDATE ELSE '' END) TDATE ,

    MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN MARKS ELSE '' END) SCIENCE,
    MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN COMMENT ELSE '' END) COMMENT,
    MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN TDATE ELSE '' END) TDATE 

FROM [dbo].[EXAM]  GROUP BY STD
英文:

i think i solved it when i used MAX(CASE)

  		SELECT [STD], 
		 MAX(CASE WHEN SUBJECT = 'MATH' THEN MARKS ELSE '' END) MATH,
		 MAX(CASE WHEN SUBJECT = 'MATH' THEN COMMENT ELSE '' END) COMMENT,
		 MAX(CASE WHEN SUBJECT = 'MATH' THEN TDATE ELSE '' END) TDATE ,
   
		 MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN MARKS ELSE '' END) ENGLISH,
	     MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN COMMENT ELSE '' END) COMMENT,
         MAX(CASE WHEN SUBJECT = 'ENGLISH' THEN TDATE ELSE '' END) TDATE ,
    
         MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN MARKS ELSE '' END) SCIENCE,
         MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN COMMENT ELSE '' END) COMMENT,
         MAX(CASE WHEN SUBJECT = 'SCIENCE' THEN TDATE ELSE '' END) TDATE 

	FROM [dbo].[EXAM]  GROUP BY STD 

答案2

得分: 0

用于演示的数据透视在SQL中并不太适合,通常最好由“前端”或“报表工具”来执行,尽管如此,仍然可以使用T-SQL来进行数据透视。

我假设一个未明示的要求是要按特定的从左到右的“块序列”“科目-分数-评论-日期”的顺序呈现列,因此需要一种方法来组织这些列的顺序。另一个可能的要求是透视要适应未知数量的总列数,为此,您需要使用“动态SQL”。

注意:由于涉及不同的数据类型,这个“逆透视”变得复杂,一种避免这个问题的方法是将所有数据转换为字符串或sql_variant(下面是这种方法)。另一种方法(我更喜欢的方法)是使用JSON 在这里解释,但我也无法控制此查询所需的“rnk”值,以制定列的数字顺序。

因此,提出以下解决方案:

DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);
    
SELECT @cols = STUFF((SELECT ',' + quotename(concat(c.column_name, cj.rn))
            from INFORMATION_SCHEMA.COLUMNS c
            cross join (
                select row_number() over(order by subject) rn
                from (select distinct subject from exam) e
                ) cj
            WHERE c.TABLE_NAME = 'Exam'
            AND c.column_name <> 'STD'
            order by cj.rn, c.ORDINAL_POSITION
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');
    
SET @query = 'SELECT STD, ' + @cols + ' 
            from 
            (
                SELECT STD, 
                       concat(COLUMN_NAME,rnk) as COLUMN_NAME, 
                       VALUE
                FROM
                (
                    SELECT STD, 
                           CAST(SUBJECT AS sql_variant) AS SUBJECT, 
                           CAST(MARKS AS sql_variant) AS MARKS, 
                           CAST(COMMENT AS sql_variant) AS COMMENT, 
                           CAST(convert(varchar(10), TDATE ,120) AS sql_variant) AS TDATE,
                           dense_rank() over(partition by STD order by MARKS) as rnk
                    FROM Exam
                ) AS subquery
                UNPIVOT
                (
                    VALUE
                    FOR COLUMN_NAME IN (SUBJECT, MARKS, COMMENT, TDATE)
                ) AS unpvt
            ) x
            pivot 
            (
                max(VALUE)
                for COLUMN_NAME in (' + @cols + ')
            ) p ';
    
EXECUTE(@query);
STD SUBJECT1 MARKS1 COMMENT1 TDATE1 SUBJECT2 MARKS2 COMMENT2 TDATE2 SUBJECT3 MARKS3 COMMENT3 TDATE3
ST1 MATH 25% POOR 2021-02-01 SCIENCE 56% PASS 2021-02-04 ENGLISH 88% DIST 2021-02-02

在这里查看演示

注意:由于我最终将日期列转换为字符串以控制格式,您可以将“as sql_variant”替换为“as varchar(100)”(100是一个猜测的长度)。

英文:

Pivots for presentation purposes are not well suited to SQL and often better performed by a "front end" or "reporting tool" despite this, it is possible to pivot this data using T-SQL.

I assume that an unstated requirement is that the columns are presented in a specific left-to-right "block sequence" of "subject-mark-comment-tdate" so there needs to be a way to organize the columns in that sequence. A further probable requirement is that the pivot cater for an unknown number of total columns, for this you need "dynamic sql".

Note: This "unpivot" is complicated by the fact that there are different data types involved, one way to avoid this is to cast all data to strings or sql_variant (which is the approach seen below). Another (that I prefer) is to use JSON explained here but I wasn't also able to control the the "rnk" value as I needed for this query to formulate the numeric sequence of columns.

So, this is proposed:

DECLARE @cols AS NVARCHAR(MAX), @query AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT &#39;,&#39; + quotename(concat(c.column_name, cj.rn))
            from INFORMATION_SCHEMA.COLUMNS c
            cross join (
                select row_number() over(order by subject) rn
                from (select distinct subject from exam) e
                ) cj
            WHERE c.TABLE_NAME = &#39;Exam&#39;
            AND c.column_name &lt;&gt; &#39;STD&#39;
            order by cj.rn, c.ORDINAL_POSITION
            FOR XML PATH(&#39;&#39;), TYPE
            ).value(&#39;.&#39;, &#39;NVARCHAR(MAX)&#39;) 
        ,1,1,&#39;&#39;);

SET @query = &#39;SELECT STD, &#39; + @cols + &#39; 
            from 
            (
                SELECT STD, 
                       concat(COLUMN_NAME,rnk) as COLUMN_NAME, 
                       VALUE
                FROM
                (
                    SELECT STD, 
                           CAST(SUBJECT AS sql_variant) AS SUBJECT, 
                           CAST(MARKS AS sql_variant) AS MARKS, 
                           CAST(COMMENT AS sql_variant) AS COMMENT, 
                           CAST(convert(varchar(10), TDATE ,120) AS sql_variant) AS TDATE,
                           dense_rank() over(partition by STD order by MARKS) as rnk
                    FROM Exam
                ) AS subquery
                UNPIVOT
                (
                    VALUE
                    FOR COLUMN_NAME IN (SUBJECT, MARKS, COMMENT, TDATE)
                ) AS unpvt
            ) x
            pivot 
            (
                max(VALUE)
                for COLUMN_NAME in (&#39; + @cols + &#39;)
            ) p &#39;;

EXECUTE(@query);
STD SUBJECT1 MARKS1 COMMENT1 TDATE1 SUBJECT2 MARKS2 COMMENT2 TDATE2 SUBJECT3 MARKS3 COMMENT3 TDATE3
ST1 MATH 25% POOR 2021-02-01 SCIENCE 56% PASS 2021-02-04 ENGLISH 88% DIST 2021-02-02

see this as a working demo

nb: As I ended up converting the date column into a string to control the format, you could replace the "as sql_variant" with "as varchar(100)"(length of 100 is a guess)

huangapple
  • 本文由 发表于 2023年6月16日 08:26:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76486263.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定