Color scheme: Light
You are here: start » de » Dokumentation » Datenintegration und Datenzugriff » WKL Database Gateway » Referenz » HTTP: OData v4 (Referenz)

HTTP: OData v4 (Referenz)

Die OData-v4-Oberfläche unter /odata/v4/ – für Access über den ODBC-Treiber, Excel und Power BI über Power Query und jeden anderen OData-Client. Sie liest Tabellen und Sichten, schreibt einzelne Sätze, fasst über $apply zusammen und beschreibt sich selbst im Schemadokument.

Syntax

Eine zweite Oberfläche über denselben Katalog, für Clients, die OData v4 sprechen statt des eigenen Vertrags: Power Query in Excel und Power BI, und ein ODBC-Treiber für OData, über den Access Tabellen verknüpft. Ein solcher Client lernt alles aus dem Schemadokument und folgt den Anmerkungen des Protokolls. Die Abmachung window oder den Schlüssel im Abfrageteil des eigenen Vertrags kennt er nicht. Anmeldung, Freigaben, Ratenbegrenzung, Audit und Fehlerform sind dieselben wie auf dem eigenen Vertrag (siehe HTTP: Fehlerform und HTTP: Anmeldung).

MethodePfadBedeutung
GET/odata/v4/Liste der Datenbanken (Aliasse)
GET/odata/v4/{alias}/Liste ihrer Schemata
GET/odata/v4/{alias}/{schema}/Dienstdokument
GET/odata/v4/{alias}/{schema}/$metadataSchemadokument (XML)
GET/odata/v4/{alias}/{schema}/{menge}$select $filter $orderby $top $skip $count $apply
GET/odata/v4/{alias}/{schema}/{menge}({schlüssel})ein Satz; nur $select
GET/odata/v4/{alias}/{schema}/{menge}/$countAnzahl; nur $filter
POST/odata/v4/{alias}/{schema}/{menge}[/$count]/$querydasselbe, Optionen im Rumpf
POST/odata/v4/{alias}/{schema}/$transactionsTransaktion öffnen (Erweiterung, siehe unten)
POST/odata/v4/{alias}/{schema}/$transactions/{id}/commitTransaktion abschließen
POST/odata/v4/{alias}/{schema}/$transactions/{id}/rollbackTransaktion zurücknehmen
QUERY/odata/v4/{alias}/{schema}/{menge}[/$count]wie POST …/$query, Optionen im Rumpf
POST/odata/v4/{alias}/{schema}/{menge}Rumpf: Felder; Antwort 201 + Satz
PATCH/odata/v4/{alias}/{schema}/{menge}({schlüssel})Rumpf: Felder; Antwort 200 + Satz
DELETE/odata/v4/{alias}/{schema}/{menge}({schlüssel})Antwort 204
POST/odata/v4/{alias}/{schema}/{menge}/UpdateByOriginalnur Tabellen ohne Schlüssel, siehe unten
POST/odata/v4/{alias}/{schema}/{menge}/DeleteByOriginalnur Tabellen ohne Schlüssel, siehe unten

Parameter

PUT beantwortet der Dienst mit 405, wie auf dem eigenen Vertrag auch.

Welche Datenbanken und Schemata ein Aufrufer nutzen kann, sagen die beiden Listen über den Dienstwurzeln – für Clients, die eine Auswahl anbieten, etwa den Verbindungsdialog des ODBC-Treibers wie die Datenbankliste im Dialog von SQL Server. Es ist ein gewöhnliches Dienstdokument des Protokolls, dessen Einträge die Art ServiceDocument haben – die Art, die OData für den Verweis auf einen weiteren Dienst vorsieht (OData JSON Format 4.01, Abschnitt „Service Document“). Ein generischer Client kann ihnen folgen, ohne diesen Dienst zu kennen:

{"@odata.context":"https://daten.example.com/odata/v4/$metadata",
 "value":[{"name":"fachdaten","kind":"ServiceDocument","url":"fachdaten/"}]}
