【问题标题】:Changing additional requirements in join clause to case statement将 join 子句中的附加要求更改为 case 语句
【发布时间】:2014-12-10 04:01:05
【问题描述】:

在我的查询中,我有各种连接和对连接的附加限制。我要重点关注的是:

INNER JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID 
    AND ((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue))
    OR ((CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore)
    OR (CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore))

StudentScores_Subject.ScoreValue 列可以在bandComponents.ScoreValuebandComponents.minScore/bandComponents.maxScorecutScores.minScore/cutScores.maxScore 中进行比较。如果 StudentScores_Subject.ScoreValue 是一个整数值,例如 0-99 之间的数字,则它的值可以通过这些 ANDORs 中的任何一个进行比较,但我不知道它比较的是哪一个每次都取决于对问题不重要的其他限制,所以底线是我不知道它将使用哪个ANDOR 来创建限制,所以我需要在连接中添加所有这些附加语句。通常在过去,StudentScores_Subject.ScoreValue 包含的学生分数只是数值,所以我对连接中的限制没有任何问题,但现在这些值可以是字符串,例如“FBB”(远低于基本值)甚至“ P”(通过)。现在在转换中字符串分数转换为整数时总是存在错误,但这并不一定是因为如果值是字符串,它总是给定唯一需要运行的限制是AND ((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue))。所以我的问题是,有没有办法将连接中的这些额外限制转换为某种 case 语句,所以如果值是字符串,它们不会达到两秒 ORs,但如果分数值是整数,它们可以达到那些额外的限制。这是完整的查询:

SELECT MM_SchoolYears.pkSchoolYearID, TestInstances.pkTestInstanceID, StudentScores_Subject.fkTest_SubjectID, 0 AS 'fkDemographicCodeID', SUM(CASE WHEN bands.StackPosition = '0' THEN 1 ELSE 0 END) * 100.0/ CASE WHEN COUNT(pkStudentScoreID) = 0 THEN 1 ELSE COUNT(pkStudentScoreID) END AS 'Percent_0', SUM(CASE WHEN bands.StackPosition = '0' THEN 1 ELSE 0 END) AS 'Count_0', (SELECT bb.pkPerformanceLevelReportBandID FROM PerformanceLevelReportBands bb WHERE bb.fkPerformanceLevelReportID = '6' AND bb.StackPosition = '0') AS 'BandID_0', SUM(CASE WHEN bands.StackPosition = '1' THEN 1 ELSE 0 END) * 100.0/ CASE WHEN COUNT(pkStudentScoreID) = 0 THEN 1 ELSE COUNT(pkStudentScoreID) END AS 'Percent_1', SUM(CASE WHEN bands.StackPosition = '1' THEN 1 ELSE 0 END) AS 'Count_1', (SELECT bb.pkPerformanceLevelReportBandID FROM PerformanceLevelReportBands bb WHERE bb.fkPerformanceLevelReportID = '6' AND bb.StackPosition = '1') AS 'BandID_1' 
        FROM StudentScores_Subject
                INNER JOIN StudentTests ON StudentScores_Subject.fkStudentTestID = StudentTests.pkStudentTestID
                INNER JOIN TestInstances ON  TestInstances.pkTestInstanceID = StudentTests.fkTestInstanceID
                INNER JOIN CAHSEE_TestPeriods ON CAHSEE_TestPeriods.pkTestPeriodID = TestInstances.fkTestPeriodID   
                INNER JOIN PerformanceLevelReportBands bands ON bands.fkPerformanceLevelReportID = @intPerfLevelReportId
                LEFT JOIN MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
                    AND cutScores.fkGradeID = @intGradeId
                    AND cutScores.fkTestSubjectID IN (SELECT id FROM @tempSubs)
                INNER JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID 
                    AND ((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue))
                    OR ((CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore)
                    OR (CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore))
                RIGHT JOIN MM_SchoolYears ON MM_SchoolYears.pkSchoolYearID = TestInstances.fkSchoolYearID
        WHERE MM_SchoolYears.pkSchoolYearID IN (SELECT number FROM itot(@strYearIds, N','))
                AND bands.fkPerformanceLevelReportID = @intPerfLevelReportId
                AND StudentScores_Subject.fkStudentTestID IN (SELECT id FROM @tempTests)
                AND StudentScores_Subject.fkScoreTypeID = bandComponents.fkScoreTypeID
                AND StudentScores_Subject.fkTest_SubjectID IN (SELECT id FROM @tempSubs)
                AND (bandComponents.ScoreValue = StudentScores_Subject.ScoreValue)
        GROUP BY MM_SchoolYears.pkSchoolYearID, TestInstances.pkTestInstanceID, StudentScores_Subject.fkTest_SubjectID
        ORDER BY MM_SchoolYears.pkSchoolYearID, TestInstances.pkTestInstanceID, StudentScores_Subject.fkTest_SubjectID

长选择语句是动态创建的,只是为学生集创建计数和百分比,但对问题不重要。

【问题讨论】:

  • 您可以将它们转换为案例,但考虑到查询的复杂性,我认为您最好还是预先计算结果(有一份工作,这样您就可以更轻松地查询结果)或尝试将其拆分为多个查询,一起进行联合;只是为了摆脱“或”逻辑,这很容易对 sql 中的执行计划造成严重破坏

标签: sql-server join case


【解决方案1】:

您可以通过添加ISNUMERIC 来扩展连接条件,如下所示:

INNER JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID 
  AND ((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue))
  OR
  (
    ISNUMERIC(StudentScores_Subject.ScoreValue)
    AND
    (
      (CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore)
      OR
      (CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore)
    )
   )

这不是万无一失的 - 有很多讨论为什么 ISNUMERIC 不保证 CAST to int 会起作用或相反,但在您的情况下,它可能足以解决您的问题。

【讨论】:

  • 嘿,这对我来说效果很好。我知道 sql server 2012 中有 try_convert,但我使用的是 2008,但这很好用,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-23
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 2015-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多