如何根据关系将列更改为行?

时间:2016-08-27 05:22:53

标签: sql sql-server

好的,所以我对SQL比较陌生,从事教育工作,以及我从这个网站上学到的几乎所有关于SQL的知识。所以谢谢!现在,我已经找到了我的问题的答案,到目前为止还没有运气。我已经调查了PIVOT,UNPIVOT,UNION ALL和CROSS APPLY,到目前为止我认为这些解决方案不会给我我需要的东西。至少我试图让它发挥作用是不成功的。

我有两张桌子,我正在处理。一个叫做STU,一个叫做TCH。你可以想象1是为学生和其他老师。有几个领域我们需要知道它们是什么。 STU.ID是学生证。假设我们有1-999个。 STU.SC是学生被分配到的学校代码(1-5),STU.CU表示学生有哪个老师。 TCH有TCH.TN,这是教师编号,与STU.CU相匹配。 (1-40)和TCH.SC将匹配STU.SC

目前我的查询看起来如下:(我知道根据我提供的信息,我只需要在我的示例中查询STU表,我还有其他东西我将要查询并希望确保连接为了简单起见,我为了这个例子减少了字段的数量。)

select TCH.TN
STU.SC,
STU.ID 
From TCH Left Join STU on
STU.SC=TCH.SC and STU.CU=TCH.TN 
where STU.SC  > 2
and STU.SC <= 5

此截断结果与此示例类似,并为所有1000名学生提供结果。

TCH.TN    STU.SC    STU.ID
---------------------------
24         3         243
32         5         145
24         3         567
21         4         098
21         4         923
24         3         417

我的请求是如下输出数据:

TCH.TN    STU.SC    STU.ID    STU.ID    STU.ID    STU.ID    STU.ID
--------------------------------------------------------------------
24         3         243       567       417
32         5         145
21         4         098       923

这些课程中的一些课程中会有超过30名学生的ID。你们怎么做这个工作?还请记住我还是SQL的新手,如果可能的话ELI5会很棒。

谢谢

2 个答案:

答案 0 :(得分:0)

您可以使用动态数据透视来解决此问题。

下面是示例代码,但我没有运行它。

    select TCH.TN as TeacherId
STU.SC as studentScollar,
STU.ID as studentId 
INTO #tmp
From TCH Left Join STU on
STU.SC=TCH.SC and STU.CU=TCH.TN 
where STU.SC  > 2
and STU.SC <= 5


DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(studentId)
FROM (SELECT DISTINCT studentId FROM #tmp) AS Courses

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'SELECT TeacherId, ' + @ColumnName + '
    FROM #tmp
    PIVOT(SUM(studentScollar) 
          FOR studentId IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery

以下是动态枢轴链接供您参考 http://sqlhints.com/2014/03/18/dynamic-pivot-in-sql-server/

答案 1 :(得分:0)

在SQL Pivot语句中,最终查询中的所有标头必须是唯一的。请参阅Microsoft Documentation on Pivots

的摘录
  

您可以使用PIVOT和UNPIVOT关系运算符将表值表达式更改为另一个表。 PIVOT通过将唯一值从表达式中的一列转换为输出中的多列来旋转表值表达式,并在最终需要的任何剩余列值上执行聚合输出

因为您希望将前两列[tch.tn], [stu.sc]保留为行,将第三列[stu.id]保留为聚合,并且是成为pivot语句中标题的值,它将创建一列每个学生。 (这就是为什么你得到了回应Rajat答案时提到的错误。)

您需要做的是创建一个新列以将值转换为标头,并聚合(仅使用max()stu.id列的值。换句话说,列出与最大类中的学生相同的列数(如果最大班级大小为30,那么它将生成30列)。

<强>答案:

use db_nm

--declaring variables to build my dynamic SQL statement later
declare @sql nvarchar(max)
    , @col_list nvarchar(max)

--building the sample data
if object_id('tempdb..##tmp_stu_id_tbl') is not null
    drop table ##tmp_stu_id_tbl

if object_id('tempdb..##tmp_stu_id_pre_pivot') is not null
    drop table ##tmp_stu_id_pre_pivot

create table ##tmp_stu_id_tbl ([tn] int not null, [sc] int not null, [id] int not null)

insert into ##tmp_stu_id_tbl
values (24, 3, 243)
    , (32, 5, 145)
    , (24, 3, 567)
    , (21, 4, 098)
    , (21, 4, 923)
    , (24, 3, 417)

--Using this query to add a column with values 
--that will become the column headers after the pivot
select a.[tn]
, a.[sc]
--this creates the value id.1 for the first row id it finds
--within each tn/sc combination
, 'stu_id_' + cast(row_number() over (partition by a.[tn], a.[sc] order by a.[id]) as varchar(10)) as piv_col
, a.[id]
into ##tmp_stu_id_pre_pivot
from ##tmp_stu_id_tbl as a

--creating the column list for the dynamic sql statement
set @col_list = (select stuff((select distinct ', [' + a.piv_col + ']'
                from ##tmp_stu_id_pre_pivot as a
                for xml path('')),1,1,''))

--building the dynamic SQL
set @sql = '
select tn
, sc
, ' + @col_list +
' from ##tmp_stu_id_pre_pivot 
pivot (max([id]) for piv_col in (' + @col_list + ')) as p'

--executing the dynamic SQL
exec (@sql);

<强>结果:

tch_tn stu_sc stu.id.1 stu.id.2 stu.id.3
  24      3     243      417      567
  21      4     98       923      NULL
  32      5     145      NULL     NULL

修改

select TCH.TN,
STU.SC,
STU.ID,
'stu_id_' + cast(row_number() over (partition by tch.[tn], stu.[sc] order by stu.[id]) as varchar(10)) as piv_col
into ##tmp_stu_id_pre_pivot
From TCH Left Join STU on
STU.SC=TCH.SC and STU.CU=TCH.TN 
where STU.SC  > 2
and STU.SC <= 5