Escape-Klauseln und Datentypen (Referenz)
Welche ODBC-Escape-Klauseln der Treiber in einer Anweisung versteht und mit welchem SQL-Datentyp er
jede Spalte des Dienstes einer Anwendung meldet. Sie brauchen diese Seite, wenn eine Anweisung mit
{d …}, {ts …} oder {fn …} nicht wie erwartet läuft, oder wenn eine Anwendung einen anderen
Typ, eine andere Länge oder einen anderen Typnamen anzeigt als über den ODBC-Treiber von SQL Server.
Die ODBC-Spezifikation beschreibt Escape-Klauseln als herstellerneutrale Schreibweise für Literale, Funktionen und Verbünde (Microsoft: Escape Sequences in ODBC). Ein Treiber muss nicht alle unterstützen; die Tabelle unten nennt, was dieser Treiber selbst übersetzt.
Escape-Klauseln
| Klausel | Verhalten |
|---|---|
{d 'jjjj-mm-tt'} | Datum. Nur genau diese Form; ein anderer Text wird abgewiesen |
{t 'hh:mm:ss'} | Uhrzeit. Nur genau diese Form |
{ts 'jjjj-mm-tt hh:mm:ss[.f]'} | Zeitpunkt mit bis zu sieben Nachkommastellen. Nur genau diese Form |
{guid '…'} | Kennung (uniqueidentifier, Edm.Guid) |
LIKE … {escape 'x'} und LIKE … ESCAPE 'x' | Fluchtzeichen für % und _ im Muster; danach gelten die Regeln für LIKE unter Unterstütztes SQL |
{call p(…)}, {? = call p(…)} (Prozeduraufruf) | übersetzt in EXEC p … und an die Adresse für eigene Anweisungen geschickt. Der Platzhalter vor dem Gleichheitszeichen nimmt den Rückgabewert; ein Platzhalter, den die Anwendung als Ausgabe bindet, erhält OUTPUT; ein leeres Argument ({call p(?,,?)}) wird DEFAULT. Ohne Adresse für eigene Anweisungen weist der Treiber den Aufruf mit 42000 ab |
{fn …} (Skalarfunktionen), {oj …} (äußerer Verbund) und jede andere Klausel | nicht übersetzt. Mit einer Adresse für eigene Anweisungen geht die Anweisung unverändert an die Datenbank, und deren Server entscheidet, ob er die Klausel versteht; ohne Adresse weist der Treiber sie mit 42000 ab |
Ein Wert, der nicht zur Klausel passt ({d '01.06.2023'}, {ts '06/01/2023'}), macht die Anweisung unübersetzbar: Mit
einer Adresse für eigene Anweisungen geht sie unverändert an die Datenbank, ohne wird sie mit 42000
und einer Meldung abgewiesen, die Klausel und Wert nennt. Der Treiber deutet den Wert nicht selbst,
weil eine geratene Deutung – Tag oder Monat zuerst – eine andere Zeilenmenge ohne jeden Hinweis
ergäbe.
GUID als Text. Wo ein Text für eine GUID-Spalte steht – als Zeichenkette in der Anweisung oder
als gebundener Textwert –, nimmt der Treiber die einfache Form, die Form mit geschweiften Klammern
und die Form, die Access selbst schreibt ({guid {33333333-…}}). Ein gebundener Wert darf auch eine
GUID (SQL_C_GUID) oder 16 Byte (SQL_C_BINARY) sein; so bindet Access den Schlüssel einer
verknüpften Tabelle beim Nachladen, Ändern und Löschen.
Datentypen
Der Dienst beschreibt jede Spalte mit einem Typ von OData (Edm.…) und, wo er es anbietet, mit dem
Typnamen der Datenbank (Store.Type, siehe
Anforderungen an einen OData-Dienst). Daraus meldet der Treiber
der Anwendung einen SQL-Typ von ODBC, eine Länge und einen Typnamen:
| Typ des Dienstes | SQL-Typ (ODBC 3) | Typname | Länge bzw. Genauigkeit |
|---|---|---|---|
Edm.String mit Länge bis 4 000 | SQL_WVARCHAR | nvarchar | Länge des Dienstes |
Edm.String mit Länge bis 4 000 und Store.Type nchar | SQL_WCHAR | nchar | Länge des Dienstes |
Edm.String mit Länge bis 8 000 und Store.Type varchar bzw. char | SQL_VARCHAR bzw. SQL_CHAR | varchar bzw. char | Länge des Dienstes |
Edm.String ohne Länge oder länger | SQL_WLONGVARCHAR | ntext; bei Store.Type nvarchar (also (max)) nvarchar | 1 073 741 823 |
Edm.String mit Store.Type varchar ohne Länge (also (max)) bzw. text | SQL_LONGVARCHAR | varchar bzw. text | 2 147 483 647 |
Edm.String mit Store.Type xml | SQL_SS_XML (-152) | xml | 0 |
Edm.String mit Store.Type sql_variant | SQL_SS_VARIANT (-150) | sql_variant | 8 000 |
Edm.Boolean | SQL_BIT | bit | 1 |
Edm.Byte | SQL_TINYINT | tinyint | 3 |
Edm.SByte, Edm.Int16 | SQL_SMALLINT | smallint | 5 |
Edm.Int32 | SQL_INTEGER | int | 10 |
Edm.Int64 | SQL_BIGINT | bigint | 19 |
Edm.Decimal | SQL_DECIMAL; bei Store.Type numeric SQL_NUMERIC | decimal bzw. numeric; bei Store.Type money/smallmoney dieser Name | Genauigkeit und Nachkommastellen des Dienstes, ohne Angabe 38 und 0 |
Edm.Single | SQL_REAL | real | 24 Bit |
Edm.Double | SQL_DOUBLE; bei Store.Type float SQL_FLOAT | float | 53 Bit |
Edm.Date | SQL_TYPE_DATE | date | 10 |
Edm.TimeOfDay | SQL_TYPE_TIME; bei Store.Type time SQL_SS_TIME2 (-154) | time | 8 bzw. 9 + Nachkommastellen |
Edm.DateTimeOffset | SQL_TYPE_TIMESTAMP | datetime; bei Store.Type datetime2 bzw. smalldatetime dieser Name | 19 bzw. 20 + Nachkommastellen (Vorgabe 3, höchstens 7); smalldatetime 16 |
Edm.DateTimeOffset mit Store.Type datetimeoffset | SQL_SS_TIMESTAMPOFFSET (-155) | datetimeoffset | 26 bzw. 27 + Nachkommastellen |
Edm.Guid | SQL_GUID | uniqueidentifier | 36 |
Edm.Binary mit Länge bis 8 000 | SQL_VARBINARY; bei Store.Type binary SQL_BINARY | varbinary bzw. binary | Länge des Dienstes |
Edm.Binary als Zeilenversion (Store.Type timestamp/rowversion) | SQL_BINARY | timestamp | 8 |
Edm.Binary ohne Länge oder länger | SQL_LONGVARBINARY | image; bei Store.Type varbinary (also (max)) varbinary | 1 073 741 823 |
Edm.Binary mit Store.Type hierarchyid, geography bzw. geometry | SQL_SS_UDT (-151) | im Katalog dieser Name, in einem Ergebnis udt | hierarchyid 892, sonst 0 |
| jeder andere Typ | – | – | Die Spalte wird nicht angeboten |
Eine Spalte, die der Dienst selbst nummeriert, trägt den Typnamen mit dem Zusatz identity
(int identity), wie beim Treiber von SQL Server; Access legt daraus ein Feld vom Typ AutoWert an.
Warum so. Die Entscheidungen und ihre Gründe:
| Festlegung | Grund |
|---|---|
Text als Unicode (SQL_W…), außer die Datenbank speichert ihn schmal (Store.Type varchar, char, text) | OData überträgt Text als JSON-Zeichenkette. Ein schmaler Typ zwänge jede Anwendung, über eine Codepage umzuwandeln, die nicht jedes Zeichen des Dienstes darstellen kann. Eine schmal gespeicherte Spalte enthält nur Zeichen ihrer Codepage; der ODBC Driver 18 beschreibt sie schmal |
Unbegrenzter Text als SQL_WLONGVARCHAR | Access legt nur daraus ein Langtextfeld an. Der Treiber von SQL Server meldet nvarchar(max) als SQL_WVARCHAR mit Länge 0; eine Anwendung, die Puffer nach der Länge bemisst, läse 0 als „leer“ |
Edm.DateTimeOffset als Zeitpunkt ohne Zone, in koordinierter Weltzeit | Ein Zeitpunkt von ODBC hat keine Zone. Ein Dienst, der eine Wanduhrzeit ohne Zone mit Z schreibt (so der Datendienst Wkl.Data.Gateway), bekommt seine gespeicherte Uhrzeit unverändert zurück; ein Wert mit echter Zone wird umgerechnet, damit ein Vergleich zwei Zeitpunkte vergleicht. Ausgenommen ist Store.Type datetimeoffset: Die Spalte behält ihren Versatz, wie beim ODBC Driver 18 |
| Typnamen der Datenbank, wo der ODBC-Typ derselbe ist | Der ODBC Driver 18 meldet datetime2 und die (max)-Typen mit ihren Grundnamen. Anwendungen zeigen diese Namen an (ADO.NET GetDataTypeName, Schematabellen) |
Die eigenen Typen des Treibers von SQL Server für time, datetimeoffset, xml, sql_variant und die CLR-Typen | Eine Anwendung, die diese Typen kennt, erhält dasselbe wie vom ODBC Driver 18. Access kennt sie nicht und zeigt solche Spalten mit beiden Treibern als Text mit 255 Zeichen: eine Uhrzeit mit Sekundenbruchteilen, einen Zeitpunkt mit Versatz. Als gewöhnlicher Zeitpunkt beschrieben, würde eine Uhrzeit das heutige Datum zeigen und ein Zeitpunkt seinen Versatz verlieren |
| Gleitkomma mit Genauigkeit in Bit (24, 53) | So zählt NUM_PREC_RADIX 2, wie beim Treiber von SQL Server |
Werte als Text und ohne eigenen Zieltyp. Liest eine Anwendung eine Spalte mit Store.Type als Text
(SQL_C_CHAR, SQL_C_WCHAR), erhält sie die Form des ODBC Driver 18: Nachkommastellen einer
Uhrzeit oder eines Zeitpunkts immer so viele, wie die Spalte festlegt (00:00:00.0000000 bei
time(7), .000 bei datetime), einen Zeitpunkt mit Versatz (2026-10-29 13:45:12.1234567 +02:00)
und eine Dezimalzahl mit allen Nachkommastellen und ohne Null vor dem Dezimalpunkt (-.0000000001,
.500). Ohne eigenen Zieltyp (SQL_C_DEFAULT) liefert der Treiber time und datetimeoffset als
Struktur des Treibers von SQL Server (SQL_SS_TIME2_STRUCT, 12 Byte; SQL_SS_TIMESTAMPOFFSET_STRUCT,
20 Byte), einen CLR-Typ als Bytes und sql_variant als schmalen Text. Als Zeitpunkt, Datum oder
Uhrzeit abgefragt, wird ein datetimeoffset in die Ortszeit des Rechners umgerechnet, wie beim
ODBC Driver 18.
ODBC-2-Anwendungen. Meldet sich eine Anwendung mit ODBC 2 an (SQL_ATTR_ODBC_VERSION), wie es
Access tut, nennt der Treiber Datum, Uhrzeit und Zeitpunkt mit den Nummern von ODBC 2 (SQL_DATE,
SQL_TIME, SQL_TIMESTAMP). Fragt sie einen Wert ohne eigenen Zieltyp ab (SQL_C_DEFAULT), liefert
der Treiber bigint und GUID als Text: ODBC 2 kennt für beide keinen eigenen C-Typ als Vorgabe;
für GUID verhält sich der ODBC Driver 18 ebenso.
Umwandlungen. SQLGetInfo(SQL_CONVERT_FUNCTIONS) meldet keine Umwandlungsfunktion; CONVERT
und CAST gehören nicht zur übersetzten Untermenge und laufen nur über die Adresse für eigene
Anweisungen. Für SQL_CONVERT_NUMERIC meldet er die Umwandlung in
SQL_NUMERIC, damit ADO.NET Dezimalwerte als Zahl und nicht als Text in der Kultur des Rechners
bindet.