RegelWarum
Gelistet wird nur, was der Aufrufer lesen darf: ein Alias, wenn eine Regel ihm Tabellen oder Sichten dort erlaubt; ein Schema, wenn es mindestens eine lesbare Tabelle oder Sicht enthältDie Liste verrät nichts, was der Aufrufer nicht ohnehin erreicht
Wer nichts lesen darf, erhält eine leere Liste der Aliasse; ein Alias ohne Lesbares antwortet 404Wie eine Dienstwurzel ohne Lesbares
Die Liste der Aliasse kommt allein aus der Konfiguration; die der Schemata aus dem KatalogDie erste öffnet keine Datenbank
Mit einer SQL-Anmeldung allein antwortet die Liste der Aliasse 401Das Kennwort lässt sich nur am Server eines Alias prüfen; die Schemata eines genannten Alias sind erreichbar
Beide Listen haben ein $metadata ohne EntitätsmengenEin Dienstdokument verweist auf eines

Geschrieben wird in Tabellen und Sichten, und immer genau ein Satz. Die Anweisung entsteht aus den Spalten des Katalogs, wie beim eigenen Vertrag; dieselben Regeln gelten unverändert. Der Aufrufer bestimmt den Satz (über den Schlüssel in der Adresse) und die Werte (über den Rumpf), nie eine Bedingung. Fehlt der Schlüssel in der Adresse, wird die Anfrage abgewiesen, statt die ganze Menge zu treffen. Eine Sicht nimmt eine Änderung an, wenn die Regeln des Aufrufers Sichten mit diesem Verb erlauben und SQL Server die Sicht für änderbar hält – wie beim ODBC-Treiber von SQL Server, über den Access verknüpfte Sichten bearbeitet; lehnt SQL Server ab, antwortet der Dienst 422. Spalten einer Sicht, die SQL Server nicht aktualisieren kann – eine skalare Unterabfrage, ein Ausdruck, eine Zusammenfassung –, meldet der Dienst als schreibgeschützt (Core.Computed); eine Änderung, die eine von ihnen nennt, weist er mit 400 und dem Namen der Spalte ab. Ausgenommen sind Sichten mit einem INSTEAD OF-Trigger: Dort entscheidet der Trigger, was eine solche Spalte bedeutet. Access übernimmt diese Angabe nicht: Eine verknüpfte Sicht bietet eine solche Spalte weiter zum Bearbeiten an, mit diesem Treiber wie mit dem ODBC Driver 18 von SQL Server, und wer sie ändert, verliert mit der Ablehnung auch die übrigen Änderungen des Satzes. Wo Benutzer in Access bearbeiten, verknüpfen Sie deshalb die Basistabelle zum Schreiben und die Sicht nur zum Lesen. Der eigene Vertrag (cf) schreibt nur in Tabellen.

Jeder Schreibvorgang nennt einen Satz über seinen vollständigen Schlüssel. Die einzige Ausnahme sind freigegebene Tabellen ohne Schlüssel: Dort nennt der Aufrufer den Satz über seine alten Werte, und auch dann wird genau ein Satz geschrieben.

Die Antwort ist der gespeicherte Satz mit seinem neuen ETag; beim Anlegen zusätzlich die Adresse des neuen Satzes im Kopf Location. So kennt der Aufrufer Identitätsschlüssel, Vorgabewerte und berechnete Spalten, ohne den Satz noch einmal lesen zu müssen.

Ein Schlüssel, den die Datenbank selbst vergibt – als Identität oder per Vorgabe wie NEWSEQUENTIALID() –, darf beim Anlegen fehlen; die Antwort und Location nennen den vergebenen Wert.

AntwortBedeutung
201 / 200 + Satzangelegt / geändert
204gelöscht
400Schlüssel unvollständig, Feld unbekannt oder nicht schreibbar, Wert passt nicht zum Typ
403der Aufrufer darf in dieser Datenbank diese Tabelle oder Sicht nicht schreiben
404kein Satz mit diesem Schlüssel
409Schlüssel beim Anlegen schon vergeben; bei den Aktionen für Tabellen ohne Schlüssel: die alten Werte treffen mehrere Sätze
412If-Match nennt eine veraltete Zeilenversion; nichts wurde geschrieben
422die Datenbank lehnt ab (Einschränkung, Trigger, Berechtigungen unter Service), siehe Fehlerform
429eine Grenze des Dienstes
503Dienst oder Datenbank gestört. Ob die Änderung gespeichert ist, ist dann unbekannt – den Satz neu lesen
504Zeitgrenze überschritten; ob gespeichert wurde, ist ebenfalls unbekannt

