【问题标题】:Stored procedure conversion failed when converting the varchar value to data type int?将 varchar 值转换为数据类型 int 时存储过程转换失败?
【发布时间】:2012-05-17 16:04:16
【问题描述】:

在我的存储过程中,我面临以下问题 - 我该如何解决?

CREATE PROC RupeshTest(@QueID int, @Answer varchar(250)) as
BEGIN
   DECLARE @STR varchar(4000) 

   SELECT @STR = COALESCE(@str + ';','') + AnswerText     
   FROM SurveyQuestionAnswerTypes 
   WHERE AnswerType = (SELECT AnswerType 
                       FROM SurveyQuestions 
                       WHERE QuestionID = CAST(@QueId AS VARCHAR(4))) 
                         AND AnswerValue IN (REPLACE(@Answer,'^',','))
END

当我运行它时

RupeshTest 25, '2^3^5^7^8' 

我收到以下错误

消息 245,级别 16,状态 1,过程 RupeshTest,第 4 行
将 varchar 值 '2,3,5,7,8' 转换为数据类型 int 时转换失败。

虽然我理解这个问题,但无法解决它,有人可以告诉我如何解决它。

【问题讨论】:

  • 我在替换功能中遇到问题..
  • 格式化工作得很好:-)
  • 您正在尝试神奇的编程 - 为什么您希望 SQL 语言在单个字符串参数中进行查看,并决定它应该将其拆分为逗号并将其转多个参数,当我知道没有其他编程语言可以做到这一点时?
  • 解决方案是将SQL命令制作/创建为字符串并运行它。

标签: c# asp.net sql-server tsql stored-procedures


【解决方案1】:

这行不通,因为最终形成的查询是:

SELECT @STR = COALESCE(@str + ';','') + AnswerText     
   FROM SurveyQuestionAnswerTypes 
   WHERE AnswerType = (SELECT AnswerType 
                       FROM SurveyQuestions 
                       WHERE QuestionID = CAST(@QueId AS VARCHAR(4))) 
                         AND AnswerValue IN ('2,3,5,7,8')

你想要这样的东西:

SELECT @STR = COALESCE(@str + ';','') + AnswerText     
   FROM SurveyQuestionAnswerTypes 
   WHERE AnswerType = (SELECT AnswerType 
                       FROM SurveyQuestions 
                       WHERE QuestionID = CAST(@QueId AS VARCHAR(4))) 
                         AND AnswerValue IN (2,3,5,7,8)

我建议您制作一个 UDF String_To_Table,将字符串传递给该 UDF 并用于 IN 子句。

String_To_Table UDF:

CREATE FUNCTION [dbo].[String_To_Table]
                    (@string      VARCHAR(4000),
                     @delimiter CHAR(1) = ';')
         RETURNS @tbl TABLE (ord INT IDENTITY(1, 1) NOT NULL,
                             token     VARCHAR(500)) AS

   BEGIN
      DECLARE @pos      int,
              @textpos  int,
              @chunklen smallint,
              @tmpstr   varchar(4000),
              @leftover varchar(4000),
              @tmpval   varchar(4000)

      SET @textpos = 1
      SET @leftover = ''
      WHILE @textpos <= datalength(@string)
      BEGIN
         SET @chunklen = 4000 - datalength(@leftover)
         SET @tmpstr = @leftover + substring(@string, @textpos, @chunklen)
         SET @textpos = @textpos + @chunklen

         SET @pos = charindex(@delimiter, @tmpstr)

         WHILE @pos > 0
         BEGIN
            SET @tmpval = ltrim(rtrim(left(@tmpstr, @pos - 1)))
            INSERT @tbl (token) VALUES(@tmpval)
            SET @tmpstr = substring(@tmpstr, @pos + 1, len(@tmpstr))
            SET @pos = charindex(@delimiter, @tmpstr)
         END

         SET @leftover = @tmpstr
      END

    IF ltrim(rtrim(@leftover)) <> ''
        INSERT @tbl(token) VALUES (ltrim(rtrim(@leftover)))


 RETURN
   END

然后你可以改变你的SP如下:

CREATE PROC RupeshTest(@QueID int, @Answer varchar(250)) as
BEGIN
   DECLARE @STR varchar(4000) 

   SELECT @STR = COALESCE(@str + ';','') + AnswerText     
   FROM SurveyQuestionAnswerTypes 
   WHERE AnswerType = (SELECT AnswerType 
                       FROM SurveyQuestions 
                       WHERE QuestionID = CAST(@QueId AS VARCHAR(4))) 
                         AND AnswerValue IN (SELECT Token FROM dbo.String_To_Table(@Answer,'^'))
END

【讨论】:

  • 有一天,MS 的某个人要向我解释为什么 SQL Server still 没有内置的“拆分”方法.
  • 重要的安全问题:OP 应该很确定输入字符串实际上不是1^2^3) DROP TABLE Students --^4
【解决方案2】:

您在这里面临的问题是AnswerValue IN (2,3,5,7,8) 部分以及如何使其成为有效的 SQL,因为这些值是整数列表并且您将它们作为字符串。对我来说,一个技巧是将所有 SQL 命令变成一个字符串并执行它:

DECLARE @SQLQuery AS varchar(4000)

SET SQLQuery = 
'SELECT AnswerText '
+ ' FROM SurveyQuestionAnswerTypes '
+ ' WHERE AnswerType = (SELECT AnswerType '
                   + ' FROM SurveyQuestions '
                   + ' WHERE QuestionID = ' + CAST(@QueId AS VARCHAR(4))) 
                    + ' AND AnswerValue IN (' + (REPLACE(@Answer,'^',',')) + ')'


EXECUTE(@SQLQuery)                  

顺便说一句,没有理由发送带有 ^ 的数字然后更改它。

【讨论】:

    【解决方案3】:

    您可以将最后一个条件替换为

    AND CHARINDEX(CONCAT("^", CAST(AnswerValue AS CHAR), "^"), CONCAT("^", @Answer, "^"))
    

    这似乎并不完全正确,但它可能会奏效。

    已编辑

    感谢指正。

    【讨论】:

    • 是的,我想通了。抱歉,我会解决的
    • LOCATE(MySQL) 或 CHARINDEX(MSSQL) 不会是一个好的解决方案。当输入像 RupeshTest 25, '112^233^225895^9967^1238' 结果将匹配 1,2,3,8,9,11,12,23,38 等组合时,SP 将失败/跨度>
    • 你是对的。也许应该是 CHARINDEX('^' + CAST(AnswerValue AS CHAR) + '^', '^' + @Answer + '^')
    • @avanigadhai 我无法评论您的答案,但您不应该在调用 String_To_Table 的子查询中选择 token 而不是 ID 吗?我对 mssql 不是很熟悉,所以我可能会遗漏一些东西。
    • 你是对的@PerroAzul。感谢您指出了这一点。我的错。会改正的。
    猜你喜欢
    • 2018-03-02
    • 2011-12-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多