拆分长度为nvarchar(120)的字符串,而不会破坏SQL Server中的单词

时间:2013-10-26 20:07:42

标签: sql sql-server sql-server-2008

我在同一个数据库中有两个表。

表1, New_Company_Data 它包含“Company_Name”列nvarchar(120),其中包含公司名称。

和表2, Old_Company_data 它有3列“Name1”nvarchar(40),“Name2”nvarchar(40)和“Name3”nvarchar(40)。

我想将表格 New_Company_Data 中的数据复制到表格 Old_Company_Data ,但在此之前我必须拆分“Company_Name”列中的公司名称。我试图将它分开,但它打破了这些话。

如何在“Company_Name”字段中拆分数据,而不会以下列方式打破单词:

如果公司名称是< = 40,则不要拆分。

如果公司名称>>< = 80,则将其分成两部分而不会破坏单词。

如果公司名称> 80且<= 120,则将其分成三部分而不会破坏单词。

我正在使用以下代码,但它没有正确生成结果。例如,在下面的代码中,我将string2称为“ik u”。但在这里我想要接下来的40个字符。

declare @strs nvarchar(120)

set @strs = 'AlufinishGesellschaftfür Verfahrenstechnik u. zur 

Metalloberflächenbehandlung mbH & C' --40

declare @lon int
declare @palabras int
declare @contador int
declare @posicion int
declare @string1 nvarchar(40)
declare @string2 nvarchar(40)
declare @string3 nvarchar(40)

--wordcount
set @palabras = LEN(@strs)-LEN(replace(@strs, ' ', ''))+1 --3
--words per batch

if (LEN(@strs)<=40) set @lon = @palabras
if (LEN(@strs)>40 AND LEN(@strs)<=80) set @lon = @palabras/2 --3 
if (LEN(@strs)>80 AND LEN(@strs)<=120) set @lon = @palabras/3

--set @lon = @palabras/3
set @contador = 1
set @posicion = 0
while @contador <= @lon
begin
-- search for the first batch
    set @posicion = CHARINDEX(' ',@strs,@posicion+1)-- here it will found 1st space
    set @contador = @contador+1
end 
set @string1 = Left(@strs, @posicion)

set @strs = replace(@strs, @string1, '')

set @contador = 1
set @posicion = 0
while @contador <= @lon
begin
-- search for the second batch
    set @posicion = CHARINDEX(' ',@strs,@posicion+1)
    set @contador = @contador+1
end 
set @string2 = LEFT(@strs, @posicion)
set @string3 = replace(@strs, @string2, '')

--use test
--update company_backup

--set company1=@string1,company2=@string3 where id=12
select @string1 as string1, @string2 as string2, @string3 as string3

1 个答案:

答案 0 :(得分:0)

如果您创建以下功能: -

create FUNCTION [dbo].WordWrap
(
    @WrapAt int,
    @Text nvarchar(1024)
)
RETURNS nvarchar(1024)
AS
BEGIN
    declare @ReturnVaue nvarchar(1024);--the string to be passed back
    declare @Snip int;-- the length to snip to the last space before the wrapap value
    declare @Block int;-- the block number of the piece in the return string
    set @Block=1;-- initialise the block number
    set @Text=ltrim(rtrim(@Text));-- clean up the input string
    while charindex('  ',@Text)>0 begin -- if there are any double spaces
        set @Text=REPLACE(@Text,'  ',' '); -- replace them with single spaces
    end
    if (@Text is null or DATALENGTH(@Text)<=@WrapAt) begin -- if the input string is null or short enough for 1 block
        set @ReturnVaue='<1>'+@Text+'</1>';-- load it into the return value and we're done
    end else begin -- otherwise we have some work to do
        set @ReturnVaue='' -- so let's initialise the return value
        while DATALENGTH(@Text)>0 begin -- and keep going until we have finished
            -- if the character after the wrapat is a space or there is a space anywhere before the wrapat
            if SUBSTRING(@Text,@WrapAt+1,1)=' ' or CHARINDEX(' ',left(@Text,@WrapAt))>0 begin
                if SUBSTRING(@Text,@WrapAt+1,1)=' ' begin -- if the character after the wrapat is a space
                    set @Snip=@WrapAt-- we can snip to the wrapat
                end else begin
                    --otherwise we have to snip to the last space before the wrapat
                    set @Snip=@WrapAt-charindex(' ',reverse(left(@text,@WrapAt)));
                end
                -- now we can load the return value with snipped text as the current block
                set @ReturnVaue+='<'+CONVERT(varchar,@Block)+'>'+left(@Text,@Snip)+'</'+CONVERT(varchar,@Block)+'>';
                -- and leave just what's left to process, by jumping past the space (@Snip+2)
                set @Text=SUBSTRING(@Text,@Snip+2,1024);
            end else begin-- otherwise we have no space to split to - so we can only cut the string at wrapat
                -- so we load the return value with the left hand wrapat characters as the current block
                set @ReturnVaue+='<'+CONVERT(varchar,@Block)+'>'+LEFT(@Text,@WrapAt)+'</'+CONVERT(varchar,@Block)+'>';
                -- and leave just what's left to process, by jumping past the wrapat (@WrapAp+1)
                set @Text=SUBSTRING(@Text,@WrapAt+1,1024);
            end
        set @Block+=1-- increment the block number in case we still have more work to do
        end
    end
    RETURN @ReturnVaue;
END
go

并且您的表中加载了以下测试数据: -

create table New_Company_Data (
    Company_name varchar(120)
);
go
insert into New_Company_Data values (null);
insert into New_Company_Data values ('');
insert into New_Company_Data values ('   abc   abc    abc      abc');
insert into New_Company_Data values ('a');
insert into New_Company_Data select REPLICATE('a',40)+REPLICATE('b',40)+REPLICATE('c',40)
insert into New_Company_Data values ('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis vehicula, quam non lobortis molestie, purus dui porta sed.');
go
select dbo.WordWrap(40,n.Company_name)
from New_Company_Data n

您收到以下内容: -

NULL
<1></1>
<1>abc abc abc abc</1>
<1>a</1>
<1>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</1><2>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</2><3>cccccccccccccccccccccccccccccccccccccccc</3>
<1>Lorem ipsum dolor sit amet, consectetur</1><2>adipiscing elit. Duis vehicula, quam non</2><3>lobortis molestie, purus dui porta sed.</3>

我留给你来弄清楚如何将(伪xml)字符串粉碎到目标列中,这取决于解决方案需要的可重复性。如果它是一个关闭 - 从我的函数输出到输出表中的临时货物列,然后时尚更新语句将每个块一个接一个地拉出到所需的输出列。如果您需要经常重复此操作,请编写一个SP,通过它创建临时表和游标,并同时将块移动到目标列中。显然,您可以将我的代码拆开并直接使用逻辑来形成动态更新语句(将SET&lt; targetfield&gt;添加到&lt;块值&gt;,因为每个块被剪切出输入字符串)将在每个枚举结束。

我留给你决定如何继续(即使这是一个更直接的问题,提出你想要继续的方式)。