【发布时间】:2013-03-27 05:38:08
【问题描述】:
我有一个用户定义的函数,可以将整数列表拆分为值表。我正在使用它来解析输入以选择一组给定类型或状态的记录。
这行得通:
select * from RequestStatus
where RequestStatusUID in (select [value] from dbo.SplitIDs('1,2,3', ','))
这不是:
select * from Requests
where RequestStatusUID in (select [value] from dbo.SplitIDs('1,2,3', ','))
Requests 查询返回错误“将 varchar 值 '1,2,3' 转换为数据类型 int 时转换失败。”两个表上的 RequestStatusUID 都是 int 列。两个解释计划在我看来都是一样的。该函数在不相关的查询中的工作方式完全相同。据我所知,只有 Requests 表有问题。
CREATE TABLE [dbo].[Requests] (
[RequestUID] int IDENTITY(1,1) NOT NULL,
[UserUID] int NOT NULL,
[LocationUID] int NOT NULL,
[DateOpened] date NULL,
[DateClosed] date NULL,
[RequestStatusUID] int NOT NULL,
[DiscussionUID] int NULL,
[RequestTypeUID] int NOT NULL,
[RequestNo] varchar(16) NOT NULL,
[LastUpdateUID] int NOT NULL,
[LastUpdated] date NOT NULL,
CONSTRAINT [PK_Requests] PRIMARY KEY NONCLUSTERED([RequestUID])
如果我使用返回 varchars 的不同函数并将 RequestStatusUID 列也转换为 varchar,它确实有效:
select * from Requests
where cast(RequestStatusUID as varchar(4)) in (select [value] from dbo.Split('1,2,3', ','))
作为参考,我正在使用的 SplitIDs 函数(Arnold Fribble's solution 的修改版本)。 Split 函数与最后没有强制转换为 int 相同:
ALTER FUNCTION [dbo].[SplitIDs] ( @str VARCHAR(MAX), @delim char(1)=',' )
RETURNS TABLE
AS
RETURN
(
with cte as (
select 0 a, 1 b
union all
select b, cast(charindex(@delim, @str, b) + 1 as int)
from cte
where b > a
)
select cast(substring(@str,a,
case when b > 1 then b-a-1 else len(@str) - a + 1 end) as int) [value]
from cte where a >0
)
我可以使用转换为字符串的解决方案,但我真的很想知道为什么这首先会失败。
【问题讨论】:
-
另外,从 Requests 中选择 *,其中 (1,2,3) 中的 RequestStatusUID 可以正常工作。只是我需要在那里有一个变量而不是字符串文字。
-
我无法重现,即使我在函数末尾去掉了显式转换。你能在 sqlfiddle.com 上设置一个完整的重现吗?您是否也尝试过任何返回 INT 的 其他 TVF,或者您是否与此特定功能结婚?由于观察到的性能问题,我倾向于远离 TVF 中的递归 CTE 方法。
-
在添加外键约束之前,我无法在 sqlfiddle.com 上重现它...link
-
看到了吗?丢失的信息。什么外键约束。
-
到状态表。但是,我再次删除它后,问题仍然存在。 sqlfiddle
标签: sql-server-2008 split type-conversion