Color scheme: Riviera
You are here: start » de » Dokumentation » Datenintegration und Datenzugriff » WKL Database Gateway » Konzepte » Zeitpunkte, Zahlen und Namen

Zeitpunkte, Zahlen und Namen

Drei Regeln entscheiden, ob ein Wert so ankommt, wie er gemeint ist: Werte werden nach dem Typ ihrer Spalte gebunden, nicht als Text; ein Zeitpunkt ohne Zone erscheint über OData mit Z; und Namen mit Zeichen, die OData nicht erlaubt, reisen kodiert. Diese Seite erklärt alle drei an einer Stelle; die Referenzen verweisen hierher.

Wichtige Funktionen

  • Datum, Zeitpunkt, Betrag und Gleitkommawert kommen exakt an, unabhängig von der Spracheinstellung.
  • Lesen und Schreiben über OData sind beim Zeitpunkt symmetrisch.
  • Jeder Name, den SQL Server annimmt, ist erreichbar, solange seine kodierte Form höchstens 128 Zeichen hat.

Grundkonzepte

Werte nach dem Spaltentyp

Werte werden nach dem Spaltentyp gebunden, nicht als Text. Ein Datum im Rumpf geht als Datum an SQL Server. Als Text deutete SQL Server es nach der Spracheinstellung der Verbindung, und aus 2023-06-01 würde bei deutscher Einstellung der 6. Januar – dauerhaft gespeichert. Daraus folgen diese Regeln:

  • Ein Datum wird nur in ISO-Form angenommen; 01.06.2023 ist mehrdeutig.
  • Ein Zeitpunkt mit Zonenangabe für eine Spalte ohne Zone wird auf der eigenen Route abgewiesen und über OData umgerechnet (siehe Zeitpunkte ohne Zone).
  • Ein Betrag wird exakt gebunden, auch in Exponentschreibweise: Ein JSON-Wert wie 1.5E2 wird für eine Dezimalspalte aus seiner Ziffernfolge gelesen und behält jede Stelle. Das gilt für bis zu 38 Stellen, so viele, wie decimal(38, s) hält, beim Schreiben wie beim Lesen; eine längere Zahl wird für eine Dezimalspalte abgewiesen.
  • Ein Wahrheitswert für eine Textspalte wird abgewiesen.
  • Ein Gleitkommawert kommt Bit für Bit an. Er wird aus seiner Ziffernfolge gelesen, nicht über eine Umwandlung aus decimal, die nicht korrekt rundet.

Ein Zeitpunkt wird im Typ seiner Spalte gebunden, beim Schreiben wie im Filter: für eine datetime2-Spalte als datetime2, für eine date-Spalte als date. Aus dem Wert allein abgeleitet wäre jeder Zeitpunkt ein datetime – auf 1/300 Sekunde gerundet und erst ab dem Jahr 1753 darstellbar. So trifft ein Filter auch einen gespeicherten Wert mit sieben Nachkommastellen, und ein geschriebener Wert kommt mit allen sieben Stellen an, auch im Jahr 1.

Ein fehlender Wert für eine Binärspalte wird als Binärwert gebunden. Ohne Typ ginge null als nvarchar an SQL Server, und SQL Server wandelt nvarchar nicht stillschweigend in binary, varbinary oder image um – auch keinen fehlenden Wert; ein Anlegen scheiterte dann mit Fehler 257. Access nennt nicht gesetzte Felder gar nicht; der CommandBuilder von ADO.NET nennt jede Spalte, auch eine varbinary-Spalte mit null.

Eine Datumsangabe gehört als Zeitpunkt in den Filter, nicht als Zeichenkette. Auf der OData-Oberfläche bindet ge 2023-06-01T00:00:00Z (Literal von OData 4) oder ge datetime'2023-06-01T00:00:00' (Literal von OData 3, das Access und Power Query schreiben) einen Zeitpunkt; ge '2023-06-01' bindet Text. Für eine Spalte vom Typ datetime oder smalldatetime deutet SQL Server diesen Text nach der Spracheinstellung der Verbindung: Gegen eine Datenbank mit deutscher Spracheinstellung wird aus '2023-06-01' der 6. Januar – ohne Fehler, ohne Hinweis, nur mit einer anderen Zeilenmenge.

Ein Bruchwert wird exakt gebunden, nicht als Gleitkommazahl. SQL Server stellt Gleitkomma über Dezimal (Microsoft: Data type precedence): ein Gleitkomma-Parameter gegen eine decimal- oder money-Spalte wandelt die Spalte um – der Index darauf ist damit unbenutzbar, und verglichen wird eine Näherung des gespeicherten Werts. Zwei verschiedene Dezimalwerte können dabei auf denselben Gleitkommawert fallen: DecimalField eq 123456789012.345678 trifft eine Zeile, dasselbe mit …678d trifft zwei. Gleitkomma wird nur dort verwendet, wo das Literal es verlangt – Endung f oder d, Exponentenschreibweise, oder ein Wert außerhalb des exakten Bereichs.