Ein Zeitpunkt mit Zone wird für eine Spalte ohne Zone in koordinierte Weltzeit umgerechnet und als Wanduhrzeit gespeichert: …T17:00:00Z als 17:00, …T17:00:00+02:00 als 15:00. Abgewiesen wird er hier nicht (anders als auf der eigenen Route); siehe Zeitpunkte, Zahlen und Namen.

Felder mit @ im Namen – @odata.etag, @odata.type – werden übergangen statt abgewiesen. Ein Client, der einen gelesenen Satz zurückschickt, führt sie mit; sie sind keine Spalten.

Ein Dienststamm je Alias und Schema. Eine Entitätsmenge heißt in OData wie ein einfacher Bezeichner, und die Objekte einer Datenbank sind nur je Schema eindeutig. Mit dem Schema im Stamm heißt die Menge genau wie das Objekt (APPARAT), ohne ein Trennzeichen, das auch in einem echten Namen vorkommen könnte.

Das Schemadokument gilt je Aufrufer. Es nennt Tabellen, wenn der Aufrufer Tabellen des Alias lesen darf, und Sichten, wenn er Sichten lesen darf – nichts, was ihm verweigert würde. Funktionen und Prozeduren erscheinen nicht. Ein Schema ohne lesbares Objekt, auch ein vertipptes, antwortet mit 404 und nicht mit einem leeren Dienst.

