2017-03-22 157 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

相關問題