5

文字列を分割する関数があります(わかりやすくするために最後に貼り付けました)。この機能は、単独で使用すると期待どおりに機能します。例:

SELECT value
FROM dbo.mg_fn_Split('2#1','#')

戻り値

-- value --
--   2   --
--   1   --
-----------

ただし、この例のように「WHERE IN」句で使用すると、次のようになります (tableA については後で詳しく説明します)。

SELECT * FROM TableA WHERE TableA.id IN
(
  SELECT value
  FROM dbo.mg_fn_Split('2#1','#')
)

「無効な長さパラメーターが LEFT または SUBSTRING 関数に渡されました」というエラーが表示されます。

ここでは例として TableA を使用します。別のテーブルを使用すると (id 列があると仮定して)、正しい結果が返されることがありますが、他のテーブルではエラーが発生します。

実行順序と関係があると思いますが、何が関数を「破損」させる可能性があるのか​​ まだわかりません。

「代わりにこれを使用する」ではなく、「何が起こっているのか」の説明を探しています。たとえば、結合を使用して結果を取得できることを知っています。

関数定義:

-- Description: Returns a table containing the results of a string-split operation.
-- Params:
--      DelimitedList: The string to split
--      Delimiter: The delimiter char, defaults to ','
-- Columns:
--      Position - The char index of the item
--      Value - The actual item
-- =============================================
CREATE Function [dbo].[mg_fn_Split]
(   
    @DelimitedList nvarchar(max)
    , @Delimiter nvarchar(2) = ','
)
RETURNS TABLE 
AS
RETURN 
    (
    With CorrectedList As
        (
        Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            + @DelimitedList
            + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            As List
            , Len(@Delimiter) As DelimiterLen
        )
        , Numbers As 
        (
        Select TOP( Coalesce(DataLength(@DelimitedList)/2,0) ) Row_Number() Over ( Order By c1.object_id ) As Value
        From sys.columns As c1
            Cross Join sys.columns As c2
        )
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
        , Substring (
                    CL.List
                    , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen     
                    , CharIndex(@Delimiter, CL.list, N.Value + 1)                           
                        - ( CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen ) 
                    ) As Value
    From CorrectedList As CL
        Cross Join Numbers As N
    Where N.Value <= DataLength(CL.List) / 2
        And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
    )

編集:これを示すためにフィドルを設定しました: http://sqlfiddle.com/#!3/9f9ff/3

4

1 に答える 1

0

これは、内部クエリのデータが次のようになる場合に発生します。

SELECT value FROM dbo.mg_fn_Split('#','#') --------------> ここでエラーが発生します。

SELECT value FROM dbo.mg_fn_Split('2#1','#') -------------> エラーはありません。

SELECT value FROM dbo.mg_fn_Split('2','#') --------------------> エラーはありません。

SELECT value FROM dbo.mg_fn_Split('','#') ----------------------> エラーはありません。

基本的に、分割しているデータと区切り文字が同じ場合、エラーが発生します。

問題は、これらのステートメントにあります。

      " Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
        + @DelimitedList
        + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End"

これを次のように変更すると

    Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '1' End
        + @DelimitedList
        + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '1' End

その後、うまくいくでしょう..あなたがしているのは、「」の代わりに「1」を追加することだけです...これが役に立てば幸いです。

于 2012-12-10T23:31:00.490 に答える