我有一个函数可以将分隔的VARCHAR转换为INTs表。
IntSplit:
USE [master]
GO
/****** Object: UserDefinedFunction [dbo].[IntSplit] Script Date: 02/10/2016 15:17:06 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[IntSplit]
(
@String NVARCHAR(4000),
@Delimiter NCHAR(1)
)
RETURNS TABLE
AS
RETURN
(
WITH Split(stpos,endpos)
AS(
SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
UNION ALL
SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
FROM Split
WHERE endpos > 0
)
SELECT 'Data' = CONVERT(INT, SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos))
FROM Split
)
GO
当我在查询中运行它时:
SELECT * FROM IntSplit('1,2,3', ',')
我得到了预期的结果:
|Data
-+----
1| 1
2| 2
3| 3
我还有一个完全相同的存储过程(即调用函数)
my_int_split:
USE [master]
GO
/****** Object: StoredProcedure [dbo].[my_int_split] Script Date: 02/10/2016 15:29:16 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[my_int_split]
(@i_ids VARCHAR)
AS
-- Common set conditions
-- Explicity suppress count information
SET NOCOUNT ON
-- Unhandled exception aborts whole transaction
SET XACT_ABORT ON
-- Autocommit on
SET IMPLICIT_TRANSACTIONS OFF
-- UK datetime
SET DATEFORMAT dmy
--
SET NOCOUNT ON
--
BEGIN
SELECT * FROM IntSplit(@i_ids, ',')
END
GO
但是,如果我使用
运行存储过程my_int_split '1,2,3'
然后我只得到第一行作为结果
|Data
-+----
1| 1
据我所知,存储过程与查询完全相同,但只返回顶行。请注意,如果我输入一个'2,3,4'的VARCHAR,它将返回一行值为2的值,因此它不只是总是向后吐出1。
有什么想法吗?
答案 0 :(得分:3)
永远不要使用VARCHAR
没有长度,您的@i_ids
参数会被截断为1个字符。
如果您知道ID列表可能会有多长,请使用此指南来指定最大长度(加上一些松弛);否则使用VARCHAR(MAX)
,效率较低,但规模相当随意。
另外,避免混合使用NVARCHAR
(在函数中)和VARCHAR
(在SP中) - 这样做可能会因转换而导致性能下降。此外(虽然不适用于此特定情况)但它可能导致索引被跳过,因为数据类型不相同。
"搞笑"事实是,当没有给出长度时假定的长度不一致。有关详细信息,请参阅Aaron Bertrand's blog post。