2017-03-22 145 views
1

我正在尝试做一个内部使用过程只有它的一部分,你可以添加一个由逗号分隔的标签的字符串。字符串拆分只返回第一个条目

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE PROCEDURE AddService 
    @ServiceName AS VARCHAR(MAX), 
    @Location AS VARCHAR(MAX), 
    @Description AS VARCHAR(MAX), 
    @PermissionType AS INT, 
    @Tags AS VARCHAR(MAX) 
AS 
BEGIN 
    DECLARE @ServiceId AS INT 

    INSERT INTO Services(NAME,LOCATION,DESCRIPTION,PERMISSIONTYPE) VALUES(@ServiceName,@Location,@Description,@PermissionType) 
    SET @ServiceId = (SELECT SCOPE_IDENTITY()) 

    DECLARE @TagSplit TABLE(ID INT IDENTITY(1,1),DATA VARCHAR(MAX)) 
    INSERT @TagSplit VALUES(SUBSTRING(@Tags,0,CHARINDEX(',',@Tags))) 

    WHILE EXISTS(SELECT * FROM @TagSplit) 
    BEGIN 
     DECLARE @TempId AS INT 
     DECLARE @Tag AS VARCHAR(MAX) 

     SET @TempId = (SELECT TOP 1 ID FROM @TagSplit) 
     SET @Tag = (SELECT TOP 1 DATA FROM @TagSplit) 

     INSERT INTO Tags VALUES(@ServiceId,@Tag) 

     DELETE FROM @TagSplit WHERE ID = @TempId 
    END 
END 
GO 

但是,当我看着我的“标签”表中,给出的@Tags字符串“一些事”只能“部分”被添加,但不是“东西”。我想我可能会误解如何在SQL中进行正确的字符串分割。

这部分不正常工作:

WHILE EXISTS(SELECT * FROM @TagSplit) 
BEGIN 
    DECLARE @TempId AS INT 
    DECLARE @Tag AS VARCHAR(MAX) 

    SET @TempId = (SELECT TOP 1 ID FROM @TagSplit) 
    SET @Tag = (SELECT TOP 1 DATA FROM @TagSplit) 

    INSERT INTO Tags VALUES(@ServiceId,@Tag) 

    DELETE FROM @TagSplit WHERE ID = @TempId 
END 

任何帮助吗?

+0

为什么不使用的数据类型* *设计用于容纳多个值,如表或XML,而不是给自己包含逗号的字符串? –

+0

@Damien_The_Unbeliever我只是觉得这很容易,因为这将被使用的方式只需右键单击数据库管理器中的过程,然后单击“执行”。 – OmniOwl

回答

2

尝试使用CSV分离器表值函数由杰夫MODEN

create function [dbo].[delimitedsplit8K] (
     @pstring varchar(8000) 
    , @pdelimiter char(1) 
) 
returns table with schemabinding as 
return 
    with e1(N) as (
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all select 1 
) 
    , e2(N) as (select 1 from e1 a, e1 b) 
    , e4(N) as (select 1 from e2 a, e2 b) 
    , ctetally(N) as (
    select top (isnull(datalength(@pstring),0)) 
     row_number() over (order by (select null)) from e4 
) 
    , ctestart(N1) as (
    select 1 union all 
    select t.N+1 from ctetally t where substring(@pstring,t.N,1) = @pdelimiter 
) 
    , ctelen(N1,L1) as (
    select s.N1, 
     isnull(nullif(charindex(@pdelimiter,@pstring,s.N1),0)-s.N1,8000) 
    from ctestart s 
) 
select itemnumber = row_number() over(order by l.N1) 
     , item  = substring(@pstring, l.N1, l.L1) 
    from ctelen l 
; 
go 

分割字符串参考:

那么你的程序变成这样:

CREATE PROCEDURE AddService 
    @ServiceName AS VARCHAR(MAX), 
    @Location AS VARCHAR(MAX), 
    @Description AS VARCHAR(MAX), 
    @PermissionType AS INT, 
    @Tags AS VARCHAR(MAX) 
AS 
BEGIN 
    set nocount, xact_abort on; 

    DECLARE @ServiceId AS INT; 

    INSERT INTO Services(NAME,LOCATION,DESCRIPTION,PERMISSIONTYPE) 
    VALUES(@ServiceName,@Location,@Description,@PermissionType) 

    SET @ServiceId = (SELECT SCOPE_IDENTITY()); 

    insert into tags 
    select @ServiceId, s.Item 
    from [dbo].[delimitedsplit8K](@Tags,',') s; 
end 
go 
+0

这看起来很复杂。从我发现的大多数解决方案来看,它看起来并不复杂。你确定这个功能是必须的吗? – OmniOwl

+1

@Vipar如果您使用的是sql server 2016,则可以使用'string_split()'来代替。否则,这是不使用CLR功能的最好方法之一。如果你想要2016年以前的字符串拆分的其他选项,我参考的文章中有很多。 – SqlZim

+0

最后我用了另一个更简单的解决方案,但我将把它作为正确的解决方案。 – OmniOwl