XPath-Datentypen (SQLXML 4.0)
MicrosoftSQL Server-, XPath- und XML-Schemas (XSD) verfügen über sehr unterschiedliche Datentypen. Zum Beispiel verfügt XPath nicht über Ganzzahl- oder Datumsdatentypen, SQL Server und XSD hingegen über mehrere. XSD gibt Zeitwerte auf die Nanosekunde genau an, während die Genauigkeit von SQL Server höchstens 1/300 Sekunde beträgt. Einen Datentyp einem anderen zuzuordnen ist deshalb nicht immer möglich. Weitere Informationen über das Zuordnen von SQL Server-Datentypen und XSD-Datentypen finden Sie unter Datentypumwandlungen und die sql:datatype-Anmerkung (SQLXML 4.0).
XPath verfügt über drei Datentypen: string, number und boolean. Beim number-Datentyp handelt es sich stets um einen IEEE 754-Gleitkommawert mit doppelter Genauigkeit. Der SQL Server float(53)-Datentyp kommt XPath number am nächsten. Allerdings entspricht float(53) IEEE 754 nicht genau. Zum Beispiel wird weder NaN (Not-a-Number) noch Unendlichkeit verwendet. Wenn man versucht, eine nicht numerische Zeichenfolge in number zu konvertieren und eine Division durch Null durchzuführen, tritt ein Fehler auf.
XPath-Konvertierungen
Wenn Sie eine XPath-Abfrage wie OrderDetail[@UnitPrice > "10.0"] verwenden, können implizite und explizite Datentypkonvertierungen den Sinn der Abfrage leicht verändern. Deshalb sollte nachvollzogen werden können, wie XPath-Datentypen implementiert werden. Die XPath-Sprachspezifikation, Empfehlung der W3C XML Path Language (XPath) Version 1.0 vom 8. Oktober 1999, finden Sie auf der W3C-Website unter http://www.w3.org/TR/1999/PR-xpath-19991008.html.
XPath-Operatoren werden in vier Kategorien unterteilt:
Boolesche Operatoren (AND, OR)
Relationale Operatoren (<, >, <=, >=)
Gleichheitsoperatoren (=, !=)
Arithmetische Operatoren (+, -, *, DIV, MOD)
Bei jeder Operatorkategorie werden die Operanden auf andere Art und Weise konvertiert. XPath-Operatoren konvertieren ihre Operanden gegebenenfalls implizit. Arithmetische Operatoren konvertieren ihre Operanden in den Typ number und geben einen Zahlenwert aus. Boolesche Operatoren konvertieren ihre Operanden in den Typ boolean und geben einen booleschen Wert aus. Relationale Operatoren und Gleichheitsoperatoren geben einen booleschen Wert aus. Allerdings verfügen sie, je nach dem ursprünglichen Datentyp ihrer Operanden, über unterschiedliche Konvertierungsregeln (siehe Tabelle).
Operand |
Relationaler Operator |
Gleichheitsoperator |
---|---|---|
Beide Operanden sind Knotensätze. |
TRUE ist nur dann gegeben, wenn sich der eine Knoten in einem Satz und der andere Knoten im zweiten Satz befindet, sodass der Vergleich ihrer string-Werte TRUE ergibt. |
Identisch. |
Bei dem einen handelt sich um einen Knotensatz, bei dem anderen um den Typ string. |
TRUE ist nur dann gegeben, wenn sich ein Knoten im Knotensatz befindet und bei der Konvertierung in number der Vergleich mit dem in number konvertierten Datentyp string TRUE ergibt. |
TRUE ist nur dann gegeben, wenn sich ein Knoten im Knotensatz befindet und bei der Konvertierung in string der Vergleich mit dem Datentyp string TRUE ergibt. |
Bei dem einen handelt sich um einen Knotensatz, bei dem anderen um den Typ number. |
TRUE ist nur dann gegeben, wenn sich ein Knoten im Knotensatz befindet und bei der Konvertierung in number der Vergleich mit dem Datentyp number TRUE ergibt. |
Identisch. |
Bei dem einen handelt sich um einen Knotensatz, bei dem anderen um den Typ boolean. |
TRUE ist nur dann gegeben, wenn sich ein Knoten im Knotensatz befindet und bei der Konvertierung in boolean und anschließend in number der Vergleich mit dem in number konvertierten Typ boolean TRUE ergibt. |
TRUE ist nur dann gegeben, wenn sich ein Knoten im Knotensatz befindet und bei der Konvertierung in boolean der Vergleich mit dem Typ boolean TRUE ergibt. |
In beiden Fällen handelt es sich nicht um einen Knotensatz. |
Konvertieren Sie beide Operanden in den Typ number, und führen Sie dann einen Vergleich durch. |
Konvertieren Sie beide Operanden in einen gängigen Typ , und führen Sie dann einen Vergleich durch. Führen Sie eine Konvertierung in den Typ boolean durch, wenn es sich um den Typ boolean handelt, oder in den Typ number, wenn es sich um den Typ number handelt. Andernfalls führen Sie eine Konvertierung in den Typ string durch. |
Hinweis |
---|
Da relationale XPath-Operatoren ihre Operanden stets in den Typ number konvertieren, sind string-Vergleiche nicht möglich. Um Datenvergleiche zu ermöglichen, bietet SQL Server 2000 bei der XPath-Spezifikation folgende Möglichkeit: Wenn ein relationaler Operator einen Typ string mit einem Typ string, einen Knotensatz mit einem Typ string oder einen als Zeichenkette angegebenen Knotensatz mit einem als Zeichenkette angegebenen Knotensatz vergleicht, erfolgt ein string-Vergleich (kein number-Vergleich). |
Konvertierungen von Knotensätzen
Konvertierungen von Knotensätzen sind nicht immer intuitiv. Die Konvertierung eines Knotensatzes in den Typ string erfolgt anhand des Zeichenkettenwerts des ersten Knotens des Satzes. Bei der Konvertierung eines Knotensatzes in den Typ number wird dieser zunächst in den Typ string und anschließend der Typ string in den Typ number konvertiert. Ein Knotensatz wird in den Typ boolean konvertiert, indem sein Vorhandensein überprüft wird.
Hinweis |
---|
SQL Server führt bei Knotensätzen keine Positionalauswahl durch: Die XPath-Abfrage Customer[3] beispielsweise bezieht sich auf den dritten Kunden; eine solche Positionalauswahl wird in SQL Server nicht unterstützt. Aus diesem Grund wurden die Konvertierungen, bei denen gemäß XPath-Spezifikation ein Knotensatz in den Typ string oder in den Typ number konvertiert wird, nicht implementiert. Die Semantik von SQL Server bezieht sich auf "ein" Vorkommnis, während die XPath-Spezifikation "das erste" Vorkommnis bezeichnet. Beispielsweise wählt gemäß W3C XPath-Spezifikation die XPath-Abfrage Order[OrderDetail/@UnitPrice > 10.0] Aufträge aus, bei deren erstem Auftreten von OrderDetail die Angabe UnitPrice größer als 10.0 ist. In SQL Server wählt diese XPath-Abfrage diejenigen Aufträge aus, bei denen die Angabe UnitPrice bei einem beliebigen Auftreten von OrderDetail größer als 10.0 ist. |
Bei Konvertierungen in den Typ boolean wird das Vorhandensein überprüft; aus diesem Grund entspricht die XPath-Abfrage Products[@Discontinued=true()] dem SQL-Ausdruck "Products.Discontinued is not null", nicht dem SQL-Ausdruck "Products.Discontinued = 1". Damit die Abfrage dem letztgenannten SQL-Ausdruck entspricht, konvertierten Sie den Knotensatz zunächst in einen anderen Typ als boolean, etwa number. Beispiel: Products[number(@Discontinued) = true()].
Da die meisten Operatoren gemäß Definition als TRUE gelten, wenn sie für einen beliebigen oder einen einzigen der Knoten im Knotensatz TRUE sind, ergeben diese Operationen stets FALSE, wenn der Knotensatz leer ist. Wenn also A leer ist, gilt sowohl für A = B als auch A != B FALSE, für not(A=B) und not(A!=B) hingegen gilt TRUE.
In der Regel ist ein Attribut oder ein Element, das auf eine Spalte verweist, vorhanden, sobald der Wert jener Spalte in der Datenbank ungleich null ist. Elemente, die auf Zeilen verweisen, sind vorhanden, sobald untergeordnete Elemente vorhanden sind.
Hinweis |
---|
Mit der is-constant-Anmerkung versehene Elemente sind immer vorhanden. Infolgedessen können XPath-Prädikate nicht für is-constant-Elemente verwendet werden. |
Wenn ein Knotensatz in den Typ string oder number konvertiert wird, wird sein XDR-Typ (sofern vorhanden) im mit Anmerkungen versehenen Schema überprüft. Dieser Typ wird dann verwendet, um die erforderliche Konvertierung zu ermitteln.
Zuordnung von XDR-Datentypen und XPath-Datentypen
Der XPath-Datentyp eines Knotens wird vom XDR-Datentyp im Schema abgeleitet, wie in der folgenden Tabelle dargestellt (der Knoten EmployeeID wird zur Veranschaulichung verwendet).
XDR-Datentyp |
Entsprechung XPath-Datentyp |
Verwendete SQL Server-Konvertierung |
---|---|---|
Nonebin.base64bin.hex |
– |
KeineEmployeeID |
boolean |
boolean |
CONVERT(bit, EmployeeID) |
number, int, float,i1, i2, i4, i8,r4, r8ui1, ui2, ui4, ui8 |
number |
CONVERT(float(53), EmployeeID) |
id, idref, idrefsentity, entities, enumerationnotation, nmtoken, nmtokens, chardate, Timedate, Time.tz, string, uri, uuid |
string |
CONVERT(nvarchar(4000), EmployeeID, 126) |
fixed14.4 |
– (es gibt keinen Datentyp in XPath, der dem fixed14.4 XDR-Datentyp entspricht) |
CONVERT(money, EmployeeID) |
date |
string |
LEFT(CONVERT(nvarchar(4000), EmployeeID, 126), 10) |
time time.tz |
string |
SUBSTRING(CONVERT(nvarchar(4000), EmployeeID, 126), 1 + CHARINDEX(N'T', CONVERT(nvarchar(4000), EmployeeID, 126)), 24) |
Datum- und Zeitkonvertierungen funktionieren unabhängig davon, ob der Wert mithilfe des SQL Server datetime-Datentyps oder des Typs string in der Datenbank gespeichert wird. Der SQL Server datetime-Datentyp verwendet timezone nicht und ist ungenauer als der XML time-Datentyp. Um den timezone-Datentyp aufzunehmen oder eine höhere Genauigkeit zu gewährleisten, speichern Sie die Daten mithilfe eines string-Typs in SQL Server.
Wenn ein Knoten vom XDR-Datentyp in den XPath-Datentyp konvertiert wird, müssen mitunter weitere Konvertierungen vorgenommen werden (von einem XPath-Datentyp in einen anderen XPath-Datentyp). Ein Beispiel ist die folgende XPath-Abfrage:
(@m + 3) = 4
Wenn es sich bei @m um den fixed14.4 XDR-Datentyp handelt, erfolgt die Konvertierung vom XDR-Datentyp in den XPath-Datentyp wie folgt:
CONVERT(money, m)
Bei dieser Konvertierung wird der Knoten m von fixed14.4 in money konvertiert. Um den Wert 3 hinzuzufügen, ist jedoch eine zusätzliche Konvertierung erforderlich:
CONVERT(float(CONVERT(money, m))
Der XPath-Ausdruck wird wie folgt ausgewertet:
CONVERT(float(CONVERT(money, m)) + CONVERT(float(53), 3) = CONVERT(float(53), 3)
Wie in der folgenden Tabelle dargestellt, handelt es sich hierbei um die gleiche Konvertierung wie bei anderen XPath-Ausdrücken (etwa Literalausdrücken oder zusammengesetzten Ausdrücken).
|
X ist unbekannt |
X ist vom Datentyp string |
X ist vom Datentyp number |
X ist vom Datentyp boolean |
string(X) |
CONVERT (nvarchar(4000), X, 126) |
- |
CONVERT (nvarchar(4000), X, 126) |
CASE WHEN X THEN N'true' ELSE N'false' END |
number(X) |
CONVERT (float(53), X) |
CONVERT (float(53), X) |
- |
CASE WHEN X THEN 1 ELSE 0 END |
boolean(X) |
- |
LEN(X) > 0 |
X != 0 |
- |
Beispiele
A.Konvertieren Sie einen Datentyp in einer XPath-Abfrage
Die folgende, für ein mit Anmerkungen versehenes XSD-Schema angegebene XPath-Abfrage wählt alle Employee-Knoten aus, bei denen der EmployeeID-Attributwert "E-1" lautet. Dabei ist "E-" das mithilfe der sql:id-prefix-Anmerkung festgelegte Präfix.
Employee[@EmployeeID="E-1"]
Das Prädikat in der Abfrage entspricht dem folgenden SQL-Ausdruck:
N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'
Da es sich bei EmployeeID um einen der id-Datentypwerte (idref, idrefs, nmtoken, nmtokens usw.) im XSD-Schema handelt, wird EmployeeID mithilfe der zuvor beschriebenen Konvertierungsregeln in den string-XPath-Datentyp konvertiert.
CONVERT(nvarchar(4000), Employees.EmployeeID, 126)
Der Zeichenfolge wird das Präfix "E-" hinzugefügt, und das Ergebnis wird dann mit N'E-1' verglichen.
B.Führen Sie mehrere Datentypkonvertierungen in einer XPath-Abfrage aus
Betrachten Sie die folgende, für ein mit Anmerkungen versehenes XSD-Schema angegebene XPath-Abfrage: OrderDetail[@UnitPrice * @OrderQty > 98]
Diese XPath-Abfrage gibt alle <OrderDetail>-Elemente zurück, die das Prädikat @UnitPrice * @OrderQty > 98 erfüllen. Wenn UnitPrice im Schema mit einem fixed14.4-Datentyp versehen ist, entspricht dieses Prädikat dem folgenden SQL-Ausdruck:
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice)) * CONVERT(float(53), OrderDetail.OrderQty) > CONVERT(float(53), 98)
Beim Konvertieren der Werte in der XPath-Abfrage wird zunächst der XDR-Datentyp in den XPath-Datentyp konvertiert. Da der XSD-Datentyp UnitPrice gemäß voranstehender Tabelle fixed14.4 ist, wird als erstes die folgende Konvertierung verwendet:
CONVERT(money, OrderDetail.UnitPrice))
Da die arithmetischen Operatoren ihre Operanden in den number-XPath-Datentyp konvertieren, erfolgt eine zweite Konvertierung (von einem XPath-Datentyp in einen anderen XPath-Datentyp), bei der der Wert in float(53) konvertiert wird (float(53) ist nahe am number-XPath-Datentyp):
CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice))
Unter der Annahme, dass das OrderQty-Attribut keinen XSD-Datentyp besitzt, wird OrderQty in einer Einzelkonvertierung in einen number-XPath-Datentyp konvertiert:
CONVERT(float(53), OrderDetail.OrderQty)
Parallel dazu wird der Wert 98 in den number-XPath-Datentyp konvertiert:
CONVERT(float(53), 98)
Hinweis |
---|
Wenn der im Schema verwendete XSD-Datentyp mit dem in der Datenbank zugrunde gelegten SQL Server-Datentyp inkompatibel ist oder eine nicht mögliche XPath-Datentypkonvertierung durchgeführt werden soll, sollte SQL Server einen Fehler melden. Wenn beispielsweise das EmployeeID-Attribut mit der id-prefix-Anmerkung versehen ist, gibt XPath Employee[@EmployeeID=1] einen Fehler aus, da EmployeeID mit der id-prefix-Anmerkung versehen ist und nicht in number konvertiert werden kann. |