Ein abgewiesenes Literal ist teurer als es aussieht. Ein Tabellenkalkulations- oder Berichtsclient meldet die 400 nicht weiter – er lässt die Bedingung fallen und liest stattdessen das ganze Objekt. Aus einer gezielten Abfrage wird so ein Lesen der ganzen Tabelle, das bei großen Tabellen an das Zeitlimit stoßen kann. Die Literale des Protokolls gehören deshalb zum Vertrag des Dienstes; sie sind keine Bequemlichkeit.

Zeitpunkte ohne Zone

Ein Zeitpunkt ohne Zone erscheint mit Z. OData v4 kennt keinen Typ für einen Zeitpunkt ohne Zone. Der Dienst schreibt die gespeicherte Wanduhrzeit und hängt Z an – das Z ist eine Folge des Protokolls, keine Aussage über die gespeicherte Zeit, denn die Datenbank weiß nicht, in welcher Zone ihre Werte entstanden. Passend dazu wird ein Filterwert mit Zone für eine solche Spalte in koordinierte Weltzeit umgerechnet: ge 2023-01-01T00:00:00+01:00 vergleicht mit 31.12.2022, 23:00. Beide Regeln ändern sich nur gemeinsam.

Über OData wird ein Zeitpunkt mit Zone beim Schreiben in koordinierte Weltzeit umgerechnet. Die Leseseite hängt für eine Spalte ohne Zone ein Z an, also schickt ein Client, der einen Satz liest und geändert zurückschickt, dieses Z mit; es wird wieder abgenommen. Ein anderer Versatz wird ebenso umgerechnet: 17:00+02:00 wird als 15:00 gespeichert, also derselbe Zeitpunkt, wie ihn auch ein Filter mit Zone meint. Die eigene Route (/api/v1/cf/…) weist einen Zeitpunkt mit Zone für eine solche Spalte dagegen ab, weil sie keine solche Abmachung kennt.

Typen

SpaltentypEdm-TypAnmerkung
bit, tinyint, smallint, int, bigintBoolean, Byte, Int16, Int32, Int64Int64 steht als JSON-Zahl; ein Client, der Zahlen als IEEE-754-Gleitkomma liest (etwa JavaScript), verliert Stellen jenseits von 2^53
decimal, numeric, money, smallmoneyDecimalGenauigkeit und Nachkommastellen im Schema; als JSON-Zahl exakt geschrieben – mit derselben Einschränkung für Gleitkomma-Leser
real, floatSingle, Double
date, timeDate, TimeOfDay
datetime, datetime2, smalldatetimeDateTimeOffsetals Wanduhrzeit mit Z, siehe Zeitpunkte ohne Zone
datetimeoffsetDateTimeOffsetmit der gespeicherten Zone
Text- und xml-TypenStringLänge: bei nchar/nvarchar in Zeichen, bei char/varchar in Bytes des Speichers (bei UTF-8-Sortierungen mehr als Zeichen)
uniqueidentifierGuid
Binärtypen, ZeilenversionBinary
hierarchyid, geography, geometryBinarydie gespeicherten Bytes, dieselben, die ODBC Driver 18 liefert; ein geschriebener Wert wird als Bytes übergeben und von SQL Server zurückverwandelt
sql_variantStringder gespeicherte Wert als Text in der Form seines Grundtyps, wie ODBC Driver 18 ihn liefert: 42, 12.345, 2026-10-29 08:00:00.000; ein geschriebener Wert wird als Text gespeichert
vector, json, CLR-Typen einer Anwendung–nicht angeboten: weder über OData noch beim Lesen ohne Feldliste oder beim Rücklesen nach dem Schreiben auf der eigenen Route

Vergleichen und sortieren lässt sich nicht jeder Typ. SQL Server vergleicht und sortiert text, ntext, image, xml, geography und geometry nicht. Einen sql_variant vergleicht es nach seinem Grundtyp: Ein Wert mit der Zahl 42 ist nicht gleich dem Text '42', und der Filter fände still nichts. Über OData weist der Dienst deshalb einen Vergleich in $filter und eine Sortierung in $orderby über eine solche Spalte mit 400 ab und nennt die Spalte; die Prüfung auf einen fehlenden Wert (eq null) und die Textsuche bleiben erlaubt. hierarchyid ist nach seinen Bytes geordnet und lässt sich vergleichen und sortieren, mit einem Binärwert in Hexadezimalschreibweise: binary'5B40'. Die eigene Route gibt einen Vergleich unverändert an SQL Server weiter; ein Vergleich über sql_variant findet dort einen Wert nur, wenn er im selben Grundtyp gespeichert ist.

