SQL Server转换失败varchar到int

时间:2016-09-22 16:36:34

标签: sql-server

我有一张表(1号),有10列。其中一个clm01是整数,不允许使用空值。

有第二个表(第2个),它有很多列。其中一个是字符串类型clm02。此列数据的示例是1,2,3

我想提出类似的查询:

select *  
from table1 t1, table2 t2 
where t1.clm01 not in (t2.clm2)

例如,在表1中,我有5条记录,其值为clm01 1,2,3,4,5,而在表格2中,我有{1}}中有1条值的记录

所以我希望查询只返回clm02 = 1,2,3中值为45的记录。

相反,我得到:

  

转换varchar值时转换失败' 1,2,3'到数据类型int

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

如果您使用的是SQL Server 2016,请使用STRING_SPLIT()函数拆分逗号分隔值。

   SELECT *
   FROM table1 t1
   WHERE t1.clm1 NOT IN (SELECT Value FROM table2 t2
                     CROSS APPLY STRING_SPLIT(t2.clm2,','))

如果您使用任何较低版本的SQL Server,请编写UDF以拆分字符串并使用CROSS APPLY子句中的函数。

   CREATE FUNCTION [dbo].[SplitString] 
    ( 
      @string NVARCHAR(MAX), 
      @delimiter CHAR(1) 
      ) 
      RETURNS @output TABLE(Value NVARCHAR(MAX) 
     ) 
    BEGIN 
      DECLARE @start INT, @end INT 
      SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
     WHILE @start < LEN(@string) + 1 BEGIN 
      IF @end = 0  
        SET @end = LEN(@string) + 1

        INSERT INTO @output (Value)  
        VALUES(SUBSTRING(@string, @start, @end - @start)) 
         SET @start = @end + 1 
         SET @end = CHARINDEX(@delimiter, @string, @start)

           END 
           RETURN 
         END

答案 1 :(得分:0)

我决定给你一些选择,但这确实是我经常看到的重复问题。

有两种主要方法可以解决这个问题。

1)使用LIKE来比较字符串,但实际上你必须有点奇怪地构建字符串:

SELECT *
FROM
    @Table1 t1
WHERE
    NOT EXISTS (SELECT * 
             FROM @Table2 t2
             WHERE ',' + t2.clm02 + ',' LIKE '%,' + CAST(t1.clm01 AS VARCHAR(15)) + ',%')

你看到的是1,2,3,就像%,clm01value,%你必须在字符串中添加分隔符才能使其正常工作,你必须将clm01转换/转换为char数据类型。这个解决方案有一些缺点,但如果您的数据集很直接,那么它可能适合您。

2)将逗号分隔的字符串拆分为行,然后使用左连接,不存在或不存在。这是将csv转换为xml然后拆分的方法

;WITH cteClm02Split AS (
SELECT
    clm02
FROM
    (SELECT
       CAST('<X>' + REPLACE(clm02,',','</X><X>') + '</X>' AS XML) as xclm02
    FROM
       @Table2) t
       CROSS APPLY (SELECT t.n.value('.','INT') clm02
                 FROM
                t.xclm02.nodes('X') as t(n)) ca
)

SELECT t1.*
FROM
    @Table1 t1
    LEFT JOIN cteClm02Split t2
    ON t1.clm01 = t2.clm02
WHERE
    t2.clm02 IS NULL

或者使用NOT EXISTS与相同的cte

SELECT t1.*
FROM
    @Table1 t1
WHERE
    NOT EXISTS (SELECT * FROM cteClm02Split t2 WHERE t1.clm01 = t2.clm02)

有许多其他方法可以分割分隔的字符串,您可以选择适合您的任何方式。

注意:我没有显示IN / NOT IN作为答案,因为我不建议使用它。如果您确实使用它,请确保您永远不会在选择等中比较NULL。这是关于性能等的另一篇好帖子。NOT IN vs NOT EXISTS

这里是使用的表变量:

DECLARE @Table1 AS TABLE (clm01 INT)
DECLARE @Table2 AS TABLE (clm02 VARCHAR(15))
INSERT INTO @Table1 VALUES (1),(2),(3),(4),(5)
INSERT INTO @Table2 VALUES ('1,2,3')