SQL Server 2008 T-SQL UDF Split() 剪裁

Posted

技术标签:

【中文标题】SQL Server 2008 T-SQL UDF Split() 剪裁【英文标题】:SQL Server 2008 T-SQL UDF Split() Tailoring 【发布时间】:2011-05-11 18:26:59 【问题描述】:

我正在使用 SQL Ser 2008 并且有一个只有一列数据的大表。数据是一个随机字符串,几乎没有一致性。示例:名称帐户 445566 0010020056893010445478008 AFD 369。我一直在使用 *** 用户建议的拆分功能。它工作得很好,但该函数将拆分字符串分配到一列。我需要一行单独的列。当前结果是 1col,其中包含值 Name, Account, 445566,... 但我要查找的结果是 col1 Name, col2 Account, col3 445566,... 如果有人可以提供有关如何定制此脚本或其用法以获得所需结果的一些见解,将不胜感激。

CREATE FUNCTION [dbo].[Split] 
(    
 @String varchar(max) 
,@Delimiter char 
) 
RETURNS @Results table 
( 
 Ordinal int 
,StringValue varchar(max) 
) 
as 
begin 

set @String = isnull(@String,'') 
set @Delimiter = isnull(@Delimiter,'') 

declare 
 @TempString varchar(max) = @String 
,@Ordinal int = 0 
,@CharIndex int = 0 

set @CharIndex = charindex(@Delimiter, @TempString) 
while @CharIndex != 0 begin      
    set @Ordinal += 1        
    insert @Results values 
    ( 
     @Ordinal 
    ,substring(@TempString, 0, @CharIndex) 
    )        
    set @TempString = substring(@TempString, @CharIndex + 1, len(@TempString) - @CharIndex)      
    set @CharIndex = charindex(@Delimiter, @TempString) 
end 

if @TempString != '' begin 
    set @Ordinal += 1  
    insert @Results values 
    ( 
     @Ordinal 
    ,@TempString 
    ) 
end 

return 
end 

--The usage:
SELECT    
* 
FROM    
mytable M    
CROSS APPLY    
[dbo].[Split] (M.TheColumn, ' ') S
Where rtrim(s.StringValue) != '' 

【问题讨论】:

顺便说一句,该函数是从@antisanity 借来的,它在表格上的用法来自@gbn。谢谢各位! 你想达到什么目的?这些数据是被维护还是导入?输出表的宽度会变化还是静态的? 我正在对旧的平面文件批处理进行逆向工程。数据由包含 120 个字符的字符串组成。表格宽度将是静态列数。我的目标是将字符串分成一行列,而不仅仅是包含所有数据的一列,而是 9 或 10 列。这将一次影响 10000 行数据。再次感谢 antisanity 的帮助! 【参考方案1】:

如果您知道字符串中有 6 列,则可以使用如下所示的拆分函数,当然可以将函数修改为您想要的任意数量的列。函数不能返回动态列数。

create function dbo.Split6(@String varchar(max), @Delimiter char(1)) 
returns table as return
(
  select
    substring(T.Col, 1, S1.Pos-1) as Col1,
    substring(T.Col, S1.Pos+1, S2.Pos-S1.Pos-1) as Col2,
    substring(T.Col, S2.Pos+1, S3.Pos-S2.Pos-1) as Col3,
    substring(T.Col, S3.Pos+1, S4.Pos-S3.Pos-1) as Col4,
    substring(T.Col, S4.Pos+1, S5.Pos-S4.Pos-1) as Col5,
    substring(T.Col, S5.Pos+1, S6.Pos-S5.Pos-1) as Col6
  from (select @String+replicate(@Delimiter, 6)) as T(Col)
    cross apply (select charindex(@Delimiter, T.Col, 1)) as S1(Pos)
    cross apply (select charindex(@Delimiter, T.Col, S1.Pos+1)) as S2(Pos)
    cross apply (select charindex(@Delimiter, T.Col, S2.Pos+1)) as S3(Pos)
    cross apply (select charindex(@Delimiter, T.Col, S3.Pos+1)) as S4(Pos)
    cross apply (select charindex(@Delimiter, T.Col, S4.Pos+1)) as S5(Pos)
    cross apply (select charindex(@Delimiter, T.Col, S5.Pos+1)) as S6(Pos)
)

测试:

declare @T table (Col varchar(100))

insert into @T values
 ('Name Account 445566 0010020056893010445478008 AFD 369'),
 (''),
 ('1 2'),
 ('1  3')

select S.Col1, S.Col2, S.Col3, S.Col4, S.Col5, S.Col6
from @T as T
  cross apply
    dbo.Split6(T.Col, ' ') as S

结果:

Col1  Col2     Col3    Col4                       Col5  Col6
----  -------  ------  -------------------------  ----  ----
Name  Account  445566  0010020056893010445478008  AFD   369

1     2             
1              3            

【讨论】:

这看起来不错。我最终会确切地知道我需要多少列,所以我认为这会很好地工作!谢谢!【参考方案2】:

您可以尝试使用 PIVOT。

http://msdn.microsoft.com/en-us/library/ms177410.aspx

【讨论】:

我应该能够在使用脚本后 PIVOT 表列,但我正在寻找解决方法。我的想法是,如果您可以拆分字符串并将数据插入一列,也许您可​​以将其分配给脚本中的多个不同列。 我知道这听起来像是我没有使用最明显的工具,但我对性能有一半关注(旋转一个超过 100000 行的表希望不会击中 CPU 两次仍然需要再加上这个过程发生了几次),一半只是想看看这是否可以完成。我对T-Sql不太熟悉,所以我想我会问专家。

以上是关于SQL Server 2008 T-SQL UDF Split() 剪裁的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2014 UDF - 精简功能

SQL Server 2008 - UDF 参数类型和返回类型

SQL Server 2008 R2 - 标量 UDF 导致无限循环

学习Microsoft SQL Server 2008技术内幕:T-SQL语法基础--第4章

如何在SQL Server 2008下轻松调试T-SQL语句和存储过程

SQL Server用户自定义函数(UDF)