在关系数据库中,当表与自身关系中涉及时,它称为递归关系。 例如,在监督监督关系中,存储员工记录的表涉及与自身的关系。 在这种情况下,员工表在关系一侧扮演监督员的角色,同一表在另一边扮演监督者的角色。
映射架构可以包含递归关系,其中元素及其上级具有相同类型。
示例 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,必须知道管理层次结构在公司中的深度。
注释
架构指定 sql:limit-field 批注,但不指定 sql:limit-value 批注。 这会将生成的层次结构中的顶部节点限制为仅那些不向任何人报告的员工。 (ReportsTo 为 NULL。)指定 sql:limit-field 和未指定 sql:limit-value (默认为 NULL)批注可实现此目的。 如果希望生成的 XML 包含每个可能的报表树(表中每个员工的报表树),请从架构中删除 sql:limit-field 批注。
注释
以下过程使用 tempdb 数据库。
针对架构测试示例 XPath 查询
在虚拟根点所在的 tempdb 数据库中创建名为 Emp 的示例表。
USE tempdb CREATE TABLE Emp ( EmployeeID int primary key, FirstName varchar(20), LastName varchar(20), ReportsTo int)添加此示例数据:
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)复制上面的架构代码,并将它粘贴到文本文件中。 将文件另存为 maxDepth.xml。
复制以下模板,并将它粘贴到文本文件中。 将文件另存为 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"创建并使用 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> 元素具有相同的属性集(EmployeeID、 FirstName 和 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 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 深度
sql:max-depth可以在任何复杂内容元素上指定批注。
递归元素
如果在 sql:max-depth 递归关系中对父元素和子元素指定,则 sql:max-depth 父元素上指定的批注优先。 例如,在以下架构中,批 sql:max-depth 注在父元素和子员工元素上指定。 在这种情况下,sql:max-depth=4在 Emp> 父元素上<指定(扮演主管角色)优先。 忽略 sql:max-depth 对子 <Emp> 元素(发挥监督作用)的指定。
示例 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> 元素由常量>子元素组成<,后者又具有 Emp<> 子元素。
在此架构中,sql:max-depth忽略对 Constant> 元素指定的<批注,因为 Emp> 父元素和 Constant 子元素之间<没有递>归。< 但是,Emp> 祖先和 Emp 子级之间<有递归。>< 架构指定 sql:max-depth 两者的注释。 因此, sql:max-depth 在上级(<主管角色中的 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-depth 批注。 在这些情况下, sql:max-depth 可以将批注添加到派生类型的元素。
另一方面,如果有按 <扩展>派生的复杂类型,则相应的基复杂类型的元素可以指定 sql:max-depth 批注。
例如,以下 XSD 架构生成错误,因为 sql:max-depth 批注是在基类型上指定的。 此批注不受其他类型的限制>派生<的类型的支持。 若要解决此问题,必须更改架构并指定 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 指定。 该架构还指定一个 <类型为 Customer> 元素, CustomerType该元素派生自 CustomerBaseType。 针对此类架构指定的 XPath 查询将生成错误,因为在 sql:max-depth 限制基类型中定义的元素上不受支持。
具有深层层次结构的架构
你可能有一个架构,其中包含一个深层层次结构,其中元素包含一个子元素,而子元素又包含另一个子元素,等等。
sql:max-depth如果此类架构中指定的批注生成一个 XML 文档,该文档包含层次结构超过 500 个级别(级别为 1 的顶级元素、第 2 级子元素等),则返回错误。