【问题标题】:Getting error when varchar value used in select query在选择查询中使用 varchar 值时出现错误
【发布时间】:2019-02-16 11:01:59
【问题描述】:

我有一个名为“TABLE_RELATION”的表。我想使用一些关系代码来过滤选择查询中的值。但是当我尝试使用 IN 运算符时,在转换 varchar 值 ''301','302','303','304','305','306',' 时出现错误 Conversion failed 312'' 到数据类型 smallint。

RELATION_CODE 列是 smallint 类型。

declare @guar_tab varchar(max)
declare @guar_tab_VALUES varchar(max)
select @guar_tab=COALESCE(''+@guar_tab+''',''','''')+convert(varchar(100), RELATION_CODE) from TABLE_RELATION where RELATION_CODE>300 and RELATION_CODE<400
SET @guar_tab_VALUES=(select @guar_tab)+''''+''
SELECT @guar_tab_VALUES
select * from TABLE_RELATION where  RELATION_CODE in ( @guar_tab_VALUES)

当我尝试使用 '301','302','303','304','305','306','312' 而不是 @guar_tab_VALUES 时,它工作正常。

我该如何解决这个问题?

我们将不胜感激。

【问题讨论】:

  • 我不确定您的实际目标是什么,但您不能使用 标量 值/变量来代替列表。你所拥有的和WHERE RELATION_CODE IN ('''301'',''302'',''303'',''304'',''305'',''306'',''312''')一样,只是一长串。

标签: sql sql-server


【解决方案1】:

您不能传递这样的值列表。您正在传递一个带有单个值的字符串,该值恰好有一堆逗号。

一种简化代码的方法是使用动态 SQL:

declare @sql nvarchar(max);

set @sql = '
select *
from TABLE_RELATION
where RELATION_CODE in (@guar_tab_VALUES);
';

set @sql = replace(@sql, '@guar_tab_VALUEs', @guar_tab_VALUEs);

exec sp_executesql @sql;

【讨论】:

    【解决方案2】:

    查看您的查询,但我觉得我遗漏了一些东西。只是有什么问题:

    SELECT *
    FROM TABLE_RELATION
    WHERE RELATION_CODE > 300 AND RELATION_CODE < 400;
    

    您正在从表 TABLE_RELATION 创建一个分隔的值列表,然后返回所有这些行。从字面上看是没有意义的。根据我们所拥有的,不需要动态 SQL 或IN

    我们可以表达您所写的内容:

    SELECT *
    FROM TABLE_RELATION TR
    WHERE TR.RELATION_CODE IN (SELECT sq.RELATION_CODE
                               FROM TABLE_RELATION sq
                               WHERE sq.RELATION_CODE > 300
                                 AND sq.RELATION_CODE < 400);
    --or
    SELECT *
    FROM TABLE_RELATION TR
    WHERE EXISTS (SELECT 1
                  FROM TABLE_RELATION sq
                  WHERE sq.RELATION_CODE > 300
                    AND sq.RELATION_CODE < 400
                    AND TR.RELATION_CODE = sq.RELATION_CODE);
    

    如您所见,不需要子查询,只需将其放在主WHERE中即可。

    【讨论】:

      【解决方案3】:

      首先,它是数字列表。
      所以像这样的

      select * from table1 
      where col1 in ('1', '2', '3')
      

      可以写成

      select * from table1 
      where col1 IN (1, 2, 3)
      

      IN 接受值列表,或返回值列表的查询。
      因此,仅添加 1 个带有值的字符串是行不通的。
      F.e.如果 col1 是数字,这将不起作用。

      select * from table1 where col1 IN ('1,2,3')
      

      因为字符串 '1,2,3' 不能隐式转换为数字。

      使用查询可以工作

      select * from table1 
      where col1 IN (select n from nums where n between 1 and 9)
      

      如果您确实想使用包含数字列表的变量?
      然后使用表变量可能适合您。

      DECLARE @NumTbl TABLE (n smallint primary key);
      
      INSERT INTO @NumTbl (n) 
      SELECT DISTINCT RELATION_CODE
      FROM TABLE_RELATION 
      WHERE RELATION_CODE > 300
        AND RELATION_CODE < 400;
      
      declare @guar_tab_values varchar(max);
      
      select @guar_tab_values = concat(@guar_tab_values+', ', n) from @NumTbl order by n;
      
      select @guar_tab_values as guar_tab_values;
      
      SELECT * 
      FROM TABLE_RELATION 
      WHERE RELATION_CODE IN (select n from @NumTbl);
      

      在您的情况下,我只会在 WHERE 子句中使用这些标准。

      SELECT * 
      FROM TABLE_RELATION 
      WHERE RELATION_CODE > 300
        AND RELATION_CODE < 400
      

      【讨论】:

        【解决方案4】:

        这样的要求在许多不同的场景中多次出现。那么为什么不创建通用解决方案。

        我们可以创建用户定义函数来分割逗号分隔的字符串并以表格的形式返回数据。

        通用用户定义函数:

        -- FUNCTION TO SPLIT STRINGS.
        ALTER FUNCTION [dbo].[SplitString]
        ( @stringToSplit VARCHAR(MAX) )
        RETURNS
        @returnList TABLE ([Name] [nvarchar] (500))
        AS
        BEGIN
        
        DECLARE @name NVARCHAR(255)
        DECLARE @pos INT
        
        WHILE CHARINDEX(',', @stringToSplit) > 0
        BEGIN
          SELECT @pos  = CHARINDEX(',', @stringToSplit)
          SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)
        
          INSERT INTO @returnList
          SELECT @name
        
          SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
        END
        
        INSERT INTO @returnList
        SELECT @stringToSplit
        
        RETURN
        END
        

        调用使用定义函数:

        declare @guar_tab varchar(max)
        declare @guar_tab_VALUES varchar(max)
        select @guar_tab=COALESCE(''+@guar_tab+',','')+convert(varchar(100), RELATION_CODE) from TABLE_RELATION where RELATION_CODE>300 and RELATION_CODE<400
        select * from TABLE_RELATION where  RELATION_CODE in (SELECT[Name] FROM dbo.SplitString( @guar_tab))
        

        希望对你有帮助:)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-01-13
          • 1970-01-01
          • 2019-06-18
          • 1970-01-01
          • 1970-01-01
          • 2018-05-11
          • 2013-07-06
          • 1970-01-01
          相关资源
          最近更新 更多