次の方法で共有


sql:max-depth を使用した、再帰リレーションシップの深さの指定

適用対象: SQL Server Azure SQL データベース

リレーショナル データベースでは、テーブルのリレーションシップにそのテーブル自身が含まれることを、再帰リレーションシップと呼びます。 たとえば、監督者と被監督者のリレーションシップでは、従業員の記録を格納するテーブルのリレーションシップに、そのテーブル自身が含まれます。 この場合、従業員テーブルはリレーションシップの 1 つの側では監督者となり、別の側では被監督者となります。

マッピング スキーマには、要素とその先祖が同じ型の再帰リレーションシップを含めることができます。

例 A

次のテーブルを考えてみます。

Emp (EmployeeID, FirstName, LastName, ReportsTo)  

このテーブルでは、ReportsTo 列にマネージャーの従業員 ID が格納されています。

ここで従業員の XML 階層を生成して、次のサンプル XML フラグメントに示すように、マネージャーである従業員を階層の一番上に、マネージャーに報告を行う従業員をそれに対応する階層に表示したいとします。 このフラグメントが示しているのは、従業員 1 の 回復ツリー です。

<?xml version="1.0" encoding="utf-8" ?>   
<root>  
  <Emp FirstName="Nancy" EmployeeID="1" LastName="Devolio">  
     <Emp FirstName="Andrew" EmployeeID="2" LastName="Fuller" />   
     <Emp FirstName="Janet" EmployeeID="3" LastName="Leverling">  
        <Emp FirstName="Margaret" EmployeeID="4" LastName="Peacock">  
          <Emp FirstName="Steven" EmployeeID="5" LastName="Devolio">  
...  
...  
</root>  

このフラグメントでは、従業員 5 が従業員 4、従業員 4 が従業員 3 に、従業員 3 と 2 は従業員 1 に報告を行います。

この結果を生成するには、次の XSD スキーマを使用して、これに対する XPath クエリを指定できます。 このスキーマは、EmployeeType 型の <Emp> 要素を記述します。この要素は、同じ型である EmployeeType の <Emp> 子要素で構成されます。 これは、要素とその先祖が同じ型の再帰リレーションシップです。 さらに、スキーマでは、 <sql:relationship> を使用して、スーパーバイザーと教師の間の親子関係を記述します。 この <sql:relationship>では、Emp は親テーブルと子テーブルの両方であることに注意してください。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
            xmlns:dt="urn:schemas-microsoft-com:datatypes"  
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">  
  <xsd:annotation>  
    <xsd:appinfo>  
      <sql:relationship name="SupervisorSupervisee"  
                                  parent="Emp"  
                                  parent-key="EmployeeID"  
                                  child="Emp"  
                                  child-key="ReportsTo" />  
    </xsd:appinfo>  
  </xsd:annotation>  
  <xsd:element name="Emp" type="EmployeeType"   
                          sql:relation="Emp"   
                          sql:key-fields="EmployeeID"   
                          sql:limit-field="ReportsTo" />  
  <xsd:complexType name="EmployeeType">  
    <xsd:sequence>  
      <xsd:element name="Emp" type="EmployeeType"   
                              sql:relation="Emp"   
                              sql:key-fields="EmployeeID"  
                              sql:relationship="SupervisorSupervisee"  
                              sql:max-depth="6" />  
    </xsd:sequence>   
    <xsd:attribute name="EmployeeID" type="xsd:ID" />  
    <xsd:attribute name="FirstName" type="xsd:string"/>  
    <xsd:attribute name="LastName" type="xsd:string"/>  
  </xsd:complexType>  
</xsd:schema>  

このリレーションシップは再帰的なので、何らかの方法でスキーマ内の再帰の深さを指定する必要があります。 指定しない場合、結果は無限再帰となり、従業員から次の従業員へと無限に報告を行うことになります。 sql:max-depth注釈を使用すると、再帰の深さを指定できます。 この特定の例では、 sql:max-depth の値を指定するには、社内の管理階層の深さを把握しておく必要があります。

Note

スキーマは sql:limit-field 注釈を指定しますが、 sql:limit-value 注釈は指定しません。 これにより、結果として生成される階層の一番上のノードは、だれにも報告しない従業員だけになります (ReportsTo は NULL です)。) sql:limit-field を指定し sql:limit-value (既定値は NULL) 注釈を指定しないと、これを実現します。 結果の XML に可能なすべてのレポート ツリー (テーブル内のすべての従業員のレポート ツリー) を含める場合は、スキーマから sql:limit-field 注釈を削除します。

