Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Van toepassing op:SQL Server
Azure SQL Database
In relationele databases wordt een relatie met zichzelf genoemd wanneer een tabel een relatie met zichzelf heeft. Bijvoorbeeld, in een relatie tussen supervisor en supervisie is een tafel die werknemersdossiers opslaat betrokken bij een relatie met zichzelf. In dit geval speelt de personeelstafel aan de ene kant van de relatie de rol van supervisor, en dezelfde tafel aan de andere kant de rol van supervisie.
Mapping schema's kunnen recursieve relaties bevatten waarbij een element en zijn voorouder van hetzelfde type zijn.
Voorbeeld A
Beschouw de volgende tabel:
Emp (EmployeeID, FirstName, LastName, ReportsTo)
In deze tabel slaat de kolom ReportsTo het werknemers-ID van de manager op.
Stel dat je een XML-hiërarchie van medewerkers wilt genereren waarin de manager-medewerker bovenaan de hiërarchie staat, en waarin de medewerkers die aan die manager rapporteren in de overeenkomstige hiërarchie verschijnen zoals getoond in het volgende voorbeeld XML-fragment. Wat dit fragment laat zien, is de recursieve boom voor werknemer 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>
In dit fragment rapporteert werknemer 5 aan werknemer 4, werknemer 4 aan werknemer 3, en medewerkers 3 en 2 aan werknemer 1.
Om dit resultaat te bereiken, kun je het volgende XSD-schema gebruiken en een XPath-query daarop specificeren. Het schema beschrijft een <Emp-element> van het type EmployeeType, bestaande uit een <Emp-kindelement> van hetzelfde type, EmployeeType. Dit is een recursieve relatie (het element en zijn voorouder zijn van hetzelfde type). Daarnaast gebruikt het schema een <sql:relatie> om de ouder-kindrelatie tussen de supervisor en supervisee te beschrijven. Let op dat in deze <sql:relationship>, Emp zowel de ouder- als de kindtabel is.
<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>
Omdat de relatie recursief is, heb je een manier nodig om de diepte van de recursie in het schema te specificeren. Anders zal het resultaat een eindeloze herhaling zijn (werknemer rapporteert aan werknemer die aan werknemer rapporteert, enzovoort). De sql:max-depth annotatie stelt je in staat aan te geven hoe diep je in de recursie wilt gaan. In dit specifieke voorbeeld moet je om een waarde voor sql:max-depth te specificeren weten hoe diep de managementhiërarchie in het bedrijf zit.
Opmerking
Het schema specificeert de sql:limit-field annotatie, maar specificeert niet de sql:limit-value annotatie. Dit beperkt de bovenste knoop in de resulterende hiërarchie tot alleen die medewerkers die aan niemand rapporteren. (ReportsTo is NULL.) Het specificeren van sql:limit-field en niet het specificeren van sql:limit-value (dat standaard op NULL staat) annotatie bereikt dit. Als je wilt dat de resulterende XML elke mogelijke rapportageboom bevat (de rapportageboom voor elke medewerker in de tabel), verwijder dan de sql:limit-field annotatie uit het schema.
Opmerking
De volgende procedure gebruikt de tempdb-database.
Om een voorbeeld van een XPath-query te testen tegen het schema
Maak een voorbeeldtabel genaamd Emp aan in de tempdb-database waarnaar de virtuele wortel verwijst.
USE tempdb CREATE TABLE Emp ( EmployeeID int primary key, FirstName varchar(20), LastName varchar(20), ReportsTo int)Voeg deze voorbeeldgegevens toe:
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)Kopieer de bovenstaande schemacode en plak deze in een tekstbestand. Sla het bestand op als maxDepth.xml.
Kopieer het volgende sjabloon en plak het in een tekstbestand. Sla het bestand op als maxDepthT.xml in dezelfde map waar je maxDepth.xmlhebt opgeslagen. De query in de template levert alle medewerkers in de Emp-tabel terug.
<ROOT xmlns:sql="urn:schemas-microsoft-com:xml-sql"> <sql:xpath-query mapping-schema="maxDepth.xml"> /Emp </sql:xpath-query> </ROOT>Het directorypad dat voor het mappingschema (maxDepth.xml) is gespecificeerd is relatief tot de map waar het sjabloon wordt opgeslagen. Een absoluut pad kan ook worden gespecificeerd, bijvoorbeeld:
mapping-schema="C:\MyDir\maxDepth.xml"Maak het SQLXML 4.0 Test Script (Sqlxml4test.vbs) aan en gebruik het om het sjabloon uit te voeren. Zie ADO gebruiken om SQLXML 4.0-query's uit te voeren voor meer informatie.
Dit is het resultaat:
<?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>
Opmerking
Om verschillende dieptes van hiërarchieën in het resultaat te produceren, verander je de waarde van de sql:max-depth-annotatie in het schema en voer je de template na elke wijziging opnieuw uit.
In het vorige schema hadden alle <Emp-elementen> exact dezelfde set attributen (EmployeeID, FirstName en AfterName). Het volgende schema is licht aangepast om een extra ReportsTo-attribuut terug te geven voor alle <Emp-elementen> die aan een manager rapporteren.
Bijvoorbeeld, dit XML-fragment toont de ondergeschikten van werknemer 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">
...
...
Dit is het herziene schema:
<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 Annotatie
In een schema dat bestaat uit recursieve relaties moet de diepte van recursie expliciet in het schema worden gespecificeerd. Dit is vereist om met succes de bijbehorende FOR XML EXPLICIT-query te produceren die de gevraagde resultaten teruggeeft.
Gebruik de sql:max-depth-annotatie in het schema om de diepte van recursie te specificeren in een recursieve relatie die in het schema wordt beschreven. De waarde van de sql:max-depth annotatie is een positief geheel getal (1 tot 50) dat het aantal recursies aangeeft: een waarde van 1 stopt de recursie bij het element waarvoor de sql:max-depth annotatie is gespecificeerd; Een waarde van 2 stopt de recursie op het volgende niveau vanaf het element waarop SQL:Max-diepte is gespecificeerd; enzovoort.
Opmerking
In de onderliggende implementatie wordt een XPath-query die is gespecificeerd tegen een mappingschema omgezet naar een SELECT ... VOOR XML EXPLICIETE query. Deze query vereist dat je een eindige diepte van recursie specificeert. Hoe hoger de waarde die je specificeert voor sql:max-depth, hoe groter de FOR XML EXPLICIT-query die wordt gegenereerd. Dit kan de ophaaltijd vertragen.
Opmerking
Updategrams en XML Bulk Load negeren de max-depth annotatie. Dit betekent dat recursieve updates of inserties zullen plaatsvinden, ongeacht welke waarde je specificeert voor maximale diepte.
Specificeren van sql:max-depth op Complexe Elementen
De sql:max-depth annotatie kan worden gespecificeerd op elk complex inhoudselement.
Recursieve elementen
Als sql:max-depth zowel op het ouderelement als het kindelement in een recursieve relatie is gespecificeerd, krijgt de sql:max-depth-annotatie die op de ouder is gespecificeerd voorrang. Bijvoorbeeld, in het volgende schema is de sql:max-depth annotatie gespecificeerd op zowel de ouder- als de kindwerknemer-elementen. In dit geval krijgt sql:max-depth=4, gespecificeerd op het <Emp-ouderelement> (als supervisor), voorrang. De sql:max-depth die op het kind-Emp-element<> (die een rol van supervisee speelt) wordt genegeerd.
Voorbeeld 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>
Om dit schema te testen, volg je de stappen die eerder in dit onderwerp voor Voorbeeld A zijn gegeven.
Niet-recursieve elementen
Als de sql:max-depth-annotatie wordt gespecificeerd op een element in het schema dat geen recursie veroorzaakt, wordt deze genegeerd. In het volgende schema bestaat een <Emp-element> uit een <Constant-kindelement> , dat op zijn beurt een <Emp-kindelement> heeft.
In dit schema wordt de sql:max-depth-annotatie die op het <Constant-element> is gespecificeerd genegeerd omdat er geen recursie is tussen de <Emp-ouder> en het <Constant-kindelement> . Maar er is recursie tussen de <Emp-voorouder> en het <Emp-kind> . Het schema specificeert de sql:max-depth-annotatie op beide. Daarom krijgt de sql:max-diepte-annotatie die op de voorouder is gespecificeerd (<Emp> in de supervisorrol) voorrang.
Voorbeeld 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>
Om dit schema te testen, volg je de stappen die eerder in dit onderwerp voor Voorbeeld A zijn gegeven.
Complexe types afgeleid door restrictie
Als je een complexe type-afleiding hebt door <restrictie>, kunnen elementen van het bijbehorende basiscomplexe type de sql:max-depth annotatie niet specificeren. In deze gevallen kan de sql:max-depth-annotatie worden toegevoegd aan het element van het afgeleide type.
Aan de andere kant, als je een complexe type-afleiding hebt via <uitbreiding>, kunnen de elementen van het bijbehorende basiscomplex type de sql:max-depth annotatie specificeren.
Bijvoorbeeld, het volgende XSD-schema genereert een fout omdat de sql:max-depth-annotatie op het basistype is gespecificeerd. Deze annotatie wordt niet ondersteund op een type dat is afgeleid door <restrictie> van een ander type. Om dit probleem op te lossen, moet je het schema wijzigen en de sql:max-depth-annotatie op element in het afgeleide type specificeren.
Voorbeeld 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>
In het schema wordt sql:max-depth gespecificeerd op een CustomerBaseType complex type. Het schema specificeert ook een <Customer-element> van het type CustomerType, dat is afgeleid van CustomerBaseType. Een XPath-query die op zo'n schema is gespecificeerd, zal een fout genereren, omdat sql:max-depth niet wordt ondersteund op een element dat is gedefinieerd in een restrictiebasistype.
Schema's met een diepe hiërarchie
Je zou een schema kunnen hebben dat een diepe hiërarchie bevat waarbij een element een kindelement bevat, dat op zijn beurt weer een ander kindelement bevat, enzovoort. Als de sql:max-depth-annotatie die in zo'n schema is gespecificeerd een XML-document genereert dat een hiërarchie van meer dan 500 niveaus bevat (met top-level element op niveau 1, het kind op niveau 2, enzovoort), wordt er een foutmelding teruggegeven.