2017-03-14 15 views
0

長い文字列の列があります。データは列に分割する必要があり、可変長の文字列があり、必ずしも同じ量の列ではありません。これを行う方法が正確ではないので、ここでいくつかのアドバイスを探していました。文字列から列にデータを分割する

私はこの文字列を考えてみましょう:

VS5〜MedCond1〜35.4を| VS3〜MedCond6〜64 | VS2〜MedCond4〜70 | | SPO2〜MedCond5〜100 VS4〜MedCond2〜16 | VS1〜MedCond3〜155 | FiO2〜MedCond7〜21 | MAP〜MedCond8〜98 |

場合によっては、その文字列の一部だけがすべての病状を有していない場合もあります。

私は列名がtildsすなわちMedCond1の間にあり、値がtildの右側にあるが、パイプの前の値でこのように終わるでしょう列に分割する必要があり

MedCond1 MedCond2 MedCond3 MedCond4 MedCond5 MedCond6 MedCond7 MedCond8 
    ======== ======== ======== ======== ======== ======== ======== ======== 
    35.1  24  110  64  100  88  21  79 

私は大きなテーブル内の多くの行のためにこれを行う必要があると私は言ったように、すべての列は常に存在していないが、彼らは異なる名前ではない、あなたはmed cond 1-8を持っている可能性があり、 3、4、7。

私が作成したクエリは、私が欲しいものだがダイナミックではないように作成されているので、値の一部を追加して値を取得していますあなたは数値がCHARINDEX数のハードコーディングによる文字列の追加の一部で時々取り上げている見ることができるように、文字列

select MainCol, case when charindex('MedCond1', MainCol) > 0 then 
substring(MainCol, charindex('MedCond1', MainCol) + 9, 4) end as [MedCond1] 
from MedTable 

MedCond1 
======== 
35.3 
40.2 
33.6 
33|V <--- Problem 

を返します。値は小数点以下4桁、時には小数点以下2桁です。私はこのダイナミックにしたいと思います。パイプは必要なデータの終わりを定義し、開始点は列名の最後のティルドによって定義されます。このダイナミック

アンドリュー

+0

広すぎます。これらの文字列を分割するために使用するツールを指定してください –

+0

SQL Server 2012を使用したいと思っています – Andrew

+0

これを達成するために締め切りを守っている人はいますか?私はSQL文を追加しますが、これは私がやりたいことはしていますが、動的ではないので、文字列のビット数が増えます。 – Andrew

答えて

0

OKを作る上の任意の考えについて

おかげで、私はこれを刺してみましょう。私が概説している解決策は、純粋にSQL Serverになるわけではありませんが、テキストファイル経由のラウンドトリップを使用しています。

アプローチは、以下の工程使用:

  1. アンピボットパイプ記号で区切らデータを
  2. 往復(入力のライン毎に出力の複数の行を作成します) SQL Serverからテキストファイルにデータを戻します。
  3. 分離したデータをチルダの列に置き換えます。シンボルデリミタ
  4. ピボットデータバックの列

へのこのアプローチの主な利点は、あなたが同等の行が存在しないことによって、自然にMedCond2などの不足している列を処理することを可能にするアンピボット操作、です。また、以下のステップ1で関数REPLACEを除いて、ほぼすべての文字列操作を排除します。

VS5~MedCond1~35.4|VS4~MedCond2~16|VS1~MedCond3~155|VS2~MedCond4~70|SPO2~MedCond5~100|VS3~MedCond6~64|FiO2~MedCond7~21|MAP~MedCond8~98| 

ステップ1(アンピボット):改行文字とのパイプ記号のすべてのインスタンスを検索と置換

は、次のような単一の行の内容を考えます。

VS5~MedCond1~35.4 
VS4~MedCond2~16 
VS1~MedCond3~155 
VS2~MedCond4~70 
SPO2~MedCond5~100 
VS3~MedCond6~64 
FiO2~MedCond7~21 
MAP~MedCond8~98 

