您有相当多的任务要执行,但规范化该表是正确的做法。在您的旧表示例中,我注意到您有 [StartDate] 和 [EndDate] 重复。 这在 SQL Sever 中是不可能的,所有列名在表中必须是唯一的。我希望这只是示例中的一个小故障,因为它非常重要。
下面我使用一种方法将一个学生行“还原”为多个较短的行,这代表了实现目标的中间步骤。此方法使用CROSS APPLY 和VALUES。请注意,您需要手动准备此 VALUES 部分,但您可能能够从针对您的信息架构的查询中获取字段列表(未提供此查询)。
在SQL Fiddle查看这个工作模型
MS SQL Server 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)
;
这是最重要的查询它将源数据“反透视”到多行
注意它需要如何为每个培训课程分配一个 ID,并且 column groups(例如 [SoftSkillTraining], [StartDate1], [EndDate1])必须在值区域中逐行指定。这里的每一行都会产生新的一行输出,所以values区域的“布局”基本上决定了最终的输出是什么。正是在这个区域,您需要仔细收集所有列名并准确排列。
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 |