2017-10-07 1226 views
-1

我有一个名为Students的表,它存储了所有参与学生和培训的基本信息(表中有超过15列和5000多条记录)。该表的样品部分是这样的:SQL Server中的拆分表

St_id St_Name St_University SoftSkillTraining StartDate EndDate  ComputerTraining StartDate EndDate 
--------------------------------------------------------------------------------------------------------------- 
1  x  x    True    12/02/2017 12/03/2017 False    -   -  
2  y  x    True    25/05/2016 25/06/2016 True    01/08/2017   

然而,该表是不归,我需要给学生表分成三个特定表(在多对多关系的形式)

  1. Student表包含像学生的基本信息:
 
St_id St_Name  St_University  St_Faculty 
-------------------------------------------------- 
1  X   Some University Law 
2  y   Some University IT 
  • 存储 '训练名', '开始日期' 和 '结束日期' 列表
  • Training表应该是:

     
    TrainingId TrainingName StartDate EndDate  TrainingLocation 
    ----------------------------------------------------------------- 
    1   SoftSkill  12/02/2017 12/03/2017 Some Location 
    2   SoftSkill  25/02/2016 25/06/2016 Some Location 
    3   CMOA   01/08/2017 01//09/2017 some location 
    
  • 一种intersection表在培训和门店的门店仅参与者的Student主键和Training表作为外键象下面这样:
  •  
    st_id  training_id 
    ----------------------- 
    1   1 
    2   2 
    2   1 
    

    如何将数据从student转换为Training表,如您可以看到来自student的不同列的数据表应该在使用存储过程的training表中显示为一行?实现你的任务

    +0

    你在这3代表期待什么列?你有没有试过你自己的任何疑问? –

    +0

    我编辑了这个问题来进一步解释列。我尝试了一些查询,但没有工作。 –

    +0

    “培训地点”从哪里来?它没有显示在退出学生表的示例中。 –

    回答

    0

    你有相当执行任务,但归该表是做正确的事。在旧表格的示例中,我注意到您已经重复了[StartDate] & [EndDate]。 这在SQL Sever中不可行,所有列名在表中必须是唯一的。我希望这只是样品中的一个小故障,因为它会变得非常重要。

    下面我使用一种方法来将学生行“转移”为多个较短的行,这代表了实现您的目标的临时步骤。该方法使用CROSS APPLYVALUES。请注意,您需要手动准备这个VALUES部分,但是您可能能够从查询中获取针对您的信息架构的字段列表(未提供此查询)。

    SQL Fiddle

    MS SQL服务器2014架构设置见的这样的工作模式:

    CREATE TABLE Student 
        ([St_id] int, [St_Name] varchar(1), [St_University] varchar(1) 
        , [SoftSkillTraining] varchar(4), [StartDate1] datetime, [EndDate1] datetime 
        , [ComputerTraining] varchar(5), [StartDate2] datetime, [EndDate2] datetime) 
    ; 
    
    INSERT INTO Student 
        ([St_id], [St_Name], [St_University] 
        , [SoftSkillTraining], [StartDate1], [EndDate1] 
        , [ComputerTraining], [StartDate2], [EndDate2]) 
    VALUES 
        (1, 'x', 'x', 'True', '2017-02-12 00:00:00', '2017-03-12 00:00:00', 'False', NULL, NULL), 
        (2, 'y', 'x', 'True', '2016-05-25 00:00:00', '2016-06-25 00:00:00', 'True', '2017-08-01', NULL) 
    ; 
    

    这是最重要的查询它 “unpivots” 源数据多行

    请注意如何为每个培训课程分配一个id,以及column groups[SoftSkillTraining], [StartDate1], [EndDate1]必须是在值区域中逐行指定。这里的每一行都会产生一个新的输出行,因此值区域的“布局”基本上决定了最终输出的结果。在这个区域,您需要仔细收集所有列名并准确安排。

    select 
        St_id, ca.TrainingId, ca.TrainingName, ca.isEnrolled, ca.StartDate, ca.EndDate 
        into training_setup 
    from Student 
    cross apply (
        values 
        (1, 'SoftSkillTraining', [SoftSkillTraining], [StartDate1], [EndDate1]) 
        ,(2, 'ComputerTraining', [ComputerTraining], [StartDate2], [EndDate2]) 
    ) ca (TrainingId,TrainingName,isEnrolled, StartDate,EndDate) 
    where ca.isEnrolled = 'True' 
    ; 
    

    查询2

    select 
    * 
    from training_setup 
    

    Results

    | St_id | TrainingId |  TrainingName | isEnrolled |   StartDate |    EndDate | 
    |-------|------------|-------------------|------------|----------------------|----------------------| 
    |  1 |   1 | SoftSkillTraining |  True | 2017-02-12T00:00:00Z | 2017-03-12T00:00:00Z | 
    |  2 |   1 | SoftSkillTraining |  True | 2016-05-25T00:00:00Z | 2016-06-25T00:00:00Z | 
    |  2 |   2 | ComputerTraining |  True | 2017-08-01T00:00:00Z |    (null) | 
    

    查询3

    -- this can be the basis for table [Training] 
    select distinct TrainingId,TrainingName, StartDate,EndDate 
    from training_setup 
    

    Results

    | TrainingId |  TrainingName |   StartDate |    EndDate | 
    |------------|-------------------|----------------------|----------------------| 
    |   1 | SoftSkillTraining | 2016-05-25T00:00:00Z | 2016-06-25T00:00:00Z | 
    |   1 | SoftSkillTraining | 2017-02-12T00:00:00Z | 2017-03-12T00:00:00Z | 
    |   2 | ComputerTraining | 2017-08-01T00:00:00Z |    (null) | 
    

    注意我对这个数据的一致性保留,注意开始/结束日期为一个疗程不同。我没有一个简单的解决方案。您可能需要清理数据以最大限度地减少差异,并且/或者您可能需要额外的步骤,使其与我们在交叉应用中使用的ID匹配,再加上开始/结束日期对,以更新training_id来获得更好的版本training_setup临时表,然后再继续。

    查询4

    -- this can be the basis for table [Student_Training] 
    select St_id, TrainingId 
    from training_setup 
    

    Results

    | St_id | TrainingId | 
    |-------|------------| 
    |  1 |   1 | 
    |  2 |   1 | 
    |  2 |   2 | 
    
    +0

    非常感谢你..你的解决方案为我工作。与您的查询一点点变化,我规范化我的表没有数据丢失:) –

    +0

    奇妙。非常高兴听到你的成功。祝贺并享受。 –

    0

    方式一:

    create table Students (
    St_id int primary key, 
    St_Name varchar(5), 
    St_University varchar(5), 
    SoftSkillTraining varchar(5), 
    ST_StartDate varchar(10), 
    ST_EndDate varchar(10), 
    ComputerTraining varchar(5), 
    CT_StartDate varchar(10), 
    CT_EndDate varchar(10), 
    ); 
    
    insert into Students (St_id, St_Name, St_University, SoftSkillTraining, ST_StartDate , ST_EndDate, ComputerTraining, CT_StartDate, CT_EndDate) 
    values('1','x', 'x' , 'True' , '12/02/2017', '12/03/2017' , 'False',NULL , NULL) 
    
    insert into Students (St_id, St_Name, St_University, SoftSkillTraining, ST_StartDate , ST_EndDate, ComputerTraining, CT_StartDate, CT_EndDate) 
    values('2' , 'y' ,'x' , 'True' , '25/05/2016' , '25/06/2016' , 'True' , '01/08/2017', NULL) 
    
    create table Student (
    St_id int primary key, 
    St_Name varchar(5), 
    St_University varchar(5), 
    ); 
    
    insert into Student (St_id, St_Name,St_University) 
    select distinct St_id , St_Name , St_University from Students; 
    
    create table Training (
    Training_Id int identity(1,1) primary key, 
    Student_Id int foreign key references Students(St_id), 
    Training_Name varchar(20), 
    StartDate varchar(10), 
    EndDate varchar(10), 
    ); 
    
    insert into Training (Student_Id ,Training_Name , StartDate, EndDate) 
    values ('1' , 'SoftSkillTraining' , '12/02/2017' , '12/03/2017'); 
    
    insert into Training (Student_Id ,Training_Name , StartDate, EndDate) 
    values ('2' , 'SoftSkillTraining' , '25/05/2016' , '25/06/2016'); 
    
    insert into Training (Student_Id ,Training_Name , StartDate, EndDate) 
    values ('2' , 'ComputerTraining' , '01/08/2017' , NULL); 
    
    create table Intersection (
    Intersection_Id int identity(1,1) primary key, 
    Student_id int foreign key references Students(St_id), 
    Training_Id int foreign key references Training(Training_id), 
    ); 
    
    insert into Intersection (Student_id,Training_Id) 
    select St_id, Training_Id from Student join Training on St_id = Student_Id 
    
    
    go 
    create view Participants 
    as 
    select St_Name as Participant, Training_Name from Intersection join Student on student_id = St_id join Training on intersection.Training_Id = training.Training_Id 
    go 
    
    +0

    旧的学生表包含5000多条记录,我无法逐一插入新表。其次,'SoftSkillTraining'和'ComputerTraining'在旧表格中显示为一列。如何插入不同列中的数据以显示在单个列中? –

    +0

    如果使用版本> SQL Server 2008中,那么你可以去 “CROSS APPLY” 与VALUES子句unpivoting:从DesiredTable 选择值 交叉应用 ( 值 ( 'I1',I1), ( 'I2',I2), ( 'I3',I3) )C(COL,值) 其中值不为空 为了通过ID,山坳 更多关于CROSS应用,可以访问: HTTPS: //sqlstudies.com/2013/04/01/unpivot-a-table-using-cross-apply/ –