你好经验的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解决方案。
答案 0 :(得分:2)
在分割例程
之前,您只需要一个TRIM(my_horrible_string, ',')