Note

次の手順では、tempdb データベースを使用します。

スキーマに対してサンプル XPath クエリをテストするには

  1. 仮想ルートが示す tempdb データベースに、Emp という名前のサンプル テーブルを作成します。

    USE tempdb  
    CREATE TABLE Emp (  
           EmployeeID int primary key,   
           FirstName  varchar(20),   
           LastName   varchar(20),   
           ReportsTo int)  
    
  2. 次のサンプル データを追加します。

    INSERT INTO Emp values (1, 'Nancy', 'Devolio',NULL)  
    INSERT INTO Emp values (2, 'Andrew', 'Fuller',1)  
    INSERT INTO Emp values (3, 'Janet', 'Leverling',1)  
    INSERT INTO Emp values (4, 'Margaret', 'Peacock',3)  
    INSERT INTO Emp values (5, 'Steven', 'Devolio',4)  
    INSERT INTO Emp values (6, 'Nancy', 'Buchanan',5)  
    INSERT INTO Emp values (7, 'Michael', 'Suyama',6)  
    
  3. 上のスキーマのコードをコピーして、テキスト ファイルに貼り付け、 maxDepth.xml として保存します。

  4. 次のテンプレートをコピーして、テキスト ファイルに貼り付け、 maxDepth.xml を保存したディレクトリに maxDepthT.xml としてファイルを保存します。 このテンプレートのクエリでは、Emp テーブル内のすべての従業員が返されます。

    <ROOT xmlns:sql="urn:schemas-microsoft-com:xml-sql">  
      <sql:xpath-query mapping-schema="maxDepth.xml">  
        /Emp  
      </sql:xpath-query>  
    </ROOT>  
    

    マッピング スキーマ (maxDepth.xml) に指定するディレクトリ パスは、テンプレートを保存するディレクトリに対する相対パスです。 次のように、絶対パスを指定することもできます。

    mapping-schema="C:\MyDir\maxDepth.xml"  
    
  5. SQLXML 4.0 テスト スクリプト (sqlxml4test.vbs) を作成し、それを使用してテンプレートを実行します。 詳細については、「ADO を使用した SQLXML 4.0 クエリの実行」を参照してください。

結果を次に示します。

<?xml version="1.0" encoding="utf-8" ?>   
<root>  
  <Emp FirstName="Nancy" EmployeeID="1" LastName="Devolio">  
  <Emp FirstName="Andrew" EmployeeID="2" LastName="Fuller" />   
    <Emp FirstName="Janet" EmployeeID="3" LastName="Leverling">  
      <Emp FirstName="Margaret" EmployeeID="4" LastName="Peacock">  
        <Emp FirstName="Steven" EmployeeID="5" LastName="Devolio">  
          <Emp FirstName="Nancy" EmployeeID="6" LastName="Buchanan">  
            <Emp FirstName="Michael" EmployeeID="7" LastName="Suyama" />   
          </Emp>  
        </Emp>  
      </Emp>  
    </Emp>  
  </Emp>  
</root>  

Note

結果で異なる階層の深さを生成するには、スキーマ内の sql:max-depth 注釈の値を変更し、変更後にテンプレートをもう一度実行します。

前のスキーマでは、すべての <Emp> 要素にまったく同じ属性セット (EmployeeIDFirstName、および LastName) がありました。 次のスキーマは、マネージャーに報告するすべての <Emp> 要素の追加の ReportsTo 属性を返すように少し変更されています。

たとえば、次の XML フラグメントでは、従業員 1 の部下が示されています。

<?xml version="1.0" encoding="utf-8" ?>   
<root>  
<Emp FirstName="Nancy" EmployeeID="1" LastName="Devolio">  
  <Emp FirstName="Andrew" EmployeeID="2"   
       ReportsTo="1" LastName="Fuller" />   
  <Emp FirstName="Janet" EmployeeID="3"   
       ReportsTo="1" LastName="Leverling">  
...  
...  

