处理在SQL中拆分字符串

时间:2014-12-24 15:22:16

标签: sql sql-server

目前,我正在开展一个项目,我们刚刚添加了在字段中存储多个值的功能。以前,它存储了一个值,但现在它包含多个值。以下是我所谈论的一个例子。

实施例。传递一个人的名字(John Smith)。现在,用户可以传递多个人的姓名,由''分隔。 (John Smith; John Doe; Jane Tandy)。

我的问题是,我们有一个下拉列表的数据源,该数据源当前从该字段开始。下面是它的SQL。

Select Distinct Content
From LIB_DocumentAttribute A
   inner join LIB_PublicDocument B on A.PublicDocumentId = B.PublicDocumentId 
Where AttributeId = (Select AttributeId From LIB_Attribute Where FieldName='Author')
   and B.Status = 'Approved'

这在某种程度上有效。内容是包含多个名称的字段。现在当加载下拉列表时,它会拉回串联的名称字符串(从上面开始的更长的名称)。我想将它拆分为数据源。到目前为止,我唯一的想法是根据''分出数据。但是,我需要将拆分数据并将其应用于返回其余数据的表。下面是我已经达到但已经陷入困境的地方。

CREATE TABLE #Authors
(
    Content varchar(MAX)
)
CREATE TABLE #Temp1
(
    Content varchar(MAX)
)
CREATE TABLE #Temp2
(
    Content varchar(MAX)
)
CREATE TABLE #Temp3
(
    Content varchar(MAX)
)

--Load Authors table to store all Authors
INSERT INTO #Authors
Select Distinct Content
    From LIB_DocumentAttribute A
        inner join LIB_PublicDocument B on A.PublicDocumentId = B.PublicDocumentId 
    Where AttributeId = (Select AttributeId From LIB_Attribute Where FieldName='Author')
        and B.Status = 'Approved'

--Take multiple Authors separated by '; ' and add to Temp1
INSERT INTO #Temp1
SELECT REPLACE(Content, '; ', ';') FROM #Authors WHERE Content LIKE '%; %'

--Remove multiple Authors separated by '; ' from Authors table
DELETE FROM #Authors
WHERE Content LIKE '%; %'

--Take multiple Authors separated by ';' and add to Temp2
INSERT INTO #Temp2
SELECT Content FROM #Authors WHERE Content LIKE '%;%'

--Remove multiple Authors separated by ';' from Authors table
DELETE FROM #Authors
WHERE Content LIKE '%;%'

--Somewhow split data and merge back together

DROP TABLE #Authors
DROP TABLE #Temp1
DROP TABLE #Temp2
DROP TABLE #Temp3

编辑:

所以最后,我提出了一个解决方案,利用了Kumar建议的一些部分。我创建了一个按照他的建议拆分字符串的函数,并添加了一些个人更改以使其工作。请注意,这是一个表返回函数,使用名为@Authors的表,它有一个名为Content的列。

BEGIN
DECLARE @Temp TABLE
(
    Content varchar(MAX)
)

--Load Authors table to store all Authors
INSERT INTO @Authors
    Select Distinct Content
    From LIB_DocumentAttribute A
        inner join LIB_PublicDocument B on A.PublicDocumentId = B.PublicDocumentId 
    Where AttributeId = (Select AttributeId From LIB_Attribute Where FieldName='Author')

--Take multiple Authors separated by ', ' and add to Temp
INSERT INTO @Temp
        SELECT REPLACE(Content, ', ', ',')
        FROM @Authors;

    --Remove multiple Authors separated by ', ' from Authors table
    DELETE FROM @Authors
    WHERE Content LIKE '%,%';


    --Readd multiple Authors now separated into Authors table
    INSERT INTO @Authors
        SELECT s.Content
        FROM @Temp
            OUTER APPLY SplitString(Content,',') AS s
        WHERE s.Content <> (SELECT TOP 1 a.Content FROM @Authors a WHERE s.Content = a.Content)

    RETURN
END

3 个答案:

答案 0 :(得分:1)

在fiddler链接http://sqlfiddle.com/#!3/390f8/11

