2

SQL 2008 データベースに次のような XML があり、XML フィールドに格納されています。ノードが XML の特定のセクションに存在するかどうかを true または false で示したいと思います。

<root>
    <node attribute1='value1' attribute2='value2'>
        <sub1 name='ID' value="1" />
        <sub2 name='project' value="abc" />
        <sub3 name='Lead' value="John" />
    </node>
    <entry attribute1='value1' attribute2='value2'>
        <message>start</message>
    </entry>
    <entry attribute1='value1' attribute2='value2'>
        <attribute name='project' value='done'>
    </entry>    
    <node attribute1='value1'>
        <sub1 name='ID' value="2" />
        <sub2 name='project' value="abc" />
        <sub3 name='Lead' value="John" />
    </node>
    <entry attribute1='value1' attribute2='value2'>
        <message>start</message>
    </entry>
    <node attribute1='value1'>
        <sub1 name='ID' value="3" />
        <sub2 name='project' value="abc" />
        <sub3 name='Lead' value="John" />
    </node>
    <entry attribute1='value1' attribute2='value2'>
        <message>start</message>
    </entry>
    <node attribute1='value1'>
        <sub1 name='ID' value="4" />
        <sub2 name='project' value="abc" />
        <sub3 name='Lead' value="John" />
    </node> 
    <entry attribute1='value1' attribute2='value2'>
        <message>start</message>
    </entry>
    <entry attribute1='value1' attribute2='value2'>
        <attribute name='project' value='done'>
    </entry>
</root>

お気づきのように、<attribute>ノードは「ID」を持つノードの後に​​発生する場合と発生しない場合があります。この例では、適切な用語がないため、最初と 4 番目の「セクション」で確認できます。

次のテーブル構造を使用します。

ID (PK)
EventID (FK)
RawXML (XML)
Created (datetime)

以下は、これまでに入手した SQL/xQuery の抜粋です。

WITH XMLNAMESPACES(
  'http://www.w3.org/2001/XMLSchema-instance' as xsi,
),
t1 as(
    SELECT distinct
      x.EventId
    , c.value ('(//node/sub[@name=''ID'']/@value)[1]', 'nvarchar(max)') as ID   
    , c.value ('(//node/sub[@name=''ID''][1][descendant::attribute/@name=''project''])[1]', 'nvarchar(max)' ) as Exists     
    FROM
      Table1 x
    CROSS APPLY
      RawXML.nodes('./.') as t(c)
     )
select distinct
  t1.ID
, t1.Exists
from t1

スクリプトを 4 回以上実行します (実行する前にすべてのシングルトン値を増やします)。

指定された XML について、クエリを 4 回実行した後、次の結果を得る必要があります (ID の値がわからないため、クエリで使用できません)。

    ID    Exists
   ----   -------
    1      true
    2      false
    3      false
    4      true

指定された SQL では、エラーは発生しませんでしたが、永遠に (45 分以上) かかり、まだ終了していません。XML を解析するのにこれほど長い時間はかからないはずです。

更新: クエリを制限して、1 行 (1 つの XML ファイル) のみを解析し、57 秒で終了したことを確認しました。ただし、ID 1 に「1」が必要な場合に、ID 1 と ID 2 に「0」という結果が得られました。

また、ほとんどの人は、次の兄弟などは SQL Server でサポートされていないため、残念ながらそれはオプションではないことを認識していると思います。

参考までに、これを使用して 'Project' の 2 つのインスタンスを見つけることができましたが、それらが発生する xml の場所は無視されます。

c.value ('(//node[descendant::attribute/@name=''Project''])[1]', 'nvarchar(max)' ) as TrueFalse

したがって、基本的には、name='ID' のノードの後に​​ name='Project' のノードが存在するかどうかを知る必要がありますが、name='ID' のノードの次のインスタンスの前に存在するかどうかを知る必要があります。

4

1 に答える 1

2

XML にいくつかのエラーがあり、使用するクエリから判断して、サブノードも変更しました。

XQuery の代わりに通常の SQL を使用して、ID およびプロジェクト ノードを列挙しrow_number()、「次の行」がプロジェクト ノードまたは ID 行であるかどうかを確認できます。

-- Temp table to hold the extracted values from the XML
create table #C
(
  rn int primary key,
  ID int
);

-- Get the enumerated rows with ID.
-- project nodes will have NULL in ID
insert into #C
  select row_number() over(order by T.N) as rn,
         T.N.value('sub[@name = "ID"][1]/@value', 'int') as ID
  from table1
    cross apply RawXML.nodes('/root/*[sub/@name = "ID" or attribute/@name = "project"]') as T(N)

-- Get the ID's and check if the next row is a project node
select C1.ID,
       case when exists (
                          select *
                          from #C as C2
                          where C1.rn + 1 = C2.rn and 
                          C2.ID is null
                        ) 
         then 1
         else 0
       end as [Exists]
from #C as C1
where C1.ID is not null;

drop table #C;

SQL フィドル

代わりにCTEを使用して一時テーブルなしでそれを行うことができますが、一時テーブルのバージョンの方が高速になると思います.

with C as
(
  select row_number() over(order by T.N) as rn,
          T.N.value('sub[@name = "ID"][1]/@value', 'int') as ID
  from table1
    cross apply RawXML.nodes('/root/*[sub/@name = "ID" or attribute/@name = "project"]') as T(N)
)
select C1.ID,
        case when exists (
                          select * 
                          from C as C2 
                          where C1.rn + 1 = C2.rn and 
                                C2.ID is null
                        ) 
          then 1
          else 0
        end as [Exists]
from C as C1
where C1.ID is not null;

SQL フィドル

于 2012-10-24T05:52:42.423 に答える