如何在SQL Server中完成此Excel功能?

时间:2015-10-16 07:31:47

标签: sql-server excel excel-formula

我有大约30,000条记录需要拆分Description字段,到目前为止,我似乎只能在Excel中实现这一点。示例Description将是:

1USBCP 2RJ45C6 1DVI 1DP 3MD 3MLP HANDS

以下是我的Excel功能:

=TRIM(MID(SUBSTITUTE($G309," ",REPT(" ",LEN($G309))),((COLUMNS($G309:G309)-1)*LEN($G309))+1,LEN($G309)))

然后将其拖过十个Excel列,并在每个空格处拆分description字段。

我已经看到很多关于在SQL中拆分字符串的问题,但它们似乎只覆盖了一个空格,而不是多个空格。

2 个答案:

答案 0 :(得分:1)

SQL Server中没有简单的功能来分割字符串。至少我不知道。我通常会使用一些技巧,这些技巧是我前段时间在互联网上找到的。我把它修改为你的例子。

诀窍在于,首先我们要弄清楚我们需要多少列。我们可以通过检查字符串中有多少空字符串来实现。最简单的方法是长度为字符串 - 字符串长度没有空字符串。 在每个字符串之后,我们尝试按位置查找每个单词的开头和结尾。最后,我们通过开始和结束位置简单地剪切字符串并分配给coulmns。详细信息在查询中。玩得开心!

CREATE TABLE test(id int, data varchar(100))

INSERT INTO test VALUES (1,'1USBCP 2RJ45C6 1DVI 1DP 3MD 3MLP HANDS')
INSERT INTO test VALUES (2,'Shorter one') 

DECLARE @pivot varchar(8000)
DECLARE @select varchar(8000)

SELECT 
        @pivot=coalesce(@pivot+',','')+'[col'+cast(number+1 as varchar(10))+']'
FROM 
        master..spt_values where type='p' and 
        number<=(SELECT max(len(data)-len(replace(data,',',''))) FROM test)

SELECT 
    @select='
        select p.*
        from (
        select 
            id,substring(data, start+2, endPos-Start-2) as token,
            ''col''+cast(row_number() over(partition by id order by start) as varchar(10)) as n
        from (
            select 
                id, data, n as start, charindex('','',data,n+2) endPos
                from (select number as n from master..spt_values where type=''p'') num
                cross join 
                (
                    select 
                        id, '' '' + data +'' '' as data 
                    from 
                        test
                ) m
            where n < len(data)-1
            and substring(odata,n+1,1) = '','') as data
        ) pvt
        Pivot ( max(token)for n in ('+@pivot+'))p'


EXEC(@select)

您可以在此处找到SQL Fiddle

中的示例

我没有注意到你想摆脱多个空格。 要做到这一点,请创建一些预先准备数据的功能:

CREATE FUNCTION dbo.[fnRemoveExtraSpaces]  (@Number AS varchar(1000))
Returns Varchar(1000)
As
Begin
Declare @n int  -- Length of counter
Declare @old char(1)

Set @n = 1
--Begin Loop of field value
While @n <=Len (@Number)
    BEGIN
     If Substring(@Number, @n, 1) = ' ' AND @old = ' '
      BEGIN
        Select @Number = Stuff( @Number , @n , 1 , '' )
      END
     Else
      BEGIN
       SET @old = Substring(@Number, @n, 1)
       Set @n = @n + 1
      END
    END
Return @number
END

之后使用删除多余空格的新版本。

DECLARE @pivot varchar(8000)
DECLARE @select varchar(8000)

SELECT 
        @pivot=coalesce(@pivot+',','')+'[col'+cast(number+1 as varchar(10))+']'
FROM 
        master..spt_values where type='p' and 
        number<=(SELECT max(len(dbo.fnRemoveExtraSpaces(data))-len(replace(dbo.fnRemoveExtraSpaces(data),' ',''))) FROM test)

SELECT 
    @select='
        select p.*
        from (
        select 
            id,substring(data, start+2, endPos-Start-2) as token,
            ''col''+cast(row_number() over(partition by id order by start) as varchar(10)) as n
        from (
            select 
                id, data, n as start, charindex('' '',data,n+2) endPos
                from (select number as n from master..spt_values where type=''p'') num
                cross join 
                (
                    select 
                        id, '' '' + dbo.fnRemoveExtraSpaces(data) +'' '' as data 
                    from 
                        test
                ) m
            where n < len(data)-1
            and substring(data,n+1,1) = '' '') as data
        ) pvt
        Pivot ( max(token)for n in ('+@pivot+'))p'


EXEC(@select)

答案 1 :(得分:0)

我可能不理解您的问题,但您在该公式中所做的一切,在SQL中几乎完全相同。我看到有人已经回答了,但在我看来,当你能做到这一点时,怎么可能做到这一切。我可能错了。但是这里有。

declare @test as varchar(100)
set @test='abcd1234567'

select right(@test,2)
, left(@test,2)
, len(@test)
, case when len(@test)%2>0 
then left(right(@test,round(len(@test)/2,0)+1),1) 
else left(right(@test,round(len(@test)/2,0)+1),2) end

结果

 67 ab  11  2

所以右,左,长,中都可以实现。

如果空格是“子串”分隔符,那么:我不记得do-while内部选择sql的实际语法,我本身也没有实际做过,但我不明白它为什么不应该有可能。如果它不起作用,那么你需要一个临时表,如果这不起作用,你需要一个游标。游标将是围绕此游标的外部循环,以一次获取并处理单个字符串。或者你可以做一些更聪明的事情。我只是个新手。

declare @x varchar(1)
declare @n integer
declare @i integer
declare @str varchar(100) -- this is your description. Fetch it and assign it. if in a cursor just use column-name 
set @x = null
set @n = 0
set @i = 0
while n < len(@str)
while NOT @x = " "
begin
set @x = left(right(@str,n),1)
n = n+1
end
--insert into or update @temptable blablabla here. 

使用i和n定位子串然后向左(右())出来。或者你可以选择它,但如果子串的数量很长,这是一个混乱的过程。继续:

set i = n
set @str = right(@str, i) -- this includes the " ". left() it out at will.
end

现在,最后的评论,或许应该有第三个循环检查你是否在最后一个“子串”,因为我现在看到这个代码将在它结束时抛出错误。或者在末尾“添加”一个空格到@str,这也可以。但我的时间到了。这至少是一个建议。