中查看演示
Create table test(name varchar(1000));

    Insert into test values('AAA BBB; CCC DDD; eee fff');
    CREATE FUNCTION SplitString
    (    
          @Input NVARCHAR(MAX),
          @Character CHAR(1)
    )
    RETURNS @Output TABLE (
          Item NVARCHAR(1000)
    )
    AS
    BEGIN
          DECLARE @StartIndex INT, @EndIndex INT

          SET @StartIndex = 1
          IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
          BEGIN
                SET @Input = @Input + @Character
          END

          WHILE CHARINDEX(@Character, @Input) > 0
          BEGIN
                SET @EndIndex = CHARINDEX(@Character, @Input)

                INSERT INTO @Output(Item)
                SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)

                SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
          END

          RETURN
    END



Declare @name varchar(100)
Declare @table as table(name varchar(1000))
Declare cur cursor for
Select name from test

Open cur
fetch next from cur into @name
while (@@FETCH_STATUS = 0)
begin
Insert into @table
   Select * from dbo.splitstring(@name,';')
    fetch next from cur into @name
end
close cur
deallocate cur


Select * from @table

答案 1 :(得分:1)

这可能有用。

drop table authors
GO
create table Authors (Author_ID int identity (1,1),name varchar (255), category varchar(255))
GO
insert into authors
(name,category)
select 
'jane doe','nonfiction'
union 
select
'Jules Verne; Mark Twain; O. Henry', 'fiction'
union 
select 
'John Smith; John Doe', 'nonfiction'
GO
DECLARE @table TABLE (
names VARCHAR(255)
,id INT
)
DECLARE @category VARCHAR(255)

SET @category = 'nonfiction'

DECLARE @Author_ID INT

DECLARE AuthorLookup CURSOR
FOR
SELECT Author_ID
FROM authors
WHERE category = @category

OPEN AuthorLookup

FETCH NEXT
FROM AuthorLookup
INTO @Author_ID

WHILE @@FETCH_STATUS = 0
BEGIN
IF (
        SELECT CHARINDEX(';', NAME, 0)
        FROM authors
        WHERE Author_ID = @Author_ID
        ) = 0
BEGIN
    INSERT INTO @table
    SELECT NAME
        ,Author_ID
    FROM authors
    WHERE Author_ID = @Author_ID
END
ELSE
BEGIN
    DECLARE @value VARCHAR(255)

    SELECT @value = NAME
    FROM authors
    WHERE Author_ID = @Author_ID

    WHILE len(@value) > 0
    BEGIN
        INSERT INTO @table
        SELECT substring(@value, 0, CHARINDEX(';', @value, 0))
            ,@Author_ID

        SELECT @value = replace(@value, substring(@value, 0, CHARINDEX(';', @value, 0) + 2), '')

        IF CHARINDEX(';', @value, 0) = 0
        BEGIN
            INSERT INTO @table
            SELECT @value
                ,@Author_ID

            SET @value = ''
        END
    END
END

FETCH NEXT
FROM AuthorLookup
INTO @Author_ID
END

CLOSE AuthorLookup

DEALLOCATE AuthorLookup

SELECT *
FROM @table

答案 2 :(得分:0)

您可以创建分割数据的功能

create function SplitString
(    
   @data nvarchar(max),
   @sep char(1)
)
returns @result table (data nvarchar(max))
as
begin
  declare @i int

  while 1 = 1
  begin
    select @i = charindex(@sep, @data)

    if @i = 0
    begin
      insert into @result
      select @data

      break
    end

    insert into @result
    select rtrim(left(@data, @i - 1))

    select @data = ltrim(right(@data, len(@data) - @i))
  end

  return
end

并像这样使用它:

select s.data
from test as t
    outer apply SplitString(t.data,';') as s

如果你确定数据中没有特殊字符,你也可以考虑使用xml技巧:

;with cte as (
    select
        cast('<s>' + replace(data, ';', '</s><s>') + '</s>' as xml) as data
    from test
)
select
    t.c.value('.', 'nvarchar(max)') as data
from cte
    outer apply data.nodes('s') as t(c)

<强> sql fiddle demo