ステップ2(往復)::だから、REPLACE(column, '|', CHAR(13))はあなたに、単一入力行のテキストの次の行(単一データベース行のテキストのつまり複数行)を与える上記の出力を書きます(SSIS、SQLCMDなど)を使用してテキストファイルに追加し、定義された改行文字が手順1のREPLACEコマンドで使用されたものと同じであることを確認してください。

この手順の目的は、同じ行の複数の行を異なる行の他の行と連結します。

ステップ1は、ステップ2 & 3の行区切り文字をパイプシンボルとして定義することで削除できます。私は、理解とデバッグを容易にするためにのみ、改行を使って追加のステップ1を実行しました。

ステップ3(別々のカラム):同じツールを使用して、SQL Serverにバックテキストファイルをインポートし、そしてチルダ~シンボルとして列デリミタを定義し、ステップ1/2と同じ区切り行。

ColA MedCondTitle MedCondValue 
------ ------------- ------------- 
VS5 MedCond1  35.4 
VS4 MedCond2  16 
VS1 MedCond3  155 
VS2 MedCond4  70 
SPO2 MedCond5  100 
VS3 MedCond6  64 
FiO2 MedCond7  21 
MAP MedCond8  98 

ステップ4(ピボット):このデータ

SUM(CASE WHEN MedCondTitle='MedCond1' THEN MedCondValue ELSE 0) as MedCond1 
1

:今、あなたは、フォームのステートメントを使用して達成することができ、列に行を回動自明の簡単なステップを、持っていると思いますテーブル自体のように見えます。 SQL Serverにxmlとして格納されている可能性があります。 SQL Serverはxmlフィールドをサポートしています。

declare @medTable table (item nvarchar(2000)) 
insert into @medTable 
values ('VS5~MedCond1~35.4|VS4~MedCond2~16|VS1~MedCond3~155|VS2~MedCond4~70|SPO2~MedCond5~100|VS3~MedCond6~64|FiO2~MedCond7~21|MAP~MedCond8~98|'); 

-- Step 1: Replace `|` with <item> tags and `~` with `tag` tags 
-- This will return an xml value for each medTable row 
with items as (
    select xmlField= cast('<item><tag>' 
          + replace( 
            replace(item,'|','</tag></item><item><tag>'), 
            '~','</tag><tag>') 
          + '</tag></item>' as xml) 
    from @medTable 
) 
-- Step 2: Select different tags and display them as fields 
select 
    y.item.value('(tag/text())[1]','nvarchar(20)'), 
    y.item.value('(tag/text())[2]','nvarchar(20)'), 
    y.item.value('(tag/text())[3]','nvarchar(20)') 
from items outer apply xmlField.nodes('item') as y(item) 

結果は次のとおりです:

-------------------- -------------------- ------- 
VS5     MedCond1    35.4 
VS4     MedCond2    16 
VS1     MedCond3    155 
VS2     MedCond4    70 
SPO2     MedCond5    100 
VS3     MedCond6    64 
FiO2     MedCond7    21 
MAP     MedCond8    98 
NULL     NULL     NULL 

ロードするときに、この変換を実行する方が良いだろう実際には、人はそれを照会しようとし、その後、XMLに変換にこの文字列を試みることができますしかしデータ。たとえば、C#またはSSISで置き換えを行い、完全なXML値をデータベースに格納するのは簡単です。

あなたはXML値を生成し、データベースに格納し、あまりにもこのクエリを変更することができます。

declare @medTable2 table (xmlField xml) 

with items as (
    select xmlField= cast('<item><tag>' + replace(replace(item,'|','</tag></item><item><tag>'),'~','</tag><tag>') + '</tag></item>' as xml) 
    from @medTable 
) 
insert into @medTable2 
select items.xmlField 
from items 

-- Query the new table from now on 
select 
    y.item.value('(tag/text())[1]','nvarchar(20)'), 
    y.item.value('(tag/text())[2]','nvarchar(20)'), 
    y.item.value('(tag/text())[3]','nvarchar(20)') 
from @medTable2 outer apply xmlField.nodes('item') as y(item) 
+0

非常に滑らかで、より多くのステップを必要とする私の答えよりも優れています! – Phylyp