SQL存储过程只返回由函数创建的第一行表

时间:2016-02-10 16:05:13

标签: sql sql-server

我有一个函数可以将分隔的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。

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

永远不要使用VARCHAR没有长度,您的@i_ids参数会被截断为1个字符。

如果您知道ID列表可能会有多长,请使用此指南来指定最大长度(加上一些松弛);否则使用VARCHAR(MAX),效率较低,但规模相当随意。

另外,避免混合使用NVARCHAR(在函数中)和VARCHAR(在SP中) - 这样做可能会因转换而导致性能下降。此外(虽然不适用于此特定情况)但它可能导致索引被跳过,因为数据类型不相同。

"搞笑"事实是,当没有给出长度时假定的长度不一致。有关详细信息,请参阅Aaron Bertrand's blog post