在选择请求中拆分varchar

时间:2016-04-21 14:29:31

标签: sql sql-server tsql

我有一个列调用Title,我需要使用以下分隔符将其拆分为3:<BR>。如果标题为空,我必须将三列设置为空

我使用一个填充了多行的临时表,我希望在插入临时表时分割Title

这是我桌子的快照:

CREATE TABLE #tempResults (
        [...]
        EMM_TITLE nvarchar(255),
        TITLE_LINE_1 nvarchar(255), 
        TITLE_LINE_2 nvarchar(255), 
        TITLE_LINE_3 nvarchar(255))

这是我的插入请求。第EMM_TITLE行是从数据库中检索的

INSERT INTO [#tempResults]
        SELECT 
         [...]
         'Fooooo<BR>Fooooo2<BR>Foooooo3'
         '' -- Expect : Fooooo
         '' -- Expect : Fooooo2
         '' -- Expect : Foooooo3

如果TITLE为空,我怎么可能将列分成三列并设置为空?

我发现有关类似问题的帖子,但无法将其应用于我的案例: Link

2 个答案:

答案 0 :(得分:2)

此分割功能可能有助于开始:

CREATE FUNCTION [dbo].[Split]
(
    @RowData nvarchar(2000),
    @SplitOn nvarchar(5)
)  
RETURNS @RtnValue table 
(
    Id int identity(1,1),
    Data nvarchar(100)
) 
AS  
BEGIN 
    Declare @Cnt int
    Set @Cnt = 1

    While (Charindex(@SplitOn,@RowData)>0)
    Begin
        Insert Into @RtnValue (data)
        Select 
            Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))

        Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+len(@SplitOn),len(@RowData))
        Set @Cnt = @Cnt + 1
    End

    Insert Into @RtnValue (data)
    Select Data = ltrim(rtrim(@RowData))

    Return
END

GO

您可以像以下一样使用它:

SELECT * FROM dbo.Split('Fooooo<BR>Fooooo2<BR>Foooooo3','<BR>')

......甚至更好,将它与以下功能结合使用:

CREATE FUNCTION Word 
(
    @Input  nvarchar(max),
    @Delim  nvarchar(10),
    @Item   int
)
RETURNS nvarchar(max)
AS
BEGIN
    DECLARE @result nvarchar(max)

    SELECT  @result = Data
    FROM    dbo.Split(@Input, @Delim)
    WHERE   Id = @Item

    RETURN @Result

END

例如:

UPDATE  #tempTable
SET     TITLE_LINE_1 =  dbo.Word(EMM_TITLE ,'<BR>',1),
        TITLE_LINE_2 =  dbo.Word(EMM_TITLE ,'<BR>',2),
        TITLE_LINE_3 =  dbo.Word(EMM_TITLE ,'<BR>',3)

答案 1 :(得分:0)

这是另一种不需要循环的方法。它比在多语句表值函数中使用循环要快得多。这项技术非常依赖于Jeff Moden和sql server central社区的精彩工作。这是我所指的文章。 http://www.sqlservercentral.com/articles/Tally+Table/72993/

if OBJECT_ID('DelimitedSplit8K_LongDelimiter') is not null
    drop function DelimitedSplit8K_LongDelimiter
GO

CREATE FUNCTION [dbo].[DelimitedSplit8K_LongDelimiter]
(
    @pString VARCHAR(8000)
    , @pDelimiter VARCHAR(10)
)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...


WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 FROM E4
    ),
    cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT t.N + 1
                   FROM cteTally t
                  WHERE (SUBSTRING(@pString, t.N, DATALENGTH(@pDelimiter)) = @pDelimiter OR t.N = 0) 
                )

--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
select ItemNumber = ROW_NUMBER() OVER(ORDER BY s.N1)
    , Item = SUBSTRING(@pString, Case when s.N1 = 1 then 1 else s.N1 + (DATALENGTH(@pDelimiter) - 1) end, 
        ISNULL(
                NULLIF(
                    CHARINDEX(@pDelimiter, @pString, s.N1 )
                    ,0)
                    - Case when s.N1 = 1 then 1 else s.N1 + (DATALENGTH(@pDelimiter) - 1) end,8000)
    )