与case和isnumeric混淆行为

时间:2016-04-12 03:52:17

标签: sql-server tsql

在我的存储过程中,我有一个case语句,它应该测试一个字段是否为数字并处理该字段,但无论如何都会得到相同的错误。我试过以下:

CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END

我还使用了自定义转换功能,因为我读过isnumeric并非100%可靠但收到了同样的错误。我也试过使用CONVERT但没有成功。我甚至用0=1取代了isnumeric,它应该总是失败,但我仍然得到同样的错误,我发现它真的很奇怪。这是我的错误:

Error converting data type nvarchar to real

它正在检查的值如下:

A0, A10, A23, B9, B51, C90, C100, etc

对此行为的任何想法? 这是完整的程序。问题发生在THEN之后的where子句中的第一种情况,而不是使用实际字段使用-1。它还包含我对ISNUMERIC和我的自定义函数的使用:

@strDemoCodeIds             nvarchar(100),
        @strYearIds                 nvarchar(100),
        @intRosterSetId             int,
        @intSchoolId                int,
        @intTeachId                 int,
        @intGradeId                 int,
        @intDeptId                  int,
        @intCourseId                int,
        @intPeriodId                int,
        @strTestInstIds             nvarchar(100),
        @intTestTypeId              int,
        @intSubjectId               int,
        @intScoreTypeId             int,
        @strSuppScoreTypeId         nvarchar(20),
        @intClusterScoreTypeId      int,
        @intClusterColorScoreTypeId int,
        @intLocalReportId           int,    
        @strSortMethod              nvarchar(20),
        @intAnchorYear              int     


       AS
       BEGIN
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;

        DECLARE @topYearID INT

        DECLARE @subs TABLE (subId int)
        IF @intSubjectId < 100
            BEGIN
                INSERT INTO @subs
                    SELECT MM_Test_Subjects.pkTestSubjectID 
                    FROM MM_Test_Subjects 
                    WHERE MM_Test_Subjects.fkCSTStrandID = @intSubjectId
            END
            ELSE
            BEGIN
                INSERT INTO @subs VALUES (@intSubjectId)
            END

        DECLARE @years TABLE (yearId int)
        INSERT INTO @years
            SELECT number FROM itot(@strYearIds, N',')

        SET @topYearID = @intAnchorYear

        SELECT  s.pkStudentID,
                s.LastName,
                s.FirstName,
                s.StudentNumber,
                st.fkTestInstanceID,
                bands.Description AS 'PL',
                bands.Color,
                subScoresSupp.scoreValue AS 'SuppScore',
                clusters.pkTestClusterID,
                clusterScores.ScoreValue,
                colors.ScoreValue,
                ti.TestInstanceName,
                tp.TestPeriodTitle,
                subScores.ScoreValue AS 'PLScore',
                ScoreType.pkScoreTypeID,
                bands.StackPosition AS 'StackPosition'
        FROM Students s
        INNER JOIN StudentTests st ON s.pkStudentID = st.fkStudentID
        INNER JOIN StudentTests baseSt ON s.pkStudentID = baseSt.fkStudentID
            AND baseSt.fkGradeID = CASE @intGradeId WHEN 99 THEN baseSt.fkGradeID ELSE @intGradeId END
            AND EXISTS (SELECT * FROM StudentScores_Subject baseSubScores WHERE baseSubScores.fkStudentTestID = baseSt.pkStudentTestID
                            AND baseSubScores.fkTest_SubjectID IN (SELECT subId FROM @subs)
                            AND baseSubScores.fkScoreTypeID = @intScoreTypeId)
        INNER JOIN StudentTestDemographics d ON d.fkStudentTestID = baseSt.pkStudentTestID
        INNER JOIN itot(@strDemoCodeIds, N',') tblDemoCodes ON d.fkDemographicCodeID = CASE @strDemoCodeIds WHEN '0' THEN d.fkDemographicCodeID ELSE tblDemoCodes.number END                
        INNER JOIN StudentScores_Subject subScores ON subScores.fkStudentTestID = st.pkStudentTestID 
            AND subScores.fkTest_SubjectID IN (SELECT subId FROM @subs)
            AND subScores.fkScoreTypeID = @intScoreTypeId
        LEFT JOIN PerformanceLevelReportBands bands ON bands.fkPerformanceLevelReportID = @intLocalReportId
        LEFT JOIN MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
            AND cutScores.fkGradeID = @intGradeId
            AND cutScores.fkTestSubjectID IN (SELECT subId FROM @subs)
        RIGHT JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID 
        LEFT JOIN StudentScores_Subject subScoresSupp ON subScoresSupp.fkStudentTestID = st.pkStudentTestID
            AND subScoresSupp.fkTest_SubjectID IN (SELECT subId FROM @subs)
            AND subScoresSupp.fkScoreTypeID IN (SELECT tblsubScoresSupp.number FROM itot(@strSuppScoreTypeId, N',') tblsubScoresSupp)
        LEFT JOIN MM_ScoreTypes ScoreType ON ScoreType.pkScoreTypeID = subScoresSupp.fkScoreTypeID  
        LEFT JOIN StudentScores_Cluster clusterScores ON clusterScores.fkStudentTestID = st.pkStudentTestID
            AND clusterScores.fkTest_SubjectID IN (SELECT subId FROM @subs)
            AND clusterScores.fkScoreTypeID = @intClusterScoreTypeId
        LEFT JOIN StudentScores_Cluster colors ON colors.fkStudentTestID = st.pkStudentTestID
            AND colors.fkTest_SubjectID IN (SELECT subId FROM @subs)
            AND colors.fkScoreTypeID = @intClusterColorScoreTypeId
            AND colors.fkTest_ClusterID = clusterScores.fkTest_ClusterID
        LEFT JOIN MM_Test_Clusters clusters ON clusters.pkTestClusterID = clusterScores.fkTest_ClusterID
        INNER JOIN TestInstances ti ON ti.pkTestInstanceID = st.fkTestInstanceID
        INNER JOIN TestInstances baseTi ON baseTi.pkTestInstanceID = baseSt.fkTestInstanceID
            AND baseTi.fkSchoolYearID = @topYearID
        INNER JOIN CAHSEE_TestPeriods tp on tp.pkTestPeriodID = ti.fkTestPeriodID
        INNER JOIN CAHSEE_TestPeriods baseTp on baseTp.pkTestPeriodID = baseTi.fkTestPeriodID
        INNER JOIN Roster_Students rs ON rs.fkStudentID = s.pkStudentID
        INNER JOIN Roster_Groups rg ON rg.fkTestInstanceID = baseTi.pkTestInstanceID
            AND ti.pkTestInstanceID IN (SELECT tblTestInstances.number FROM itot(@strTestInstIds, N',') tblTestInstances)
            AND baseTi.pkTestInstanceID IN (SELECT tblTestInstances.number FROM itot(@strTestInstIds, N',') tblTestInstances)
            AND rg.fkRosterSetID = @intRosterSetId
            AND rg.pkRosterGroupID = rs.fkRosterGroupID
            AND (rg.fkSchoolID = @intSchoolId OR @intSchoolId = 0)
            AND (rg.fkTeacherID = @intTeachId OR @intTeachId = 0)
            AND (rg.fkGradeID = baseSt.fkGradeID)
            AND (rg.fkDepartmentID = @intDeptId OR @intDeptId = 0)
            AND (rg.fkCourseID = @intCourseId OR @intCourseId = 0)
            AND (rg.fkPeriodID = @intPeriodId OR @intPeriodId = 0)
        WHERE (bandComponents.ScoreValue = subScores.ScoreValue)
            OR 
            ((CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE subScores.ScoreValue END)
                BETWEEN (CASE WHEN dbo.TryConvertInt(bandComponents.minScore) = 1 THEN CAST(bandComponents.minScore AS REAL) ELSE bandComponents.minScore END) and 
                (CASE WHEN dbo.TryConvertInt(bandComponents.maxScore) = 1 THEN CAST(bandComponents.maxScore AS REAL) ELSE bandComponents.maxScore END)/*CAST(ISNULL(bandComponents.maxScore,'0') AS INT)*/)
            OR 
            ((CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END)
                BETWEEN ISNULL(cutScores.minScore,0) and ISNULL(cutScores.maxScore,0))
        GROUP BY s.pkStudentID, s.LastName, s.FirstName, s.StudentNumber, st.fkTestInstanceID, bands.Description, bands.Color, subScoresSupp.scoreValue, 
            clusters.pkTestClusterID, clusterScores.ScoreValue, colors.ScoreValue, ti.TestInstanceName, tp.TestPeriodTitle, subScores.ScoreValue, 
            ScoreType.pkScoreTypeID, bands.StackPosition
        ORDER BY 
            CASE WHEN @strSortMethod = 'ScoreDesc'
                THEN bands.StackPosition END DESC,
            CASE WHEN @strSortMethod = 'ScoreAsc'
                THEN bands.StackPosition END ASC,
            CASE WHEN @strSortMethod = 'ScoreDesc' AND ISNUMERIC(subScores.ScoreValue) = 1
                THEN CONVERT(int, subScores.ScoreValue) END DESC,
            CASE WHEN @strSortMethod = 'ScoreAsc' AND ISNUMERIC(subScores.ScoreValue) = 1
                THEN CONVERT(int, subScores.ScoreValue) END ASC,
                s.LastName, s.FirstName, s.pkStudentID, st.fkTestInstanceID


   END

