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)
)
- Click here查看结果
编辑:
你的拆分功能有问题
函数
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 ,
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)
)
- Click here查看结果
编辑:
你的拆分功能有问题
函数
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 ,