我在 SQL Server 2012 中有一个如下所示的StudentScores表。评分系统使用特殊规则加权。对于学生的每个MATHS结果,结果集中将有一行。根据是否有可用的分数"在MATHS结果日期的两个月内,该行可能有也可能没有科学和文学专栏的分数。和#34;在MATHS结果日期的一个月内,LITERATURE"。
注意:这是我为简化实际业务领域问题而创建的方案。
我使用子查询创建了以下查询。有没有办法在没有子查询的情况下更有效地重写它?
表
DECLARE @StudentScores TABLE (StudentMarkID INT IDENTITY(1,1) NOT NULL, StudentID INT, SubjectCode VARCHAR(10), ResultDate DATETIME, Score DECIMAL(5,2))
INSERT INTO @StudentScores (StudentID,SubjectCode,ResultDate,Score)
SELECT 1, 'MATHS','2016-01-10',35
UNION ALL
SELECT 1, 'LITERATURE','2016-01-10',62
UNION ALL
SELECT 1, 'SCIENCE','2016-01-30',65
UNION ALL
SELECT 1, 'SCIENCE','2016-02-02',61
UNION ALL
SELECT 1, 'LITERATURE','2016-02-03',60
UNION ALL
SELECT 1, 'MATHS','2016-03-25',55
UNION ALL
SELECT 2, 'LITERATURE','2016-01-10',12
UNION ALL
SELECT 2, 'SCIENCE','2016-01-30',14
UNION ALL
SELECT 2, 'SCIENCE','2016-02-14',12
UNION ALL
SELECT 2, 'LITERATURE','2016-02-14',15
UNION ALL
SELECT 2, 'MATHS','2016-03-25',18
QUERY
SELECT SS.StudentID, Score AS MathsScore,
ResultDate AS MathsResultDate,
(SELECT TOP 1 Score
FROM @StudentScores S2
WHERE S2.StudentID = SS.StudentID
AND S2.SubjectCode = 'SCIENCE'
AND S2.ResultDate >= DATEADD(MONTH,-2,SS.ResultDate)
ORDER BY s2.ResultDate DESC
) AS ScienceScore,
(SELECT TOP 1 ResultDate
FROM @StudentScores S2
WHERE S2.StudentID = SS.StudentID
AND S2.SubjectCode = 'SCIENCE'
AND S2.ResultDate >= DATEADD(MONTH,-2,SS.ResultDate)
ORDER BY s2.ResultDate DESC
) AS ScienceResultDate,
(SELECT TOP 1 Score
FROM @StudentScores S2
WHERE S2.StudentID = SS.StudentID
AND S2.SubjectCode = 'LITERATURE'
AND S2.ResultDate >= DATEADD(MONTH,-1,SS.ResultDate)
ORDER BY s2.ResultDate DESC
) AS LiteratureScore,
(SELECT TOP 1 ResultDate
FROM @StudentScores S2
WHERE S2.StudentID = SS.StudentID
AND S2.SubjectCode = 'LITERATURE'
AND S2.ResultDate >= DATEADD(MONTH,-1,SS.ResultDate)
ORDER BY s2.ResultDate DESC
) AS LiteratureResultDate
FROM @StudentScores SS
WHERE SS.SubjectCode = 'MATHS'
预期结果
答案 0 :(得分:1)
我设法将查询减少到两次调用数据表 - 一次用于获取Maths
详细信息,因为他们的日期用于提取其他主题的详细信息,其次用于其他主题:
WITH DataSource_Maths AS
(
SELECT SS.[StudentID]
,SS.[Score] AS [MathsScore]
,SS.[ResultDate] AS [MathsResultDate]
-- we are using this interal ID later in the final join between the two CTEs
-- in order to know which record, for which date period refers
,ROW_NUMBER() OVER(ORDER BY SS.[StudentID], SS.[ResultDate]) AS InternalID
FROM @StudentScores SS
WHERE SS.[SubjectCode] = 'MATHS'
),
DataSource_Others AS
(
SELECT DS.[StudentID]
,DS.[SubjectCode]
,DS.[Score]
,DS.[ResultDate]
,Ds.[RowID]
,SS.[InternalID]
FROM DataSource_Maths SS
OUTER APPLY
(
SELECT *
-- calculating row ID for each record across student and subject (we are going to take only the latest ones)
-- this is achived using TOP in your example
,DENSE_RANK() OVER (PARTITION BY [StudentID], [SubjectCode] ORDER BY [ResultDate] DESC) AS [RowID]
FROM @StudentScores
WHERE
(
[ResultDate] >= DATEADD(MONTH, -2, SS.[MathsResultDate]) AND [SubjectCode] = 'SCIENCE'
OR
[ResultDate] >= DATEADD(MONTH, -1, SS.[MathsResultDate]) AND [SubjectCode] = 'LITERATURE'
) AND [StudentID] = SS.[StudentID]
) DS
)
SELECT FDS_M.[StudentID]
,FDS_M.[MathsScore] AS [MathsScore]
,FDS_M.[MathsResultDate] AS [MathsResultDate]
,FDS_S.[Score] AS [ScienceScore]
,FDS_S.[ResultDate] AS [ScienceResultDate]
,FDS_L.[Score] AS [LiteratureScore]
,FDS_L.[ResultDate] AS [LiteratureResultDate]
FROM DataSource_Maths FDS_M
LEFT JOIN DataSource_Others FDS_S
ON FDS_M.[InternalID] = FDS_S.[InternalID]
AND FDS_S.[SubjectCode] = 'SCIENCE'
AND FDS_S.[RowID] = 1
LEFT JOIN DataSource_Others FDS_L
ON FDS_M.[InternalID] = FDS_L.[InternalID]
AND FDS_L.[SubjectCode] = 'LITERATURE'
AND FDS_L.[RowID] = 1;
当然,在更复杂的示例中,您可以实现临时表中的CTE
子句(例如),以简化和优化查询。