3 个答案:

答案 0 :(得分:0)

我会尝试你的东西,然后找到这个问题

select CASE WHEN ISNUMERIC(CONVERT(nvarchar,'- 5')) = 1 THEN CAST(CONVERT(nvarchar,'- 5') AS REAL) ELSE -1 END

Isnumeric函数应返回此值为true,并且convert函数不应将值转换为real,因为值为空格。

在列中查找此类型的数据,例如得分值。

答案 1 :(得分:0)

/*Show how isnumeric differs from TRY_CONVERT*/
declare @temp table (dec int, chr char(1) , isnum int,tryconvert int)
declare @loop int = 1
declare @i int
while @loop < 127
begin
    set @i = @loop
    insert into @temp (dec,chr,isnum,tryconvert)
    select @i,char(@i) charac, isnumeric(char(@i)), TRY_CONVERT(int,char(@i))
    set @loop = @loop + 1
end

select * from @temp where isnum = 1

答案 2 :(得分:0)

问题不在于您指向的行!

这一行没问题:

CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE -1 END

但是在第一种情况下,就在WHERE子句后面就有了这一行

CASE WHEN ISNUMERIC(subScores.ScoreValue) = 1 THEN CAST(subScores.ScoreValue AS REAL) ELSE subScores.ScoreValue END

它不能像ScoreValue不是数字一样工作,你有一个真实数据和varchar数据的情况(我猜ScoreValue是varchar)

您必须再次使用-1代替ScoreValue才能使其正常工作