使用 sql:max-depth 來指定遞迴關聯性的深度

適用於:SQL ServerAzure SQL 資料庫

在關係資料庫中,當數據表與本身有關聯性時,它稱為遞歸關聯性。 例如,在監督監督關聯性中,儲存員工記錄的數據表會參與與本身的關係。 在這種情況下,員工數據表在關係一邊扮演主管的角色,而同一張桌子在另一邊扮演監督的角色。

對應架構可以包含遞歸關聯性,其中元素及其上階屬於相同類型。

範例 A

以下列資料表來說:

Emp (EmployeeID, FirstName, LastName, ReportsTo)  

在此數據表中,ReportsTo 數據行會儲存經理的員工標識碼。

假設您想要產生員工 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 深度的值,您必須知道管理階層在公司中的深度。

注意

架構會 指定 sql:limit-field 註釋,但未指定 sql:limit-value 註釋。 這會將產生的階層中的最上層節點限制為只有未向任何人報告的員工。 (ReportsTo 為 NULL。)指定 sql:limit-field ,而不是指定 sql:limit-value (預設值為 NULL) 註釋即可完成此作業。 如果您想要讓產生的 XML 包含每個可能的報表樹狀結構(數據表中每位員工的報告樹狀結構),請從架構中移除 sql:limit-field 批注。

注意

下列程式會使用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. 複製下列範本,並將它貼到文字檔中。 將檔案儲存為maxDepthT.xml儲存maxDepth.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>  

注意

若要在結果中產生不同的階層深度,請變更架構中 sql:max-depth 註釋的值,並在每次變更之後再次執行範本。

在先前的架構中 <,所有 Emp> 元素都有完全相同的屬性集(EmployeeIDFirstNameLastName)。 下列架構已經過稍微修改,以針對向管理員報告的所有< 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 Annotation

在包含遞歸關聯性的架構中,必須在架構中明確指定遞歸深度。 若要成功產生傳回所要求結果的對應 FOR XML EXPLICIT 查詢,必須執行此作業。

在架構中使用 sql:max-depth 批注,在架構中所述的遞歸關聯性中指定遞歸深度。 sql:max-depth 批注的值是正整數(1 到 50),表示遞歸數目:值 1 會停止指定 sql:max-depth 批注之元素的遞歸;2 的值會停止下一個層級的遞歸,從指定 sql:max-depth 的元素開始遞歸,依故。

注意

在基礎實作中,針對對應架構指定的 XPath 查詢會轉換成 SELECT ...FOR XML EXPLICIT 查詢。 此查詢會要求您指定遞歸的有限深度。 您為 sql:max-depth 指定的值愈高,產生的 FOR XML EXPLICIT 查詢愈大。 這可能會減緩擷取時間。

注意

Updategram 和 XML 大量載入會忽略最大深度註釋。 這表示,不論您為最大深度指定的值為何,都會發生遞歸更新或插入。

在複雜元素上指定 sql:max-depth

您可以在任何複雜的內容元素上指定 sql:max-depth 註釋。

遞歸元素

如果在 遞歸關聯性的父元素和子元素上指定 sql:max-depth則父代上指定的 sql:max 深度 批注優先。 例如,在下列架構中, 會在父元素和子員工元素上指定 sql:max 深度 批注。 在此情況下,在 Emp> 父元素上<指定 sql:max-depth=4(扮演主管角色)優先。 忽略在子< 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 註釋。 因此,在上階上指定之 sql:max 深度批注(<主管角色中的 Emp>) 優先。

範例 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 所提供的步驟。

依限制衍生的複雜型別

如果您有依 <限制>衍生的複雜型別,對應基底複雜類型的元素無法指定 sql:max 深度 批注。 在這些情況下, 可以將 sql:max 深度 批註新增至衍生型別的 元素。

另一方面,如果您有以延伸>方式<衍生的複雜型別,對應的基底複雜類型元素可以指定 sql:max 深度批注。

例如,下列 XSD 架構會產生錯誤,因為 基底類型上指定了 sql:max 深度 註釋。 此批注不受其他類型限制>所衍生<的類型支援。 若要修正此問題,您必須變更架構,並在衍生型別的 元素上指定 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-depth 是在 CustomerBaseType 複雜類型上指定。 架構也會指定 <CustomerType 類型的 Customer> 元素,該元素衍生自 CustomerBaseType。 在這類架構上指定的 XPath 查詢會產生錯誤,因為 限制基底類型中定義的元素不支援 sql:max-depth

具有深層階層的架構

您可能有一個架構,其中包含一個深層階層,其中元素包含子元素,接著包含另一個子專案等等。 如果這類架構中指定的 sql:max-depth 批注會產生包含階層超過 500 個層級的 XML 檔(在層級 1 的頂層元素為第 1 層、其子層級 2 等等),則會傳回錯誤。