table 值函数的子查询不起作用

subquery with table value function not working

DECLARE @temp AS TABLE (id INT, NAME VARCHAR(20) )

DECLARE @str VARCHAR(20) = '1,2'

INSERT INTO @temp (id, NAME)
VALUES (1, ''), (2, ''), (2, '')

SELECT * 
FROM @temp a
WHERE id IN ((SELECT String FROM dbo.FN_SplitStrings(@str,',')))

我在 运行 这个

时收到以下错误

Conversion failed when converting the varchar value '1,2' to data type int.

代码:

CREATE function [dbo].[FN_SplitStrings] 
( 
   @StringToSplit varchar(8000), 
   @Separator varchar(128)
) 
RETURN TABLE 
AS 
   RETURN 
     with indices as 
     ( 
        select 
            0 S, 1 E 
        union all 
        select 
            E, charindex(@Separator, @StringToSplit, E) + len(@Separator) 
        from 
            indices 
        where E > S
     ) 
     select 
         substring(@StringToSplit,S, case when E > len(@Separator) 
 then e-s-len(@Separator) else len(@StringToSplit) - s + 1 end) String ,
         S StartIndex 
     from 
         indices 
     where 
         S > 0 

试试这个。这个拆分可以不用函数

DECLARE @temp AS TABLE
(
   id INT,
   NAME VARCHAR(20)
)

DECLARE @str VARCHAR(20)='1,2'
INSERT INTO @temp
        ( id, NAME )
VALUES  ( 1, '' ),
         ( 2, ''),
         ( 2, '')

SELECT * FROM @temp a
 WHERE id IN 
 (
        SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'KeyWords' 
        FROM  
        (
             -- To change ',' to any other delimeter, just change ',' before '</M><M>' to your desired one
             SELECT CAST ('<M>' + REPLACE(@str, ',', '</M><M>') + '</M>' AS XML) AS Data                
        ) AS A 
        CROSS APPLY Data.nodes ('/M') AS Split(a)
)

编辑:

你的拆分功能有问题

函数

ALTER FUNCTION dbo.FN_SplitStrings(@StringToSplit varchar(8000),@Separator char(1))
RETURNS table
AS
RETURN (
    WITH splitter_cte AS (
      SELECT CHARINDEX(@Separator, @StringToSplit) as pos, 0 as lastPos
      UNION ALL
      SELECT CHARINDEX(@Separator, @StringToSplit, pos + 1), pos
      FROM splitter_cte
      WHERE pos > 0
    )
    SELECT SUBSTRING(@StringToSplit, lastPos + 1,
                     case when pos = 0 then 80000
                     else pos - lastPos -1 end) as String
    FROM splitter_cte
  )

查询

DECLARE @temp AS TABLE (id INT, NAME VARCHAR(20) )

DECLARE @str VARCHAR(20) = '1,2'

INSERT INTO @temp (id, NAME)
VALUES (1, ''), (2, ''), (2, '')

SELECT * 
FROM @temp a
WHERE id IN ((SELECT String FROM dbo.FN_SplitStrings(@str,',')))

原因是混合了数据类型,而且您的函数是内联 table 值函数,这意味着它在查询优化发生之前嵌入到查询中。

如果从函数中删除 where S > 0 并使用 1,2 执行它,函数的结果是:

String
------
1,2
1
2

注意第一行的值为 1,2

当优化器对您的查询执行其工作时,将在计算函数的 where 子句之前完成与列 id 的比较。在那个比较中,你有一个隐式转换为 int 并且 1,2 不能转换为 int.

要解决此问题,您可以确保拆分函数的字符串列始终是 int(并可能在此过程中更改列的名称)。

 select 
     cast(substring(@StringToSplit,S, case when E > len(@Separator) 
                                   then e-s-len(@Separator) 
                                   else len(@StringToSplit) - s + 1 
                                 end) as int) String ,