変更後のスキーマは次のようになります。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
            xmlns:dt="urn:schemas-microsoft-com:datatypes"  
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">  
  <xsd:annotation>  
    <xsd:documentation>  
      Customer-Order-Order Details Schema  
      Copyright 2000 Microsoft. All rights reserved.  
    </xsd:documentation>  
    <xsd:appinfo>  
      <sql:relationship name="SupervisorSupervisee"   
                  parent="Emp"  
                  parent-key="EmployeeID"  
                  child="Emp"  
                  child-key="ReportsTo" />  
    </xsd:appinfo>  
  </xsd:annotation>  
  <xsd:element name="Emp"   
                   type="EmpType"   
                   sql:relation="Emp"   
                   sql:key-fields="EmployeeID"   
                   sql:limit-field="ReportsTo" />  
  <xsd:complexType name="EmpType">  
    <xsd:sequence>  
       <xsd:element name="Emp"   
                    type="EmpType"   
                    sql:relation="Emp"   
                    sql:key-fields="EmployeeID"  
                    sql:relationship="SupervisorSupervisee"  
                    sql:max-depth="6"/>  
    </xsd:sequence>   
    <xsd:attribute name="EmployeeID" type="xsd:int" />  
    <xsd:attribute name="FirstName" type="xsd:string"/>  
    <xsd:attribute name="LastName" type="xsd:string"/>  
    <xsd:attribute name="ReportsTo" type="xsd:int" />  
  </xsd:complexType>  
</xsd:schema>  

sql:max-depth 注釈

再帰リレーションシップで構成されるスキーマでは、スキーマ内に再帰の深さを明示的に指定する必要があります。 これは、対応する FOR XML EXPLICIT クエリを正常に作成し、要求された結果を返すために必要です。

スキーマ内の sql:max-depth 注釈を使用して、スキーマで記述されている再帰リレーションシップの再帰の深さを指定します。 sql:max-depth注釈の値は、再帰の数を示す正の整数 (1 ~ 50) です。値 1 を指定すると、sql:max-depth注釈が指定されている要素で再帰が停止します。 値 2 を指定すると、sql:max-depth が指定されている要素から次のレベルで再帰が停止します。

Note

基になる実装では、マッピング スキーマに対して指定された XPath クエリが SELECT ... に変換されます。FOR XML EXPLICIT クエリ。 このクエリでは、再帰に有限の深さを指定する必要があります。 sql:max-depth に指定する値が大きいほど、生成される FOR XML EXPLICIT クエリは大きくなります。 これによって、取得に時間がかかることがあります。

Note

アップデートグラムと XML 一括読み込みでは、max-depth 注釈は無視されます。 つまり、再帰更新や再帰挿入は、max-depth に指定されている値に関係なく行われます。

複合要素での sql:max-depth の指定

sql:max-depth注釈は、任意の複雑なコンテンツ要素で指定できます。

再帰要素

sql:max-depthが再帰リレーションシップの親要素と子要素の両方で指定されている場合、親に指定されたsql:max-depth注釈が優先されます。 たとえば、次のスキーマでは、 sql:max-depth 注釈が親要素と子従業員要素の両方で指定されています。 この場合、 sql:max-depth=4 (スーパーバイザの役割を果たす) <Emp> 親要素で指定された値が優先されます。 子<Emp>要素で指定されたsql:max-depthは無視されます。

例 B

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
            xmlns:dt="urn:schemas-microsoft-com:datatypes"  
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">  
  <xsd:annotation>  
    <xsd:appinfo>  
      <sql:relationship name="SupervisorSupervisee"  
                                  parent="Emp"  
                                  parent-key="EmployeeID"  
                                  child="Emp"  
                                  child-key="ReportsTo" />  
    </xsd:appinfo>  
  </xsd:annotation>  
  <xsd:element name="Emp" type="EmployeeType"   
                          sql:relation="Emp"   
                          sql:key-fields="EmployeeID"   
                          sql:limit-field="ReportsTo"   
                          sql:max-depth="3" />  
  <xsd:complexType name="EmployeeType">  
    <xsd:sequence>  
      <xsd:element name="Emp" type="EmployeeType"   
                              sql:relation="Emp"   
                              sql:key-fields="EmployeeID"  
                              sql:relationship="SupervisorSupervisee"  
                              sql:max-depth="2" />  
    </xsd:sequence>   
    <xsd:attribute name="EmployeeID" type="xsd:ID" />  
    <xsd:attribute name="FirstName" type="xsd:string"/>  
    <xsd:attribute name="LastName" type="xsd:string"/>  
  </xsd:complexType>  
</xsd:schema>  

このスキーマをテストするには、このトピックで前述したサンプル A の手順に従います。

非再帰要素

sql:max-depth注釈が、再帰を引き起こさないスキーマ内の要素に対して指定されている場合、その注釈は無視されます。 次のスキーマでは、 <Emp> 要素は <Constant> 子要素で構成され、子要素には <Emp> 子要素があります。

