2017-09-07 8 views
0

したがって、最初の投稿はそれほど問題ではありません。ごめんなさい。TSQL/SQL Server - 区切られた文字列を解析して複数の列に分割するテーブル関数

VarCharテーブルの列に格納されている区切り文字列を、同じレコードの複数の/別々の列に変換する必要がありました。 (それはCOTSのソフトウェアなので、テーブルがどうやって設計されているかを教えてください)。インターネット広告の不具合を調べて、それを行うための一般的な単一回線呼び出しを作成する方法、私は自分自身を作成し​​ました。

戻り値:[Col1]で始まる連続した番号付き/名前付き列の表。入力値が指定されていない場合、空の文字列が返されます。 32個未満の値が指定された場合、最後の値を超えたものはすべてnullとして返されます。 32以上の値が指定されている場合、それらは無視されます。

前提条件:番号/集計表(幸いにも、私たちのデータベースにはすでに 'dbo.numbers'が含まれています)。

前提条件:32個以下の区切りの値。 (もっと必要な場合は、 "WHERE tNumbers.Number BETWEEN 1 AND XXX"を変更し、さらに名前のついた列を追加してください "、[Col33] ...、[ColXXX]")

問題: @InputStringがNULLの場合でも、値が移入されます。

--====================================================================== 
--SMOZISEK 2017/09 CREATED 
--====================================================================== 
CREATE FUNCTION dbo.fStringToPivotTable 
     (@InputString VARCHAR(8000) 
     ,@Delimiter  VARCHAR(30)   = ',' 
     ) 
    RETURNS TABLE AS RETURN 
    WITH cteElements AS (
     SELECT ElementNumber  = ROW_NUMBER() OVER(PARTITION BY @InputString ORDER BY (SELECT 0)) 
       ,ElementValue  = NodeList.NodeElement.value('.','VARCHAR(1022)') 
     FROM  (SELECT TRY_CONVERT(XML,CONCAT('<X>',REPLACE(@InputString,@Delimiter,'</X><X>'),'</X>')) AS InputXML) AS InputTable 
     CROSS APPLY InputTable.InputXML.nodes('/X')                   AS NodeList(NodeElement) 
    ) 
    SELECT PivotTable.* 
     FROM (
      SELECT ColumnName   = CONCAT('Col',tNumbers.Number) 
        ,ColumnValue  = tElements.ElementValue 
      FROM  DBO.NUMBERS   AS tNumbers    --DEPENDENT ON ANY EXISTING NUMBER/TALLY TABLE!!! 
      LEFT JOIN cteElements   AS tElements 
       ON  tNumbers.Number  = tElements.ElementNumber 
      WHERE  tNumbers.Number  BETWEEN 1 AND 32 
     ) AS XmlSource 
    PIVOT (
     MAX(ColumnValue) 
     FOR ColumnName 
     IN ([Col1] ,[Col2] ,[Col3] ,[Col4] ,[Col5] ,[Col6] ,[Col7] ,[Col8] 
      ,[Col9] ,[Col10],[Col11],[Col12],[Col13],[Col14],[Col15],[Col16] 
      ,[Col17],[Col18],[Col19],[Col20],[Col21],[Col22],[Col23],[Col24] 
      ,[Col25],[Col26],[Col27],[Col28],[Col29],[Col30],[Col31],[Col32] 
      ) 
    ) AS PivotTable 
    ; 
    GO 

テスト:

SELECT * 
FROM dbo.fStringToPivotTable ('|Height|Weight||Length|Width||Color|Shade||Up|Down||Top|Bottom||Red|Blue|','|') ; 

使用法:

SELECT 1  AS ID,'Title^FirstName^MiddleName^LastName^Suffix' AS Name 
INTO #TempTable 
UNION SELECT 2,'Mr.^Scott^A.^Mozisek^Sr.' 
UNION SELECT 3,'Ms.^Jane^Q.^Doe^' 
UNION SELECT 5,NULL 
UNION SELECT 7,'^Betsy^^Ross^' 
; 

SELECT SourceTable.* 
     ,ChildTable.Col1  AS ColTitle 
     ,ChildTable.Col2  AS ColFirst 
     ,ChildTable.Col3  AS ColMiddle 
     ,ChildTable.Col4  AS ColLast 
     ,ChildTable.Col5  AS ColSuffix 
FROM #TempTable    AS SourceTable 
OUTER APPLY dbo.fStringToPivotTable(SourceTable.Name,'^')  AS ChildTable 
; 

いいえ、私は(私は動作するように必要な)任意の計画をテストしていません。 ああ、そうです:SQL Server 2012(12.0 SP2)

コメント?訂正?強化?

+0

あなたの質問は何ですか? –

答えて

0

ここは私のTVFです。簡単に32まで拡張できます(パターンはかなりクリアです)。

これはPIVOTの費用をかけないストレートXMLです。

例 - OUTERを通知は、APPLY ---使用CROSSは、UDFをNULLを除外

Select A.ID 
     ,B.* 
From #TempTable A 
Outer Apply [dbo].[tvf-Str-Parse-Row](A.Name,'^') B 

戻り

enter image description here

に適用されます興味があれば

CREATE FUNCTION [dbo].[tvf-Str-Parse-Row] (@String varchar(max),@Delimiter varchar(10)) 
Returns Table 
As 
Return (
    Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)'))) 
      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)'))) 
      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)'))) 
      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)'))) 
      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)'))) 
      ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)'))) 
      ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)'))) 
      ,Pos8 = ltrim(rtrim(xDim.value('/x[8]','varchar(max)'))) 
      ,Pos9 = ltrim(rtrim(xDim.value('/x[9]','varchar(max)'))) 
    From (Select Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml) as xDim) as A 
    Where @String is not null 
) 
--Thanks Shnugo for making this XML safe 
--Select * from [dbo].[tvf-Str-Parse-Row]('Dog,Cat,House,Car',',') 
--Select * from [dbo].[tvf-Str-Parse-Row]('John <test> Cappelletti',' ')