我有一个函数,可以将分隔的 VARCHAR 转换为 INT 表。
内部分割:
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。
有什么想法吗?
最佳答案
切勿使用没有长度的 VARCHAR
,您的 @i_ids
参数将被截断为 1 个字符。
如果您知道 ID 列表可能会变得多长,请以此为指导来指定最大长度(加上一些余量);否则使用 VARCHAR(MAX) ,效率较低,但大小几乎任意。
此外,请避免混合使用 NVARCHAR
(在函数中)和 VARCHAR
(在 SP 中) - 这样做可能会因转换而导致性能下降。此外(虽然在这种特定情况下不适用),它可能会导致索引被跳过,因为数据类型不相同。
“有趣”的是,没有给出长度时假定的长度不一致。请参阅Aaron Bertrand's blog post了解更多详细信息。
关于SQL存储过程仅返回函数创建的表的第一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35320088/