2016-07-30 1 views
1

テーブルの列内から部分文字列を連結した値を返すSQLビューを作成しようとしています。SQL内の列から連結された部分文字列を返します

私の例では、「TrebuchetSettings」という名前のテーブルに「DefDetails」というタイトルの列があります。この列には、連結する必要がある値のXMLリストが含まれています。

DefDetails列には、レコードごとに、以下のような値を保持します:

<Trebuchet> <FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> <Alias /> <Description /> <Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner> <FolderList> <FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" /> <FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> </FolderList> </FolderSetDef> </Trebuchet>

をSQLステートメントを使用して、私はTrebuchetSettingsテーブルを照会し、「名前」の連結されたリストを返す必要があります上記のXMLの 'FolderDef'ノード内のフィールドは、 '/'文字で区切られ、FolderDefのIDは後続のFolderDefのParentIDと一致し、連結構造がフォルダ構造を表します。

レコードの他の種類は、この表にあるとおり、私のクエリは、現在の私はこれらのサブストリングを引っ張るために必要なレコードを識別するために、次のように構成されます上記の例のSQLで

SELECT * 
FROM TrebuchetSettings 
WHERE DefType = 'FolderSetDef' 
AND DefDetails LIKE '%(Folder ID)%' 

、フォルダIDは42文字のIDで、XML内のFolder DefsのIDと一致する別のテーブルの値と比較されます。

残念ながら、私はSQLの列の部分文字列での作業経験がなく、どこから開始するのかわからないため、このためのコードはありません。

+0

は別の列に 'NAME'値をコピーして(%」LIKE' DefDetails行のフラグ欄に設定しますフォルダID)% ''さもなければ非常に遅い操作である。 SQLはXMLを扱う最良のツールではありません。 –

答えて

1

非常に遅くかもしれません...この場合、管理するための良いアドバイスでしょう(トリガーを?)インデックス付きの列にParentIDを保持し、XMLを含む行のキーと一緒に保持します。これは言い換えれば、自己完結したインデックスのようなものです...

これを明確にするには、複数のID(長い文字列)を持つテーブルがあります。次に、 "/ FolderDef"内の "ParentID"としてこの値を含むXMLエントリをすべて検索する必要があります。見つけたら、特定のDefDetailsのすべての名前を連結したいと思う。つまり、2番目のテーブルにあるIDの場合は、DefDetailsを何度もスキャンしなければなりません。%の最初のLIKE検索はと非常に遅いとなります。 XMLメソッド.exist()はもっと速くなければなりません...

あなたはこれを試してみてください:

私は2つのエントリを使用して設定テーブルをモックアップするためにテーブル変数を宣言します。

DECLARE @TrebuchetSettings TABLE(DefDetails XML); 
INSERT INTO @TrebuchetSettings VALUES 
(N'<Trebuchet> 
    <FolderSetDef ID="9365da81288308c9c57aba483f83d2469a5da9ecba" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> 
     <Alias /> 
     <Description /> 
     <Owner>934ec7a1701c451ce57f2c43bfbbe2e46fe4843f81</Owner> 
     <FolderList> 
      <FolderDef ID="93af31dc1b3238241be33549ba8f8239b377767680" Name="Yearly Reports" ParentID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Scope="Core" /> 
      <FolderDef ID="93af31a36cf8232f44265b40f9a1cd14d1e7000813" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> 
     </FolderList> 
    </FolderSetDef> 
</Trebuchet>') 
,(N'<Trebuchet> 
    <FolderSetDef ID="SomeOther" Name="ReportDef" Version="1.0" SubType="" Scope="Global" Culture="Invariant" View="(None)"> 
     <Alias /> 
     <Description /> 
     <Owner>OtherOwner</Owner> 
     <FolderList> 
      <FolderDef ID="Other first ID" Name="Yearly Reports" ParentID="Other ParentID" Scope="Core" /> 
      <FolderDef ID="Other second ID" Name="CSM Management Reports" ParentID="Root" Scope="Core" /> 
     </FolderList> 
    </FolderSetDef> 
</Trebuchet>'); 

は1つの既存のParentIDで2番目のテーブルを定義し、1は

を存在しません
DECLARE @YourOtherTable TABLE(FolderID VARCHAR(42)); 
INSERT INTO @YourOtherTable VALUES 
('93af31a36cf8232f44265b40f9a1cd14d1e7000813') 
,('Some not existing'); 

特定のFolderDef-ParentIDを持つすべてのレコードを検索し、すべての名前属性を/-separateリスト

SELECT ot.FolderID 
     ,concatenated.Names 
FROM @YourOtherTable AS ot 
CROSS JOIN @TrebuchetSettings AS s 
CROSS APPLY 
(
    SELECT STUFF(
    (
    SELECT '/' + A.NameAttr.value('@Name','varchar(max)') 
    FROM DefDetails.nodes('/Trebuchet/FolderSetDef/FolderList/FolderDef') AS A(NameAttr) 
    FOR XML PATH('') 
    ),1,1,'') 
) AS concatenated(Names) 
WHERE s.DefDetails.exist('/Trebuchet/FolderSetDef/FolderList/FolderDef[@ParentID=sql:column("ot.FolderID")]')=1 

このなりに対する結果:私は/移動することをお勧めしたい

93af31a36cf8232f44265b40f9a1cd14d1e7000813 Yearly Reports/CSM Management Reports 
関連する問題