将行合并为包含单独列的1行

时间:2014-11-25 17:12:00

标签: sql-server sql-server-2012

FirstName |LastName |OtherName |admim_no| ExamCategory | subject | Exam| Score| Grade 
Anthony   | Tee     | Tony     | 1000   | MockExams2014|Chemistry| PP1 | 12   | D+
Anthony   | Tee     | Tony     | 1000   | MockExams2014|Biology  | PP1 | 50   | C+
Moses K.  | Ndu     |          | 1001   | MockExams2014|Chemistry| PP1 | 65   | B+
Moses K.  | Ndu     |          | 1001   | MockExams2014|Biology  | PP1 | 85   | A

我希望在sql server 2012中实现的是每个考试类别我已将admission_no分组为一行,然后将主题,考试,分数,成绩作为第二行的单独列放置,以便您拥有例如admission_no 1000和列的所有不同数据(主题,考试,分数,成绩)为单行。我不知道如何解决它。我尝试了下面的失败。

我的结果应该如下

Anthony |   Tee |    Tony  |  1000|  MockExams2014|Chemistry|   PP1 |  12| D+   Biology|   PP1 |   50| C+

SQLITE: merging rows into single row if they share a column

enter image description here

1 个答案:

答案 0 :(得分:0)

如果允许将重复的值连接到on行,则可以使用XML PATH处理连接的子查询,在下面显示为add(2)。
要将重复值作为列获取,您可以计算admim_no的最大行数,并根据需要使用尽可能多的左连接来创建动态sql以获取所需的列。

/* test data
Create table TestX (FirstName varchar(50) ,LastName varchar(50),OtherName varchar(50), admim_no int,ExamCategory varchar(50), subject varchar(50), Exam Varchar(50), Score int,grade varchar(50))
Insert into TestX Values ('Anthony','Tee','Tony',1000 ,' MockExams2014','Chemistry','PP1',12,'D+')
Insert into TestX Values ('Anthony','Tee','Tony',1000 ,' MockExams2014','Biology','PP1',50,'C+')
Insert into TestX Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Chemistry','PP1',65,'B+')
Insert into TestX Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Biology','PP1',85,'A')
Insert into TestX Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Physiks','PP2',12,'D+')
*/


Declare @maxcnt int
Declare @cnt int
Declare @Dyn1 varchar(max)
Declare @Dyn2 varchar(max)

Select @maxcnt=MAX(cnt) from
       (Select COUNT(*) as cnt from TestX Group by admim_no ) a




Set @Dyn1='
;With CTE as
(
Select *, Row_Number() over (Partition by admim_no order by admim_no ) as rn  from TestX
)
Select CTE0.*
'
Set @Dyn2='
           From CTE CTE0'
Set @cnt=1
While @maxcnt>1
  begin
  Set @Dyn1 = @Dyn1 + ',CTE' + Cast(@cnt as varchar(5))+'.subject
                       ,CTE' + Cast(@cnt as varchar(5))+'.Exam
                       ,CTE' + Cast(@cnt as varchar(5))+'.Score
                       ,CTE' + Cast(@cnt as varchar(5))+'.grade'
  Set @Dyn2 = @Dyn2 + ' 
                       LEFT Join CTE CTE' + Cast(@cnt as varchar(5))+'
                       on CTE' + Cast(@cnt as varchar(5))+'.rn=CTE0.rn + '+Cast(@cnt as varchar(5))+' 
                       and CTE' + Cast(@cnt as varchar(5))+'.admim_no=CTE0.admim_no'   
  Set @maxcnt=@maxcnt-1
  Set @cnt=@cnt+1
  end 
Set @Dyn2 = @Dyn1 + @Dyn2 + '
                       where CTE0.rn=1'
Print @Dyn2
Exec(@Dyn2)

提供的测试数据的生成SQL如下所示:

;With CTE as
(
Select *, Row_Number() over (Partition by admim_no order by admim_no ) as rn  from TestX
)
Select CTE0.*
,CTE1.subject
                       ,CTE1.Exam
                       ,CTE1.Score
                       ,CTE1.grade,CTE2.subject
                       ,CTE2.Exam
                       ,CTE2.Score
                       ,CTE2.grade
           From CTE CTE0 
                       LEFT Join CTE CTE1
                       on CTE1.rn=CTE0.rn + 1 
                       and CTE1.admim_no=CTE0.admim_no 
                       LEFT Join CTE CTE2
                       on CTE2.rn=CTE0.rn + 2 
                       and CTE2.admim_no=CTE0.admim_no
                       where CTE0.rn=1

结果如

Anthony Tee Tony    1000     MockExams2014  Chemistry   PP1 12  D+  1   Biology PP1 50  C+  NULL    NULL    NULL    NULL
Moses K Ndu NULL    1001     MockExams2014  Chemistry   PP1 65  B+  1   Biology PP1 85  A   Physiks PP2 12  D+

最初提到的outpu的一列更简单的方法(2)如下所示:

Declare @a table (FirstName varchar(50) ,LastName varchar(50),OtherName varchar(50), admim_no int,ExamCategory varchar(50), subject varchar(50), Exam Varchar(50), Score int,grade varchar(50))
Insert into @a Values ('Anthony','Tee','Tony',1000 ,' MockExams2014','Chemistry','PP1',12,'D+')
Insert into @a Values ('Anthony','Tee','Tony',1000 ,' MockExams2014','Biology','PP1',50,'C+')
Insert into @a Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Chemistry','PP1',65,'B+')
Insert into @a Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Biology','PP1',85,'A')
Insert into @a Values ('Moses K','Ndu',NULL,1001 ,' MockExams2014','Physiks','PP1',12,'D+')


Select FirstName,LastName,OtherName,admim_no,ExamCategory
, STUFF(
             (SELECT ',' + subject +', ' + Exam +', ' + CAST(Score as varchar(20)) + ', ' + Grade 
              FROM @a a2 where a1.admim_no = a2.admim_no            
              FOR XML PATH (''))       
             , 1, 1, '') as subjectExamScoreGrade       

from  @a a1
Group by  FirstName,LastName,OtherName,admim_no,ExamCategory