如何将此逗号分隔列与新表分隔

时间:2010-08-03 14:36:35

标签: sql sql-server

你好经验的SQL'rs ......

我遇到了一个小问题(SQLServer 2005),我遇到了遗留表(我老实说,我没有试图掩盖我的尴尬 - 这是一张旧表:-))。基本上,由于原始编码器最熟悉的原因,其中一列用于记录表中所指对象的状态变化(在这种情况下,是物业预订)。此单个列(修订单)将作为逗号分隔列表附加,然后被拉回到应用程序(.net应用程序)中。该字符串被解析为单独的行。到现在为止还挺好'。但是,我现在的任务是将此列标准化为单独的行作为单独的行。下面是它的外观和我希望实现的目的:

current bookingdetail table
bookingdetailid | amendmentnote | other fields....
-------------------------------------------------------------------
145               16/07/2010 14:15:02: New,29/07/2010 15:09:42: Booking status change from On Option to Cancelled,
146               19/07/2010 12:34:05: New,


proposed denormailzed booking_amendment_notes table
bookingdetailid | amendmentnote
-------------------------------------------------------------------
145               16/07/2010 14:15:02: New
145               Booking status change from On Option to Cancelled 
145               
146               19/07/2010 12:34:05: New
146               

正如你所看到的,它非常可怕。每个新行都添加一个尾随逗号,然后在应用程序内部进行解析,并忽略“空白”最终逗号条目(因为这将是最后一个逗号后的空格)。我已经采购了几个“几乎”通过Google完成工作的例程,但是由于该尾随逗号的性质,例程会选取最后一个条目并将其附加到下一个后续条目,从而在每个条目上输入错误最后一排。这有时是一个空行,但通常是下一行的值。

无论如何,这是我正在使用的例程。希望有人能够看到一个适当的“if”语句测试,以便将其引导到正确的方向。无论如何,功能:

    ALTER FUNCTION dbo.fn_Split
    (@sText varchar(8000), @sDelim varchar(20) = ' ')
    RETURNS @retArray TABLE (idx smallint Primary Key, value varchar(8000))
    AS
    BEGIN
    DECLARE @idx smallint,
          @value varchar(8000),
          @bcontinue bit,
          @iStrike smallint,
          @iDelimlength tinyint

    IF @sDelim = 'Space'
          BEGIN
          SET @sDelim = ' '
          END

    SET @idx = 0
    SET @sText = LTrim(RTrim(@sText))
    SET @iDelimlength = DATALENGTH(@sDelim)
    SET @bcontinue = 1

    IF NOT ((@iDelimlength = 0) or (@sDelim = 'Empty'))
          BEGIN
          WHILE @bcontinue = 1
                BEGIN

    --If you can find the delimiter in the text, retrieve the first element and
    --insert it with its index into the return table.

                IF CHARINDEX(@sDelim, @sText)>0
                      BEGIN
                      SET @value = SUBSTRING(@sText,1, CHARINDEX(@sDelim,@sText)-1)
                            BEGIN
                            INSERT @retArray (idx, value)
                            VALUES (@idx, @value)
                            END

    --Trim the element and its delimiter from the front of the string.
                      --Increment the index and loop.
    SET @iStrike = DATALENGTH(@value) + @iDelimlength
                      SET @idx = @idx + 1
                      SET @sText = LTrim(Right(@sText,DATALENGTH(@sText) - @iStrike))

                      END
                ELSE
                      BEGIN
    --If you can’t find the delimiter in the text, @sText is the last value in
    --@retArray.
     SET @value = @sText
                            BEGIN
                            INSERT @retArray (idx, value)
                            VALUES (@idx, @value)
                            END
                      --Exit the WHILE loop.
    SET @bcontinue = 0
                      END
                END
          END
    ELSE
          BEGIN
          WHILE @bcontinue=1
                BEGIN
                --If the delimiter is an empty string, check for remaining text
                --instead of a delimiter. Insert the first character into the
                --retArray table. Trim the character from the front of the string.
    --Increment the index and loop.
                IF DATALENGTH(@sText)>1
                      BEGIN
                      SET @value = SUBSTRING(@sText,1,1)
                            BEGIN
                            INSERT @retArray (idx, value)
                            VALUES (@idx, @value)
                            END
                      SET @idx = @idx+1
                      SET @sText = SUBSTRING(@sText,2,DATALENGTH(@sText)-1)

                      END
                ELSE
                      BEGIN
                      --One character remains.
                      --Insert the character, and exit the WHILE loop.
                      INSERT @retArray (idx, value)
                      VALUES (@idx, @sText)
                      SET @bcontinue = 0      
                      END
          END

    END

    RETURN
    END

和sp:

    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[USP_SPLIT_COLUMN] AS
    DECLARE CUR_TABLE CURSOR FOR
    SELECT bookingdetailid,amendmentnote
    FROM DBO.bookingdetail
    DECLARE @bookingdetailid varchar(50),
    @amendmentnote varchar(8000)

    BEGIN
         CREATE TABLE #tmp (bookingdetailid varchar(50),amendmentnote varchar(7800))
         OPEN CUR_TABLE
         FETCH NEXT FROM CUR_TABLE
         INTO @bookingdetailid,@amendmentnote
         WHILE @@FETCH_STATUS = 0 
         BEGIN
             INSERT INTO #tmp(bookingdetailid,amendmentnote)
             SELECT @bookingdetailid, value amendmentnote
             FROM DBO.FN_SPLIT(@amendmentnote,',') 
             FETCH NEXT FROM CUR_TABLE
             INTO @bookingdetailid,@amendmentnote
         END
         CLOSE CUR_TABLE
         DEALLOCATE CUR_TABLE
         SELECT * FROM #tmp 
         RETURN
    END

[更新] - 这是我为了让它发挥作用所做的改变:

    set ANSI_NULLS ON
    set QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[USP_SPLIT_COLUMN] AS
    DECLARE CUR_TABLE CURSOR FOR
    SELECT bookingdetailid,amendmentnote
    FROM DBO.bookingdetail
    DECLARE @bookingdetailid varchar(50),
    @amendmentnote varchar(8000)

    BEGIN
         CREATE TABLE #tmp (bookingdetailid varchar(50),amendmentnote varchar(7800))
         OPEN CUR_TABLE
         FETCH NEXT FROM CUR_TABLE
         INTO @bookingdetailid,@amendmentnote
           select @amendmentnote = left(@amendmentnote,Len(@amendmentnote)-1) 
         WHILE @@FETCH_STATUS = 0 
         BEGIN
             INSERT INTO #tmp(bookingdetailid,amendmentnote)
             SELECT @bookingdetailid, value amendmentnote
             FROM DBO.FN_SPLIT(@amendmentnote,',') 
             FETCH NEXT FROM CUR_TABLE
             INTO @bookingdetailid,@amendmentnote
             if right(@amendmentnote,1)=','
             begin
             select @amendmentnote = left(@amendmentnote,Len(@amendmentnote)-1) 
             end
         END
         CLOSE CUR_TABLE
         DEALLOCATE CUR_TABLE
         SELECT * FROM #tmp 
         RETURN
    END

用法:

DECLARE @V_RC INT
EXEC @V_RC = DBO.USP_SPLIT_COLUMN

如果没有足够的信息,请告诉我。

由于

吉姆

btw - 由于各种原因,无法在.net中运行例程并将其保存到表中,因此它必须是SQL解决方案。

1 个答案:

答案 0 :(得分:2)

在分割例程

之前,您只需要一个TRIM(my_horrible_string, ',')