vector (SQL Server 2025) meldet als Systemtyp varbinary, verweigert aber die Umwandlung in varbinary(max). Der Katalog nennt ihn deshalb beim eigenen Namen: Als varbinary geführt, würde er als Binärwert angeboten, ohne einer zu sein, und ein Zeilenstempel über die Tabelle ließe jedes Lesen scheitern.

Namen mit Sonderzeichen

SQL Server nimmt in eckigen Klammern fast jedes Zeichen im Namen an: [F&E], [Ein/Aus], [Prüf-Kennung], [Pos. Nr.]. OData erlaubt in Namen nur Buchstaben, Ziffern und den Unterstrich, höchstens 128 Zeichen (SimpleIdentifier in OData CSDL XML 4.01, Abschnitt „SimpleIdentifier“). Der Dienst trägt solche Namen deshalb kodiert, in der Form, die SQL Server bei FOR XML und SharePoint bei Feldnamen verwenden: Ein Zeichen, das an seiner Stelle nicht stehen darf, wird zu _x, seinem Code in vier Hexadezimalziffern (Großbuchstaben) und _; außerhalb der Basisebene von Unicode acht Ziffern.

GespeichertIm Protokoll
F&EF_x0026_E
Ein/AusEin_x002F_Aus
Prüf-KennungPrüf_x002D_Kennung
Pos. Nr.Pos_x002E__x0020_Nr_x002E_
Geräte ListeGeräte_x0020_Liste
1Nummer_x0031_Nummer
Nr#Nr_x0023_
GeändertAmGeändertAm (unverändert)
A_x0020_B (wörtlich)A_x005F_x0020_B
RegelWarum
Unverändert bleiben Buchstaben (auch Umlaute), der Unterstrich und Ziffern ab dem zweiten ZeichenEin Name ohne Sonderzeichen bleibt, wie er ist
Kodiert werden auch @, # und $SQL Server erlaubt sie in einem gewöhnlichen Namen, OData nicht; unkodiert machten sie das Schemadokument ungültig
Ein Unterstrich, der wie der Anfang einer Kodierung aussieht, wird selbst kodiert (_x005F_)Sonst trügen A B und eine Spalte, die wörtlich A_x0020_B heißt, denselben Namen
Gilt für Schema, Tabelle, Sicht und Spalte: in $metadata, im Pfad, in $select, $filter, $orderby, im Schlüssel und im RumpfEin Aufrufer nennt ein Objekt überall gleich
Die Konfiguration nennt ein Objekt ebenso (RowStampTables, KeylessWriteTables, Obergrenzen)Sie nennt Objekte so, wie eine Anfrage sie nennt
Auf der eigenen Route (/api/v1/cf/…) nennt die Anfrage den kodierten Namen, die Antwort trägt weiter den gespeichertenDie Antworten dieser Route nennen die Namen so, wie die Datenbank sie führt; siehe Darstellungen
Wegen des Namens ausgelassen wird nur ein Objekt oder eine Spalte, deren kodierter Name länger als 128 Zeichen wäre (daneben fehlen Spalten nicht angebotener Typen und Objekte ohne eine angebotene Spalte)Mehr lässt ein Bezeichner nicht zu; ein langer Name aus vielen Leerzeichen kann darüber kommen

In eine Anweisung geht weiterhin nur die Schreibweise des Katalogs: Der kodierte Name wird im Katalog nachgeschlagen und durch den gespeicherten ersetzt, bevor er – in Klammern, mit verdoppelter ] – in die Anweisung geschrieben wird. Der ODBC-Treiber übersetzt die Namen für Access zurück; dort erscheint F&E wieder als F&E.

Wie ein Name sicher in die Anweisung kommt. Namen mit Umlauten und Akzenten sind zugelassen, obwohl Datenbanken Bezeichner unter Sortierungen vergleichen, die Akzente unterschiedlich behandeln: Sonst könnte niemand in eine Tabelle mit einer Pflichtspalte wie GeändertAm schreiben. Die Grenze sichern zwei Schritte: Ein Name wird in dem Katalog nachgeschlagen, den der Dienst aus der Datenbank gelesen hat, und in die Anweisung geht nur die Schreibweise des Katalogs, in Klammern und mit verdoppelter schließender Klammer. Verglichen wird ordinal – Groß- und Kleinschreibung werden gefaltet, Akzente nicht. Ein kodierter Name wird dabei gegen die kodierten Namen des Katalogs verglichen, nie gegen die gespeicherten: Sonst könnte eine Spalte, die wörtlich F_x0026_E heißt, mit F&E verwechselt werden.

Verwandte Themen

de/wiki/data-conectivity/database-gateway/concepts/timestamps-numbers-and-names.txt · Last modified: by Wolfgang van der Stille