このスキーマでは、<Constant> 要素に指定された sql:max-depth 注釈は無視されます。これは、<Emp> 親要素と <Constant> 子要素の間に再帰がないためです。 しかし、 <Emp> 先祖と <Emp> 子の間には再帰があります。 スキーマでは、両方の sql:max-depth 注釈を指定します。 したがって、先祖 (スーパーバイザ ロールの<Emp>) で指定されたsql:max-depth注釈が優先されます。

例 C

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"   
xmlns:sql="urn:schemas-microsoft-com:mapping-schema">  
  <xsd:annotation>  
    <xsd:appinfo>  
      <sql:relationship name="SupervisorSupervisee"   
                  parent="Emp"   
                  child="Emp"   
                  parent-key="EmployeeID"   
                  child-key="ReportsTo"/>  
    </xsd:appinfo>  
  </xsd:annotation>  
  <xsd:element name="Emp"   
               sql:relation="Emp"   
               type="EmpType"  
               sql:limit-field="ReportsTo"  
               sql:max-depth="1" />  
    <xsd:complexType name="EmpType" >  
      <xsd:sequence>  
       <xsd:element name="Constant"   
                    sql:is-constant="1"   
                    sql:max-depth="20" >  
         <xsd:complexType >  
           <xsd:sequence>  
            <xsd:element name="Emp"   
                         sql:relation="Emp" type="EmpType"  
                         sql:relationship="SupervisorSupervisee"   
                         sql:max-depth="3" />  
         </xsd:sequence>  
         </xsd:complexType>  
         </xsd:element>  
      </xsd:sequence>  
      <xsd:attribute name="EmployeeID" type="xsd:int" />  
    </xsd:complexType>  
</xsd:schema>  

このスキーマをテストするには、このトピックの例 A の手順に従ってください。

制限により派生する複合型

<restriction>による複合型派生がある場合、対応する基本複合型の要素は、sql:max-depth 注釈を指定できません。 このような場合、 sql:max-depth 注釈を派生型の要素に追加できます。

一方、 <extension> による複合型の派生がある場合、対応する基本複合型の要素は、 sql:max-depth 注釈を指定できます。

たとえば、次の XSD スキーマでは、基本型に sql:max-depth 注釈が指定されているため、エラーが生成されます。 この注釈は、別の型から <restriction> によって派生した型ではサポートされていません。 この問題を解決するには、スキーマを変更し、派生型の要素に対して sql:max-depth 注釈を指定する必要があります。

例 D

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
            xmlns:dt="urn:schemas-microsoft-com:datatypes"  
            xmlns:msdata="urn:schemas-microsoft-com:mapping-schema">  
  <xsd:complexType name="CustomerBaseType">   
    <xsd:sequence>  
       <xsd:element name="CID" msdata:field="CustomerID" />  
       <xsd:element name="CompanyName"/>  
       <xsd:element name="Customers" msdata:max-depth="3">  
         <xsd:annotation>  
           <xsd:appinfo>  
             <msdata:relationship  
                     parent="Customers"  
                     parent-key="CustomerID"  
                     child-key="CustomerID"  
                     child="Customers" />  
           </xsd:appinfo>  
         </xsd:annotation>  
       </xsd:element>  
    </xsd:sequence>  
  </xsd:complexType>  
  <xsd:element name="Customers" type="CustomerType"/>  
  <xsd:complexType name="CustomerType">  
    <xsd:complexContent>  
       <xsd:restriction base="CustomerBaseType">  
          <xsd:sequence>  
            <xsd:element name="CID"   
                         type="xsd:string"/>  
            <xsd:element name="CompanyName"   
                         type="xsd:string"  
                         msdata:field="CName" />  
            <xsd:element name="Customers"   
                         type="CustomerType" />  
          </xsd:sequence>  
       </xsd:restriction>  
    </xsd:complexContent>  
  </xsd:complexType>  
</xsd:schema>   

スキーマでは、 sql:max-depthCustomerBaseType 複合型で指定されます。 このスキーマでは、CustomerBaseType> から派生した CustomerType 型の <Customer 要素も指定します。 sql:max-depth は制限の基本型で定義されている要素ではサポートされていないため、このようなスキーマで指定された XPath クエリではエラーが生成されます。

深い階層のスキーマ

要素に子要素が含まれ、その子要素にさらに別の子要素が含まれるというような深い階層のスキーマの場合は、 このようなスキーマで指定された sql:max-depth 注釈によって、500 レベルを超える階層 (レベル 1 の最上位要素、レベル 2 の子など) を含む XML ドキュメントが生成された場合、エラーが返されます。