let
    Quelle = OData.Feed("https://gateway.example.com/odata/v4/fachdaten/dbo/", null,
        [Implementation = "2.0", Headers = [#"X-Api-Key" = "…"]]),
    Apparate = Quelle{[Name = "APPARAT"]}[Data],
    Keller = Table.SelectRows(Apparate, each Text.Contains([Benennung], "Keller"))
in
    Keller

Der Schlüssel steht in diesem Beispiel im Klartext in der Abfrage und damit in jeder Kopie der Mappe. Das ist eine Grenze der Anmeldung per Kopfzeile, nicht dieser Oberfläche.

Mit der Windows-Anmeldung entfällt die Kopfzeile: OData.Feed("https://gateway.example.com/odata/v4/fachdaten/dbo/", null, [Implementation = "2.0"]), dazu im Anmeldedialog von Power Query die Anmeldeart „Windows“.

Schlüssel. Schlüssel einer Menge ist der Primärschlüssel, ersatzweise der erste eindeutige Index – aber nur, wenn keine seiner Spalten leer sein darf und alle einen Typ haben, den das Protokoll als Schlüssel zulässt. Eine Sicht ohne eigenen Index bekommt den Schlüssel, den SQL Server für ihr Ergebnis nennt (sp_describe_first_result_set im Browse-Modus, is_part_of_unique_key) – dieselbe Angabe, aus der der ODBC-Treiber von SQL Server den Schlüssel einer Sicht ableitet. Übernommen wird er nur, wenn die Sicht alle diese Spalten zeigt: Muss SQL Server eine Schlüsselspalte einer Basistabelle ergänzen, die die Sicht nicht auswählt (ein Verbund), identifizieren die sichtbaren allein keinen Satz. Eine Sicht ohne solchen Schlüssel wird ohne Schlüssel angeboten: lesbar und filterbar, aber kein einzelner Satz adressierbar. Das Protokoll erwartet eigentlich einen; ohne diese Ausnahme wären gerade die Sichten unerreichbar, über die ein Client lesen soll.

Beschrieben wird eine Sicht nach ihrem Ergebnis, nicht nach ihrer gespeicherten Spaltenliste. Eine Sicht über SELECT *, deren Tabellen sich seither geändert haben, behält die alte Liste, bis jemand sp_refreshview ausführt, und SQL Server liefert die neuen Spalten unter den alten Namen; Werte kommen dann unter falschen Spaltennamen und mit falschem Typ an. Der Dienst beschreibt deshalb jede Sicht über sys.dm_exec_describe_first_result_set, wie der ODBC-Treiber ein Ergebnis beschreibt, und schreibt einmal je Sicht eine Warnung ins Protokoll.

Was der Dienst über die Datenbank sagt. Was OData nicht kennt, ein Client aber braucht, um sich gegenüber einer Anwendung wie der Treiber des Produkts zu verhalten, steht als Annotation eines eigenen Vokabulars in $metadata. Das Vokabular (Namensraum Wkl.Store.V1, Alias Store) liegt ohne Anmeldung unter /odata/v4/$vocabulary/Wkl.Store.V1.xml; ein Client, der es nicht kennt, übergeht die Annotationen und verliert nichts.

AnnotationWoInhalt
Store.Product, Store.ProductVersionContainerMicrosoft SQL Server, 17.00 – Haupt- und Nebenversion, ohne Build
Store.SchemaContainerSchema des Dienststamms, wie die Datenbank es nennt (dbo); der ODBC-Treiber meldet es als TABLE_SCHEM, woraus Access den Quellnamen verknüpfter Tabellen bildet
Store.PassThroughContainerAdresse für eigene Anweisungen; nur für einen Aufrufer, der sie benutzen darf: Alias mit AllowPassThrough und Regel mit sql oder Anweisung unter eigener Anmeldung, oder Alias mit AllowCheckedStatements (Vorgabe) für geprüfte Anweisungen
Store.TypeEigenschaftTypname der Datenbank, bei einer Identitätsspalte mit identity (int identity)
Store.IndexesEntitätstypalle Zeilenspeicher-Indizes mit Name, Unique, Primary, Clustered und den Spalten in Schlüsselfolge; gefilterte und abgeschaltete nicht
Store.Rows, Store.PagesEntitätstypZeilen und Datenseiten der Tabelle bzw. indizierten Sicht (Heap oder gruppierter Index, In-Row-Seiten), dieselben Zahlen, die sp_statistics an ODBC meldet; Stand beim Laden des Katalogs, also Schätzwerte. Fehlen bei Sichten ohne Index
Core.ComputedEigenschaftnicht schreibbar: Identität, berechnete Spalte, Zeilenversion, Zeilenstempel und Spalten einer Sicht, die SQL Server als nicht aktualisierbar meldet

Power Query in Excel für Microsoft 365 liest das erweiterte Schemadokument unverändert.

Zeilen und Seiten sind Planungshilfen, keine Zählung. Access liest sie beim Verknüpfen über SQLStatistics und plant danach seine Verbünde. Ohne Seitenzahl schlägt Access bei einem Verbund die Zeilen einer Tabelle unter Umständen einzeln über den Schlüssel nach, je eine Anfrage für jede Zeile der anderen Seite; mit Seitenzahl schickt es den Verbund in einer Anweisung. Die Zeilenzahl allein ändert den Plan nicht. Beide Zahlen stammen aus Katalogsichten, die SQL Server laufend führt; ihr Lesen kostet unabhängig von der Tabellengröße gleich wenig und braucht kein zusätzliches Recht.

Die Schlüsselangabe Menge(4711) oder Menge(Auftrag=7,Zeile='a') wird mit der Filtergrammatik gelesen und danach auf ihre Form geprüft: genau ein Gleichheitsvergleich je Schlüsselspalte, sonst nichts. APPARAT(1 or nummer ne 0) ist als Ausdruck gültig und träfe jede Zeile; es wird mit 400 abgewiesen.

Typen und kodierte Namen: Zeitpunkte, Zahlen und Namen.

Was Power Query zeigt (Excel, OData.Feed mit Implementation="2.0"):

Anzeige
Spaltennamenwie gespeichert – Power Query dekodiert selbst, etwa F&E, Prüf-Kennung, auch mit ", . und [
Namen von Tabellen und Sichten in der Navigationkodiert, etwa gw_x0020_Tabelle_x0020__x0026__x0020_Co; umbenennen lässt sich die Abfrage in Power Query
Filter über solche Spaltenan den Dienst gereicht, etwa [#"F&E"] <> null and [#"Prüf-Kennung"] = "F", statt die ganze Tabelle zu laden

Zeilenversion. Führt eine Tabelle eine, trägt jeder Satz sie als @odata.etag (W/"<Base64>"), ein Einzelsatz zusätzlich im Kopf ETag. Das Schemadokument kündigt die Spalte mit Core.OptimisticConcurrency an. Der Wert ist derselbe, den If-Match beim Schreiben annimmt. Für bearbeitbare Tabellen ist die Spalte keine Kür: Ein Client, der einen Satz ändern will, hat sonst nichts, woran er eine Vorbedingung knüpfen kann. Der OData-ODBC-Treiber dieses Produkts weist deshalb Ändern und Löschen ohne Zeilenversion ab, statt eine fremde Änderung stillschweigend zu überschreiben. Für eine Tabelle ohne Zeilenversion tritt der Zeilenstempel an ihre Stelle, wenn er für sie freigeschaltet ist.

Folgeseiten bietet der Dienst nach denselben Regeln wie nextLink im eigenen Vertrag an, hier als @odata.nextLink und als absolute Adresse, wie das Protokoll sie vorsieht. Hinter einem vorgeschalteten Proxy muss dieser deshalb Schema und Host weiterreichen (X-Forwarded-* mit der zugehörigen Middleware); sonst zeigen Kontext- und Folgeadressen auf den Host, den dieser Prozess sieht.

Ist die Menge nach ihrem Schlüssel geordnet – kein $orderby des Aufrufers, ein Schlüssel aus ganzen Zahlen, Text oder uniqueidentifier, alle Schlüsselspalten ausgewählt –, setzt die Folgeseite nach dem Schlüssel der letzten Zeile fort ($skiptoken, etwa ?$skiptoken=3691 oder ?$skiptoken=Auftrag=7,Zeile='a') statt nach einer Zeilenzahl ($skip). $skip wird zu OFFSET … ROWS, und SQL Server zählt für jede Seite alle vorigen Zeilen erneut ab; jede Seite dauert dann länger als die vorige. Mit $skiptoken bleibt die Zeit je Seite gleich. Das Token ist für den Client undurchsichtig; der Dienst liest es wie die Schlüsselangabe einer Adresse und weist es für eine anders geordnete Leseanfrage mit 400 ab. In allen anderen Fällen bleibt es bei $skip. Ein Dezimalschlüssel ist bewusst ausgenommen: Über die Filtergrammatik gelesen, könnte sein Wert gerundet werden.

Folgeseiten zählen nicht gegen die Anfragengrenze (Gateway:Security:RateLimit) – hier wie im eigenen Vertrag. Jede Folgeadresse trägt dazu die Option wkl-page, einen Prüfwert über Aufrufer, Pfad, alle übrigen Optionen und einen Ablaufzeitpunkt (15 Minuten). Der Schlüssel dafür entsteht zufällig beim Start des Prozesses und verlässt ihn nie. Grund: Ein Client liest eine große Menge Seite für Seite, jede Seite ist eine Anfrage, und ein Abbruch mitten im Lesen mit 429 ließe Access eine Tabelle unvollständig mit „ODBC-Aufruf fehlgeschlagen“ zurück. Gezählt wird deshalb nur der Beginn eines Lesevorgangs. Die Regeln:

FallWirkung
Erster Abruf einer Folgeadresse, die der Dienst diesem Aufrufer ausgegeben hatZählt nicht
Derselbe Abruf noch einmal (Wiederholung nach Verbindungsabbruch, Schleife)Zählt wie jede Anfrage
Selbst gebautes $skip/$skiptoken, veränderte Option, verfälschter oder abgelaufener PrüfwertZählt wie jede Anfrage
Prüfwert eines anderen Prozesses (nach einem Neustart, andere Instanz hinter einem Lastverteiler)Zählt wie jede Anfrage

Abgewiesen wird wegen wkl-page nie: Ein ungültiger Prüfwert hebt nur die Befreiung auf; Anmeldung und Rechte prüft der Dienst bei jeder Seite wie sonst. Die Option erscheint nur in Adressen, die der Dienst selbst bildet; ein Client reicht sie ungelesen weiter (sie beginnt nicht mit $).

Eine Abweichung vom Protokoll und eine Ergänzung gehen auf das Verhalten von Power Query zurück:

FestlegungGrund
Abweichung: Binärwerte als gewöhnliches Base64 statt base64url, das OData JSON Format 4.01 im Abschnitt „Primitive Value“ vorsiehtDie OData-Bibliothek der Office-Clients liest nur das gewöhnliche Alphabet; mit base64url bricht das Laden einer Tabelle mit Zeilenversion mit einem Umwandlungsfehler nach Edm.Binary ab
Ergänzung: Capabilities.FilterFunctions nennt contains, startswith, endswithOhne diese Angabe wertet Power Query Text.Contains selbst aus und lädt dafür die ganze Tabelle; mit ihr geht die Bedingung als $filter an den Dienst. Vergleiche, Bereiche und Zeitpunkte gehen auch ohne sie als $filter hinaus

Transaktionen

Erweiterung dieses Dienstes, nicht Teil von OData. OData sieht für mehrere Änderungen in einem Schritt den Stapel $batch mit Änderungsgruppen vor; eine Transaktion über mehrere einzelne Anfragen, wie sie ODBC-Anwendungen erwarten, kennt es nicht. Ein generischer OData-Client nutzt diese Erweiterung nicht; sie ist für den ODBC-Treiber und Programme gedacht, die sie ausdrücklich ansprechen.

Ein Client klammert mehrere Anfragen in einer Transaktion, wie eine Anwendung über den Treiber von SQL Server mit BeginTrans/CommitTrans/Rollback. Der Dienst kündigt das im Schemadokument an (Store.Transactions am Entitätscontainer, die Adresse unten); der ODBC-Treiber meldet Transaktionen nur dann.

AnfrageAntwort
POST {Dienststamm}/$transactions201 mit {"id": "…", "idleSeconds": 120}
jede Anfrage mit der Kopfzeile Wkl-Transaction: <id> – Lesen, Schreiben, Prozeduren, eigene Anweisungen (sql.json)läuft in der Transaktion; sieht ihre eigenen, noch nicht gespeicherten Änderungen
POST {Dienststamm}/$transactions/<id>/commit204; 409, wenn die Datenbank die Transaktion schon zurückgenommen hat – dann ist nichts davon gespeichert; 503, wenn die Verbindung zur Datenbank beim Abschluss abriss – dann ist der Ausgang unbekannt
POST {Dienststamm}/$transactions/<id>/rollback204
eine unbekannte, beendete oder fremde Kennung404
FestlegungGrund
Die Transaktion hält eine eigene Verbindung, als die Anmeldung des Aufrufers, Isolation READ COMMITTEDSo verhält sie sich wie über den Treiber von SQL Server: eigene Änderungen sichtbar, Sperren bis zum Ende
Nur der Aufrufer, der sie geöffnet hat, und nur auf demselben AliasEine Kennung ist kein Recht; jede Anweisung darin wird nach den Regeln des Aufrufers beurteilt wie ohne Transaktion
Eine Anweisung, die scheitert – an der Versionsprüfung (412) oder weil die Datenbank sie ablehnt (Einschränkung, Meldung eines Triggers) –, scheitert allein; die Transaktion besteht weiterWie über den Treiber von SQL Server. Die erzeugte Anweisung rollt bis zu ihrem eigenen Sicherungspunkt zurück
Nach TransactionIdleSeconds ohne Anfrage nimmt der Dienst sie zurückEin verschwundener Client hielte sonst Verbindung und Sperren für immer
Höchstens MaxTransactionsPerCaller offene je Aufrufer (429)Jede hält eine Verbindung des Pools
Beim Beenden des Dienstes werden offene Transaktionen zurückgenommen–

Tabellen ohne Schlüssel: Aktionen

{ "Name": "fachdaten", "Provider": "sqlserver", "ConnectionString": "…",
  "KeylessWriteTables": [ "dbo.Protokoll" ] }

Die Formen der Einträge sind dieselben wie bei RowStampTables (schema.tabelle, schema.*, *), ebenso die Prüfung beim Start. Eine gelistete Tabelle, die doch einen Schlüssel hat, wird weiter über ihn geschrieben und im Protokoll genannt.

Über das Protokoll geschieht das mit zwei gebundenen Aktionen, die das Schemadokument nur für freigegebene Tabellen deklariert. Ein Client erkennt daran, ob die Tabelle beschreibbar ist:

POST /odata/v4/fachdaten/dbo/Protokoll/UpdateByOriginal
{ "original": { "Nummer": 2, "Text": "zwei", "Betrag": null, "Aktiv": false },
  "changes":  { "Text": "neu" } }
 
POST /odata/v4/fachdaten/dbo/Protokoll/DeleteByOriginal
{ "original": { … } }

Der Aktionsname darf mit dem Namensraum des Schemas stehen (fachdaten.dbo.UpdateByOriginal), wie das Protokoll ihn schreibt. Geprüft wird als das, was die Aktion tut: Ändern braucht das Recht für PATCH, Löschen das für DELETE. Ein Recht nur zum Anlegen öffnet diese Tür nicht.

RegelGrund
original nennt jede vergleichbare Spalte – oder die Zeilenversion bzw. den ZeilenstempelEine Bedingung über weniger Spalten träfe Sätze, die nur in diesen Werten übereinstimmen
Vergleichbar ist jede angebotene Spalte begrenzter Länge; nicht dazu gehören Langtext und lange Binärwerte (max), text, ntext, image, xmltext bis xml kann die Engine nicht mit = vergleichen; Langtext nennt Access nicht – eine Pflicht dazu ließe jede Änderung aus Access scheitern
Ein fehlender alter Wert wird zu IS NULL= NULL ist nie wahr; ein Ersatzwert wie ISNULL(x, 0) fiele mit echten Nullen zusammen und träfe die Zeile mit 0 mit
Geändert wird genau ein Satz; treffen die alten Werte mehrere, wird zurückgenommen und mit 409 abgewiesenMehrere Treffer sind Sätze, die in allen vergleichbaren Spalten gleich sind; sie können sich in Langtext oder nicht angebotenen Spalten unterscheiden. Access direkt gegen SQL Server meldet in diesem Fall Fehler 3362 und nimmt die Änderung zurück; der Dienst verhält sich ebenso
Nichts getroffen: 412Der Satz wurde geändert oder gelöscht; ohne Schlüssel ist beides nicht unterscheidbar

Antwort bei Erfolg: 200 mit {"value": 1}.

Gruppieren und Zusammenfassen ($apply)

Eine Menge lässt sich gruppiert und zusammengefasst lesen, nach OData Data Aggregation 4.0. Grund ist Access: Das Datenbankmodul schickt SUM, COUNT(Spalte), MIN, MAX, GROUP BY, HAVING, DISTINCT und für eine Standardabweichung SUM(x * x) über eine verknüpfte Tabelle an den ODBC-Treiber, gleich was dieser über sich meldet, und rechnet nicht selbst, wenn der Treiber ablehnt – die Abfrage scheitert dann mit „ODBC-Aufruf fehlgeschlagen“. Ohne Durchreiche, also für jeden Schlüssel ohne das Recht sql, führen $apply und – wo der Alias sie annimmt – geprüfte Anweisungen zu Summen und Gruppen. Er ist ein Lesen: Es gelten die Leserechte der Menge, und eine Summe über eine Million Zeilen reist als eine Zahl.

GET …/Auftrag?$apply=groupby((Werk),aggregate($count as Anzahl,Menge with sum as Summe))
GET …/Auftrag?$apply=filter(Werk eq 3)/aggregate(Menge with average as Mittel)
GET …/Rolle?$apply=groupby((Abteilung),aggregate($count as N))&$filter=N gt 1&$orderby=N desc&$top=10
GET …/Rolle?$apply=compute(Id mul Id as Q)/aggregate(Q with sum as Quadratsumme)
GET …/Rolle?$apply=groupby((Abteilung))                          verschiedene Werte (DISTINCT)
{"@odata.context":"…/$metadata#Auftrag(Werk,Anzahl,Summe)",
 "value":[{"Werk":1,"Anzahl":2140,"Summe":18350.5}, …]}

Was $apply ausführt – in dieser Reihenfolge, jede Transformation höchstens einmal:

TransformationBedeutungSQL
filter(Bedingung)Zeilen vor dem Gruppieren; Grammatik wie $filterWHERE
compute(Ausdruck as Alias, …)Rechnen mit add, sub, mul über Zahlenspalten und ZahlenAusdruck im Aggregat
groupby((Eigenschaft, …)[,aggregate(…)])Gruppen; ohne aggregate die verschiedenen WerteGROUP BY
aggregate(…)Zusammenfassen ohne Gruppen: eine ZeileAggregat ohne GROUP BY
AggregatErgebnisSQLTyp des Ergebnisses
$count as AZeilenCOUNT_BIG(*)Edm.Int64
x with sum as ASummeSUM; ganze Zahlen über bigintganze Zahlen Edm.Int64, Dezimal Edm.Decimal, Gleitkomma Edm.Double
x with average as AMittelwertAVG; ganze Zahlen über floatganze Zahlen und Gleitkomma Edm.Double, Dezimal Edm.Decimal
x with min as A, x with max as Akleinster, größter WertMIN, MAXTyp der Spalte
x with countdistinct as Averschiedene Werte ohne fehlendeCOUNT_BIG(DISTINCT x)Edm.Int64
x with Wkl.Store.V1.count as AWerte, die nicht fehlenCOUNT_BIG(x)Edm.Int64

Nach $apply beziehen sich die übrigen Optionen auf die Gruppen, wie das Protokoll es vorsieht: $filter ist SQL HAVING und darf einen Alias nennen ($filter=N gt 1), $orderby ordnet die Gruppen, $top, $skip und $count=true fenstern und zählen sie. Sie nennen nur, was das Ergebnis hat – eine Gruppierungseigenschaft oder einen Alias; eine andere Spalte der Menge weist der Dienst mit 400 ab. Ohne $orderby sind die Gruppen nach ihren Gruppierungseigenschaften geordnet, sodass aufeinander folgende Fenster sich nicht überschneiden.

FestlegungGrund
Summe und Mittelwert ganzer Zahlen werden vorher je Spalte nach bigint bzw. float umgewandeltSQL Server summiert int als int und bricht jenseits von 2^31 mit einem Überlauf ab; den Mittelwert ganzer Zahlen rechnet es ohne Rest (Mittel von 1 und 2 ist 1). Die Summe des Protokolls ist so groß, wie sie ist, sein Mittelwert hat Nachkommastellen. Je Spalte, nicht am Ergebnis, damit x mul x nicht schon vorher überläuft
div und mod gibt es in compute nichtSQL teilt ganze Zahlen ohne Rest, OData nicht – ein Operator ergäbe zwei Antworten
Wkl.Store.V1.count statt einer StandardmethodeDas Protokoll hat keine Methode, die Werte ohne fehlende zählt (COUNT(Spalte)); $count zählt Zeilen, countdistinct verschiedene Werte. Eine eigene Methode muss es mit Namensraum benennen; das Schemadokument kündigt sie mit Aggregation.CustomAggregationMethods an
Ein Alias darf nicht wie eine Eigenschaft der Menge heißen, gespeichert oder kodiertDas Ergebnis trüge sonst zwei Werte unter einem Namen, und eine Bedingung auf die Gruppen wüsste nicht, welchen sie meint
Nicht gruppiert, verglichen oder verschieden gezählt werden xml, text, ntext, image; nicht summiert wird Text; min/max nicht über Ja/Nein; der berechnete Zeilenstempel gar nichtSQL Server vergleicht diese Typen nicht bzw. lehnt die Funktion ab; die Ablehnung nennt den Grund, statt einen Datenbankfehler weiterzugeben
Ohne $top liefert eine Seite bis zu MaxTop Gruppen, nicht nur DefaultTopJede weitere Seite gruppiert in der Datenbank wieder alle Zeilen, bevor sie zur Seite springen kann; die Gruppen selbst sind wenige und klein. Eine Seite statt mehrerer erspart diese Wiederholung
$select neben $apply und $skiptoken für ein gruppiertes Ergebnis lehnt der Dienst abDas Ergebnis hat die Eigenschaften, die $apply nennt; eine Gruppe hat keinen Schlüssel, nach dem fortgesetzt werden könnte – geblättert wird mit $skip
Jede andere Transformation (concat, topcount, rollup …), Methode oder Stellung wird mit 400 abgewiesen, nie übergangenEine übergangene Transformation beantwortet eine andere Frage mit einem Ergebnis, das wie die Antwort aussieht

Das Schemadokument kündigt an, was ausgeführt wird: Aggregation.ApplySupported mit den vier Transformationen und ohne Rollup, dazu die eigene Zählmethode. Der ODBC-Treiber gruppiert nur über einen Dienst, der das ankündigt. Auf der eigenen Route (/api/v1/cf/…) bleibt $apply abgewiesen.

Die Anweisung ist eine abgeleitete Tabelle, aus der die Gruppen wie Zeilen gelesen werden:

SELECT TOP (100) * FROM (
    SELECT [Kunde], COUNT_BIG(*) AS [Anzahl] FROM [dbo].[Umsatz] WHERE [Nr] > @p0 GROUP BY [Kunde]
) AS [gw_g] WHERE [Anzahl] > @p1 ORDER BY [Anzahl] DESC

Nur so kann die Bedingung auf die Gruppen einen Alias nennen und gilt für das Fenster dieselbe Logik wie beim gewöhnlichen Lesen. Werte gehen wie überall als Parameter hinein; Zahlen aus compute schreibt der Dienst aus dem gelesenen Wert, nie aus dem Text des Aufrufers.

Siehe auch

de/wiki/data-conectivity/database-gateway/reference/odata.txt · Last modified: by Wolfgang van der Stille