在选择查询中使用varchar值时出现错误

时间:2019-02-16 11:01:59

标签: sql sql-server

我有一个名为“ TABLE_RELATION”的表。我想使用一些相关代码来过滤选择查询中的值。但是当我尝试使用IN运算符时遇到错误 ,当转换varchar值``301','302','303','304','305','306','时转换失败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时,它工作正常。

我该如何解决这个问题?

任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:0)

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

代码的一种简单方法是使用动态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;

答案 1 :(得分:0)

正在查看您的查询,但我觉得我遗漏了一些东西。只是怎么了?

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中即可。

答案 2 :(得分:0)

首先是数字列表。
像这样

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

答案 3 :(得分:0)

在许多不同的情况下,这种要求会多次出现。那么为什么不创建通用解决方案呢?

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

通用用户定义功能:

-- 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))

我希望这会对您有所帮助:)