2011-06-23 14 views
1

私はVARCHAR(3000)である列の単語頻度を決定しようとしています。私はこれが最良のデータ型であるかどうかはわかりませんが、テーブルの作成は手元にありませんでした。いずれにせよ、私はこの時点までの文字列を分割する(hereから取られた)次の関数を使用している次のように非常に大きな文字列をカスタム区切り文字で分割していますか?

CREATE FUNCTION dbo.Split 
(
    @RowData nvarchar(2000), 
    @SplitOn nvarchar(5) 
) 
RETURNS @RtnValue table 
(
    Id int identity(1,1), 
    Data nvarchar(100) 
) 
AS 
BEGIN 
    Declare @Cnt int 
    Set @Cnt = 1 

    While (Charindex(@SplitOn,@RowData)>0) 
    Begin 
     Insert Into @RtnValue (data) 
     Select 
      Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1))) 

     Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData)) 
     Set @Cnt = @Cnt + 1 
    End 

    Insert Into @RtnValue (data) 
    Select Data = ltrim(rtrim(@RowData)) 

    Return 
END 

使い方ました:

SELECT s FROM dbo.Split(' ', @description) 

それは非常にうまく働いているが、今私はエラーが表示されます:

The statement terminated. The maximum recursion 100 has been exhausted before statement completion.

これを達成する良い方法は何ですか?

答えて

2

気にしないでください。念のために他の誰かが同じ問題に直面し、hereから以下のことは、大きな文字列に完璧に動作します:

CREATE FUNCTION dbo.SplitLarge(@String varchar(8000), @Delimiter char(1))  
returns @temptable TABLE (items varchar(8000))  
as  
begin  
    declare @idx int  
    declare @slice varchar(8000)  

    select @idx = 1  
     if len(@String)<1 or @String is null return  

    while @idx!= 0  
    begin  
     set @idx = charindex(@Delimiter,@String)  
     if @idx!=0  
      set @slice = left(@String,@idx - 1)  
     else  
      set @slice = @String  

     if(len(@slice)>0) 
      insert into @temptable(Items) values(@slice)  

     set @String = right(@String,len(@String) - @idx)  
     if len(@String) = 0 break  
    end 
return  
end 
2

この機能taken from hereは、私は状況がある.Nodesを使用し、ループや再帰CTEの

CREATE FUNCTION dbo.Split(@data NVARCHAR(MAX), @delimiter NVARCHAR(5)) 
RETURNS @t TABLE (data NVARCHAR(max)) 
AS 
BEGIN 

    DECLARE @textXML XML; 
    SELECT @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML); 

    INSERT INTO @t(data) 
    SELECT T.split.value('.', 'nvarchar(max)') AS data 
    FROM @textXML.nodes('/d') T(split) 

    RETURN 
END 
GO 
+0

これは、ループを使用した上記の受け入れられた回答に対してこれをテストしたところ、これは非常に悪化していました。 CPUと読み取りはループを持つものよりはるかに高かった。私のテストでは、100と200のデータ要素を持つ入力文字列を使用しました。これはいつ受け入れられた答えよりもうまくいくのかについて誰かが考えていますか? –

+0

@ Dave.Gugg私はあなたのコメントがこの答えの文脈にあることを認識していますが、別の質問としてこれを検討することをお勧めします。さて、SQLでは文字列を分割することはほとんど常に悪い考えです。 [CLR proc](https://www.mssqltips.com/sqlservertip/1665/sql-server-clr-and-sql-split-functions-to-parse-a-delimited-string/)ははるかに高速になります。もう1つの選択肢は、テーブル値付きパラメータを使用することです –

0

を回避次のコードは私にとってうまくいきます。このコードでは、replace関数とSQL 2008の1つの挿入ステートメントで複数の行を挿入する機能を使用しています。この方法の唯一の欠点は、実際には欠点である場合、1000分割に制限されていることです。

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[StringSegmenter]') AND type in (N'U')) 
DROP TABLE [dbo].[StringSegmenter] 
GO 

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

SET ANSI_PADDING ON 
GO 

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[StringSegmenter]') AND type in (N'U')) 
BEGIN 
CREATE TABLE [dbo].[StringSegmenter](
    [ss_id] [int] IDENTITY(1,1) NOT NULL, 
    [ss_segment] [varchar](max) NOT NULL, 
CONSTRAINT [PK_StringSegmenter] PRIMARY KEY CLUSTERED 
(
    [ss_id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
END 
GO 

SET ANSI_PADDING OFF 
GO 

truncate table scratchpad.dbo.stringsegmenter 
declare @String varchar(max) 
declare @Splitter varchar(10) 
set @String = '1,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,2222222222222222222,3,4,55555555555555555555555,2222222222222222222,3,4,55555555555555555555555,666666666666666666666666666666,2222222222222222222,3,4,55555555555555555555555,666666666666666666666666666666,2222222222222222222,3,4,55555555555555555555555,666666666666666666666666666666,2222222222222222222,3,4,55555555555555555555555,666666666666666666666666666666' 
set @Splitter = ',' 
set @String = 'Insert [dbo].[StringSegmenter] Values (''' + replace(@string, @splitter,'''),(''') + ''')' 
select @String 
execute (@String) 

Select * from [dbo].[StringSegmenter] order by ss_id 
関連する問題